From 71f4f46cb9068b6bec048402d81f951fd8ffbff7 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Tue, 7 May 2024 12:48:49 +0200 Subject: [PATCH] chore(medusa): cleanup medusa package (#7206) --- .changeset/config.json | 2 - .github/actions/cache-deps/action.yml | 4 +- .github/workflows/action.yml | 225 +- .github/workflows/test-cli-with-database.yml | 180 +- .../api/src/index.js | 0 .../api/src/services/local-file-service.js | 96 - .../api/src/services/test-ful.js | 53 - .../api/src/services/test-not.js | 19 - .../api/src/services/test-pay.js | 87 - .../development/.env.development | 7 - .../development/create-database.js | 31 - .../development/database/customer.js | 17 - .../development/database/index.js | 9 - .../development/database/region.js | 45 - .../development/database/user.js | 17 - integration-tests/development/dev-require.js | 69 - .../development/medusa-config.js | 23 - integration-tests/development/server.js | 155 - .../src/services/local-file-service.js | 96 - .../development/src/services/test-ful.js | 53 - .../development/src/services/test-not.js | 19 - .../development/src/services/test-pay.js | 87 - .../development/use-db-development.js | 94 - .../simple-discount-condition-factory.ts | 123 - .../factories/simple-discount-factory.ts | 15 - integration-tests/helpers/admin-seeder.js | 3 +- .../shipping-option-price-set.spec.ts | 4 +- .../price-lists/admin/price-lists.spec.ts | 3 +- .../modules/__tests__/product/admin/index.ts | 2 - .../modules/__tests__/workflow-engine/api.ts | 9 - integration-tests/plugins/.babelrc.js | 13 - integration-tests/plugins/.gitignore | 4 - .../__tests__/cart/store/ff-medusa-v2.ts | 96 - .../plugins/__tests__/cart/store/index.ts | 212 - .../plugins/__tests__/inventory/cart/cart.js | 362 - .../inventory-items/ff-many-to-many.js | 86 - .../inventory/inventory-items/index.js | 1083 - .../__tests__/inventory/order/draft-order.js | 180 - .../__tests__/inventory/order/order.js | 1131 - .../inventory/products/create-variant.js | 176 - .../inventory/products/delete-variant.js | 114 - .../inventory/products/get-product.js | 151 - .../inventory/products/get-variant.js | 144 - .../inventory/products/list-products.js | 348 - .../inventory/products/list-variants.js | 147 - .../inventory/reservation-items/index.js | 459 - .../plugins/__tests__/inventory/service.js | 815 - .../inventory/variant-inventory-service.js | 286 - .../list-stock-locations.spec.ts | 181 - .../service/delete-sales-channels.js | 88 - .../service/delete-stock-location.js | 96 - .../stock-location/service/sales-channels.js | 162 - .../stock-location/service/service.js | 273 - .../inventory/create-inventory-items.ts | 96 - .../workflows/product/create-product.ts | 138 - .../workflows/product/update-product.ts | 114 - .../plugins/helpers/call-helpers.js | 100 - integration-tests/plugins/jest.config.js | 23 - integration-tests/plugins/medusa-config.js | 71 - integration-tests/plugins/package.json | 48 - .../src/services/local-file-service.js | 96 - .../plugins/src/services/test-ful.js | 53 - .../plugins/src/services/test-not.js | 19 - .../plugins/src/services/test-pay.js | 73 - .../__tests__/product-categories/queries.ts | 231 - integration-tests/repositories/jest.config.js | 21 - .../repositories/medusa-config.js | 15 - integration-tests/repositories/package.json | 26 - jest.config.js | 18 +- package.json | 12 +- packages/admin-next/dashboard/package.json | 2 +- .../vite-plugin-extension/tsconfig.json | 5 +- .../cli/oas/medusa-oas-cli/src/command-oas.ts | 6 +- .../src/medusa-test-runner.ts | 39 +- packages/design-system/ui/package.json | 4 +- .../src/lib/models/AdminPostCampaignsReq.ts | 46 + .../src/lib/models/ApplicationMethod.ts | 9 + .../models/ApplicationMethodsMethodPostReq.ts | 69 + .../client-types/src/lib/models/Campaign.ts | 9 + .../src/lib/models/CampaignBudget.ts | 15 + .../src/lib/models/CreateApplicationMethod.ts | 85 + .../src/lib/models/CreateCampaign.ts | 46 + .../src/lib/models/CreateCampaignBudget.ts | 19 + .../src/lib/models/CreateDefaultTaxRate.ts | 26 + .../src/lib/models/CreateProductType.ts | 22 + .../src/lib/models/StockLocationAddress.ts | 42 + ...PostPaymentCollectionsPaymentSessionReq.ts | 19 + packages/medusa-js/.gitignore | 2 - packages/medusa-js/CHANGELOG.md | 553 - packages/medusa-js/README.md | 11 - packages/medusa-js/jest.config.js | 13 - packages/medusa-js/package.json | 57 - packages/medusa-js/src/error.ts | 57 - packages/medusa-js/src/index.ts | 91 - packages/medusa-js/src/jwt-token-manager.ts | 38 - packages/medusa-js/src/key-manager.ts | 25 - packages/medusa-js/src/request.ts | 254 - packages/medusa-js/src/resources/addresses.ts | 102 - .../medusa-js/src/resources/admin/auth.ts | 114 - .../src/resources/admin/batch-jobs.ts | 185 - .../src/resources/admin/collections.ts | 232 - .../src/resources/admin/currencies.ts | 99 - .../medusa-js/src/resources/admin/custom.ts | 138 - .../src/resources/admin/customer-groups.ts | 267 - .../src/resources/admin/customers.ts | 165 - .../src/resources/admin/discounts.ts | 626 - .../src/resources/admin/draft-orders.ts | 289 - .../src/resources/admin/gift-cards.ts | 172 - .../medusa-js/src/resources/admin/index.ts | 240 - .../src/resources/admin/inventory-item.ts | 337 - .../medusa-js/src/resources/admin/invites.ts | 154 - .../medusa-js/src/resources/admin/notes.ts | 171 - .../src/resources/admin/notifications.ts | 111 - .../src/resources/admin/order-edits.ts | 394 - .../medusa-js/src/resources/admin/orders.ts | 787 - .../resources/admin/payment-collections.ts | 143 - .../medusa-js/src/resources/admin/payments.ts | 105 - .../src/resources/admin/price-lists.ts | 407 - .../src/resources/admin/product-categories.ts | 281 - .../src/resources/admin/product-tags.ts | 66 - .../src/resources/admin/product-types.ts | 69 - .../medusa-js/src/resources/admin/products.ts | 473 - .../resources/admin/publishable-api-keys.ts | 297 - .../medusa-js/src/resources/admin/regions.ts | 375 - .../src/resources/admin/reservations.ts | 191 - .../src/resources/admin/return-reasons.ts | 145 - .../medusa-js/src/resources/admin/returns.ts | 129 - .../src/resources/admin/sales-channels.ts | 310 - .../src/resources/admin/shipping-options.ts | 165 - .../src/resources/admin/shipping-profiles.ts | 145 - .../src/resources/admin/stock-locations.ts | 197 - .../medusa-js/src/resources/admin/store.ts | 157 - .../medusa-js/src/resources/admin/swaps.ts | 94 - .../src/resources/admin/tax-rates.ts | 466 - .../medusa-js/src/resources/admin/uploads.ts | 141 - .../medusa-js/src/resources/admin/users.ts | 232 - .../medusa-js/src/resources/admin/variants.ts | 161 - packages/medusa-js/src/resources/auth.ts | 130 - packages/medusa-js/src/resources/base.ts | 9 - packages/medusa-js/src/resources/carts.ts | 308 - .../medusa-js/src/resources/collections.ts | 84 - packages/medusa-js/src/resources/customers.ts | 194 - .../medusa-js/src/resources/gift-cards.ts | 35 - packages/medusa-js/src/resources/index.ts | 47 - .../medusa-js/src/resources/line-items.ts | 88 - .../medusa-js/src/resources/order-edits.ts | 84 - packages/medusa-js/src/resources/orders.ts | 153 - .../src/resources/payment-collections.ts | 231 - .../src/resources/payment-methods.ts | 35 - .../src/resources/product-categories.ts | 150 - .../medusa-js/src/resources/product-tags.ts | 64 - .../medusa-js/src/resources/product-types.ts | 66 - .../src/resources/product-variants.ts | 107 - packages/medusa-js/src/resources/products.ts | 147 - packages/medusa-js/src/resources/regions.ts | 53 - .../medusa-js/src/resources/return-reasons.ts | 53 - packages/medusa-js/src/resources/returns.ts | 42 - .../src/resources/shipping-options.ts | 65 - packages/medusa-js/src/resources/swaps.ts | 73 - .../medusa-js/src/test/utils/utils.test.ts | 31 - packages/medusa-js/src/typings.ts | 59 - packages/medusa-js/src/utils.ts | 35 - packages/medusa-js/tsconfig.json | 21 - packages/medusa-js/tsconfig.spec.json | 10 - packages/medusa-js/tsup.config.ts | 16 - .../medusa-react/.github/workflows/main.yml | 32 - .../medusa-react/.github/workflows/size.yml | 12 - packages/medusa-react/.gitignore | 5 - packages/medusa-react/.storybook/main.js | 8 - .../medusa-react/.storybook/medusa-context.js | 23 - packages/medusa-react/.storybook/preview.js | 24 - packages/medusa-react/CHANGELOG.md | 631 - packages/medusa-react/LICENSE | 21 - packages/medusa-react/README.md | 5 - packages/medusa-react/jest.config.js | 18 - packages/medusa-react/jest.setup.js | 45 - .../medusa-react/mocks/data/fixtures.json | 1447 -- packages/medusa-react/mocks/data/index.ts | 27 - packages/medusa-react/mocks/handlers/admin.ts | 2526 --- packages/medusa-react/mocks/handlers/index.ts | 2 - packages/medusa-react/mocks/handlers/store.ts | 564 - packages/medusa-react/mocks/server.ts | 4 - packages/medusa-react/package.json | 71 - .../medusa-react/public/mockServiceWorker.js | 338 - packages/medusa-react/src/contexts/cart.tsx | 239 - packages/medusa-react/src/contexts/index.ts | 17 - packages/medusa-react/src/contexts/medusa.tsx | 171 - .../src/contexts/session-cart.tsx | 439 - packages/medusa-react/src/helpers/index.ts | 434 - .../src/hooks/admin/auth/index.ts | 17 - .../src/hooks/admin/auth/mutations.ts | 95 - .../src/hooks/admin/auth/queries.ts | 53 - .../src/hooks/admin/batch-jobs/index.ts | 17 - .../src/hooks/admin/batch-jobs/mutations.ts | 158 - .../src/hooks/admin/batch-jobs/queries.ts | 200 - .../src/hooks/admin/claims/index.ts | 16 - .../src/hooks/admin/claims/mutations.ts | 417 - .../src/hooks/admin/collections/index.ts | 14 - .../src/hooks/admin/collections/mutations.ts | 287 - .../src/hooks/admin/collections/queries.ts | 152 - .../src/hooks/admin/currencies/index.ts | 17 - .../src/hooks/admin/currencies/mutations.ts | 70 - .../src/hooks/admin/currencies/queries.ts | 104 - .../src/hooks/admin/custom/index.ts | 11 - .../src/hooks/admin/custom/mutations.ts | 231 - .../src/hooks/admin/custom/queries.ts | 90 - .../src/hooks/admin/customer-groups/index.ts | 17 - .../hooks/admin/customer-groups/mutations.ts | 301 - .../hooks/admin/customer-groups/queries.ts | 292 - .../src/hooks/admin/customers/index.ts | 14 - .../src/hooks/admin/customers/mutations.ts | 124 - .../src/hooks/admin/customers/queries.ts | 161 - .../src/hooks/admin/discounts/index.ts | 17 - .../src/hooks/admin/discounts/mutations.ts | 766 - .../src/hooks/admin/discounts/queries.ts | 324 - .../src/hooks/admin/draft-orders/index.ts | 16 - .../src/hooks/admin/draft-orders/mutations.ts | 411 - .../src/hooks/admin/draft-orders/queries.ts | 162 - .../src/hooks/admin/gift-cards/index.ts | 17 - .../src/hooks/admin/gift-cards/mutations.ts | 175 - .../src/hooks/admin/gift-cards/queries.ts | 157 - .../medusa-react/src/hooks/admin/index.ts | 39 - .../src/hooks/admin/inventory-item/index.ts | 19 - .../hooks/admin/inventory-item/mutations.ts | 392 - .../src/hooks/admin/inventory-item/queries.ts | 249 - .../src/hooks/admin/invites/index.ts | 16 - .../src/hooks/admin/invites/mutations.ts | 177 - .../src/hooks/admin/invites/queries.ts | 60 - .../src/hooks/admin/notes/index.ts | 14 - .../src/hooks/admin/notes/mutations.ts | 167 - .../src/hooks/admin/notes/queries.ts | 153 - .../src/hooks/admin/notifications/index.ts | 15 - .../hooks/admin/notifications/mutations.ts | 71 - .../src/hooks/admin/notifications/queries.ts | 143 - .../src/hooks/admin/order-edits/index.ts | 16 - .../src/hooks/admin/order-edits/mutations.ts | 630 - .../src/hooks/admin/order-edits/queries.ts | 238 - .../src/hooks/admin/orders/index.ts | 16 - .../src/hooks/admin/orders/mutations.ts | 674 - .../src/hooks/admin/orders/queries.ts | 201 - .../hooks/admin/payment-collections/index.ts | 14 - .../admin/payment-collections/mutations.ts | 201 - .../admin/payment-collections/queries.ts | 68 - .../src/hooks/admin/payments/index.ts | 14 - .../src/hooks/admin/payments/mutations.ts | 136 - .../src/hooks/admin/payments/queries.ts | 65 - .../src/hooks/admin/price-lists/index.ts | 16 - .../src/hooks/admin/price-lists/mutations.ts | 541 - .../src/hooks/admin/price-lists/queries.ts | 361 - .../hooks/admin/product-categories/index.ts | 18 - .../admin/product-categories/mutations.ts | 345 - .../hooks/admin/product-categories/queries.ts | 253 - .../src/hooks/admin/product-tags/index.ts | 14 - .../src/hooks/admin/product-tags/queries.ts | 118 - .../src/hooks/admin/product-types/index.ts | 14 - .../src/hooks/admin/product-types/queries.ts | 118 - .../src/hooks/admin/products/index.ts | 16 - .../src/hooks/admin/products/mutations.ts | 610 - .../src/hooks/admin/products/queries.ts | 274 - .../hooks/admin/publishable-api-keys/index.ts | 22 - .../admin/publishable-api-keys/mutations.ts | 389 - .../admin/publishable-api-keys/queries.ts | 260 - .../src/hooks/admin/regions/index.ts | 17 - .../src/hooks/admin/regions/mutations.ts | 533 - .../src/hooks/admin/regions/queries.ts | 226 - .../src/hooks/admin/reservations/index.ts | 20 - .../src/hooks/admin/reservations/mutations.ts | 198 - .../src/hooks/admin/reservations/queries.ts | 202 - .../src/hooks/admin/return-reasons/index.ts | 17 - .../hooks/admin/return-reasons/mutations.ts | 179 - .../src/hooks/admin/return-reasons/queries.ts | 116 - .../src/hooks/admin/returns/index.ts | 17 - .../src/hooks/admin/returns/mutations.ts | 131 - .../src/hooks/admin/returns/queries.ts | 62 - .../src/hooks/admin/sales-channels/index.ts | 17 - .../hooks/admin/sales-channels/mutations.ts | 468 - .../src/hooks/admin/sales-channels/queries.ts | 197 - .../src/hooks/admin/shipping-options/index.ts | 17 - .../hooks/admin/shipping-options/mutations.ts | 196 - .../hooks/admin/shipping-options/queries.ts | 126 - .../hooks/admin/shipping-profiles/index.ts | 17 - .../admin/shipping-profiles/mutations.ts | 187 - .../hooks/admin/shipping-profiles/queries.ts | 122 - .../src/hooks/admin/stock-locations/index.ts | 20 - .../hooks/admin/stock-locations/mutations.ts | 183 - .../hooks/admin/stock-locations/queries.ts | 212 - .../src/hooks/admin/store/index.ts | 15 - .../src/hooks/admin/store/mutations.ts | 139 - .../src/hooks/admin/store/queries.ts | 162 - .../src/hooks/admin/swaps/index.ts | 17 - .../src/hooks/admin/swaps/mutations.ts | 438 - .../src/hooks/admin/swaps/queries.ts | 152 - .../src/hooks/admin/tax-rates/index.ts | 16 - .../src/hooks/admin/tax-rates/mutations.ts | 555 - .../src/hooks/admin/tax-rates/queries.ts | 225 - .../src/hooks/admin/uploads/index.ts | 15 - .../src/hooks/admin/uploads/mutations.ts | 190 - .../src/hooks/admin/users/index.ts | 16 - .../src/hooks/admin/users/mutations.ts | 273 - .../src/hooks/admin/users/queries.ts | 151 - .../src/hooks/admin/variants/index.ts | 15 - .../src/hooks/admin/variants/queries.ts | 287 - packages/medusa-react/src/hooks/index.ts | 4 - .../src/hooks/store/carts/index.ts | 18 - .../src/hooks/store/carts/mutations.ts | 549 - .../src/hooks/store/carts/queries.ts | 67 - .../src/hooks/store/collections/index.ts | 12 - .../src/hooks/store/collections/queries.ts | 157 - .../src/hooks/store/customers/index.ts | 14 - .../src/hooks/store/customers/mutations.ts | 112 - .../src/hooks/store/customers/queries.ts | 113 - .../src/hooks/store/gift-cards/index.ts | 13 - .../src/hooks/store/gift-cards/queries.ts | 62 - .../medusa-react/src/hooks/store/index.ts | 17 - .../src/hooks/store/line-items/index.ts | 12 - .../src/hooks/store/line-items/mutations.ts | 181 - .../src/hooks/store/order-edits/index.ts | 15 - .../src/hooks/store/order-edits/mutations.ts | 129 - .../src/hooks/store/order-edits/queries.ts | 68 - .../src/hooks/store/orders/index.ts | 15 - .../src/hooks/store/orders/mutations.ts | 118 - .../src/hooks/store/orders/queries.ts | 180 - .../hooks/store/payment-collections/index.ts | 12 - .../store/payment-collections/mutations.ts | 403 - .../store/payment-collections/queries.ts | 71 - .../hooks/store/product-categories/index.ts | 15 - .../hooks/store/product-categories/queries.ts | 286 - .../src/hooks/store/product-tags/index.ts | 12 - .../src/hooks/store/product-tags/queries.ts | 116 - .../src/hooks/store/product-types/index.ts | 12 - .../src/hooks/store/product-types/queries.ts | 116 - .../src/hooks/store/products/index.ts | 14 - .../src/hooks/store/products/queries.ts | 196 - .../src/hooks/store/regions/index.ts | 14 - .../src/hooks/store/regions/queries.ts | 108 - .../src/hooks/store/return-reasons/index.ts | 11 - .../src/hooks/store/return-reasons/queries.ts | 117 - .../src/hooks/store/returns/index.ts | 13 - .../src/hooks/store/returns/mutations.ts | 57 - .../src/hooks/store/shipping-options/index.ts | 13 - .../hooks/store/shipping-options/queries.ts | 134 - .../src/hooks/store/swaps/index.ts | 15 - .../src/hooks/store/swaps/mutations.ts | 68 - .../src/hooks/store/swaps/queries.ts | 67 - .../src/hooks/utils/buildOptions.ts | 32 - .../medusa-react/src/hooks/utils/index.ts | 2 - .../src/hooks/utils/queryKeysFactory.ts | 18 - .../src/hooks/utils/useLocalStorage.ts | 30 - packages/medusa-react/src/index.ts | 4 - packages/medusa-react/src/types.ts | 47 - packages/medusa-react/src/utils/index.ts | 11 - .../medusa-react/stories/Carts.stories.tsx | 50 - .../stories/Collections.stories.tsx | 86 - .../stories/Customers.stories.tsx | 69 - .../medusa-react/stories/Orders.stories.tsx | 76 - .../medusa-react/stories/Products.stories.tsx | 86 - .../medusa-react/stories/Regions.stories.tsx | 66 - .../stories/ReturnReasons.stories.tsx | 70 - .../stories/ShippingOptions.stories.tsx | 84 - .../medusa-react/stories/Swaps.stories.tsx | 50 - .../stories/components/Layout.tsx | 16 - .../test/cart-context/cart.test.ts | 196 - .../test/hooks/admin/auth/mutations.test.ts | 38 - .../test/hooks/admin/auth/queries.test.ts | 18 - .../hooks/admin/batch-jobs/mutations.test.ts | 78 - .../hooks/admin/batch-jobs/queries.test.ts | 35 - .../test/hooks/admin/claims/mutations.test.ts | 162 - .../hooks/admin/collections/mutations.test.ts | 142 - .../hooks/admin/collections/queries.test.ts | 35 - .../hooks/admin/currencies/mutation.test.ts | 31 - .../hooks/admin/currencies/queries.test.ts | 18 - .../admin/customer-groups/mutations.test.ts | 59 - .../admin/customer-groups/queries.test.ts | 55 - .../hooks/admin/customers/mutations.test.ts | 64 - .../hooks/admin/customers/queries.test.ts | 35 - .../hooks/admin/discounts/mutations.test.ts | 342 - .../hooks/admin/discounts/queries.test.ts | 80 - .../admin/draft-orders/mutations.test.ts | 189 - .../hooks/admin/draft-orders/queries.test.ts | 35 - .../hooks/admin/gift-cards/mutations.test.ts | 84 - .../hooks/admin/gift-cards/queries.test.ts | 35 - .../admin/inventory-items/mutations.test.ts | 144 - .../admin/inventory-items/queries.test.ts | 74 - .../hooks/admin/invites/mutations.test.ts | 90 - .../test/hooks/admin/invites/queries.test.ts | 18 - .../test/hooks/admin/notes/mutations.test.ts | 86 - .../test/hooks/admin/notes/queries.test.ts | 32 - .../admin/notifications/mutations.test.ts | 32 - .../hooks/admin/notifications/queries.test.ts | 18 - .../hooks/admin/order-edits/mutations.test.ts | 277 - .../hooks/admin/order-edits/queries.test.ts | 37 - .../test/hooks/admin/orders/mutations.test.ts | 229 - .../test/hooks/admin/orders/queries.test.ts | 32 - .../payment-collections/mutations.test.ts | 80 - .../admin/payment-collections/queries.test.ts | 21 - .../hooks/admin/payments/mutations.test.ts | 58 - .../test/hooks/admin/payments/queries.test.ts | 18 - .../hooks/admin/price-lists/mutations.test.ts | 197 - .../hooks/admin/price-lists/queries.test.ts | 35 - .../product-categories/mutations.test.ts | 132 - .../admin/product-categories/queries.test.ts | 40 - .../hooks/admin/products/mutations.test.ts | 155 - .../test/hooks/admin/products/queries.test.ts | 50 - .../publishable-api-keys/mutations.test.ts | 167 - .../publishable-api-keys/queries.test.ts | 62 - .../hooks/admin/regions/mutations.test.ts | 174 - .../test/hooks/admin/regions/queries.test.ts | 54 - .../admin/reservations/mutations.test.ts | 85 - .../hooks/admin/reservations/queries.test.ts | 35 - .../admin/return-reasons/mutations.test.ts | 85 - .../admin/return-reasons/queries.test.ts | 35 - .../hooks/admin/returns/mutations.test.ts | 49 - .../test/hooks/admin/returns/queries.test.ts | 18 - .../admin/sales-channels/mutations.test.ts | 132 - .../admin/sales-channels/queries.test.ts | 35 - .../admin/shipping-options/mutations.test.ts | 96 - .../admin/shipping-options/queries.test.ts | 38 - .../admin/shipping-profiles/mutations.test.ts | 85 - .../admin/shipping-profiles/queries.test.ts | 38 - .../admin/stock-location/mutations.test.ts | 87 - .../admin/stock-location/queries.test.ts | 40 - .../test/hooks/admin/store/mutations.test.ts | 65 - .../test/hooks/admin/store/queries.test.ts | 35 - .../test/hooks/admin/swaps/mutations.test.ts | 149 - .../test/hooks/admin/swaps/queries.test.ts | 32 - .../hooks/admin/uploads/mutations.test.ts | 46 - .../test/hooks/admin/users/mutations.test.ts | 129 - .../test/hooks/admin/users/queries.test.ts | 32 - .../hooks/admin/variants/mutations.test.ts | 88 - .../test/hooks/admin/variants/queries.test.ts | 59 - .../test/hooks/store/carts/mutations.test.ts | 203 - .../test/hooks/store/carts/queries.test.ts | 18 - .../hooks/store/collections/queries.test.ts | 32 - .../hooks/store/customers/mutations.test.ts | 59 - .../hooks/store/customers/queries.test.ts | 89 - .../hooks/store/gift_cards/queries.test.ts | 18 - .../hooks/store/line-items/mutations.test.ts | 89 - .../hooks/store/order-edits/mutations.test.ts | 52 - .../hooks/store/order-edits/queries.test.ts | 21 - .../test/hooks/store/orders/mutations.test.ts | 31 - .../test/hooks/store/orders/queries.test.ts | 79 - .../payment-collections/mutations.test.ts | 138 - .../store/payment-collections/queries.test.ts | 21 - .../hooks/store/product-tags/queries.test.ts | 19 - .../test/hooks/store/products/queries.test.ts | 53 - .../test/hooks/store/regions/queries.test.ts | 32 - .../store/return-reasons/queries.test.ts | 35 - .../hooks/store/returns/mutations.test.ts | 34 - .../store/shipping-options/queries.test.ts | 83 - .../test/hooks/store/swaps/mutations.test.ts | 40 - .../test/hooks/store/swaps/queries.test.ts | 18 - .../session-cart-context/session-cart.test.ts | 322 - packages/medusa-react/test/utils.tsx | 72 - .../medusa-react/test/utils/utils.test.ts | 154 - packages/medusa-react/tsconfig.json | 35 - packages/medusa-react/tsup.config.ts | 18 - packages/medusa/src/api/index.js | 88 - .../batch-job/can-access-batch-job.ts | 20 - .../batch-job/get-requested-batch-job.ts | 14 - .../does-condition-belong-to-discount.ts | 33 - packages/medusa/src/api/middlewares/index.ts | 34 - .../extend-request-params.ts | 40 - ...idate-product-sales-channel-association.ts | 51 - .../validate-sales-channel-param.ts | 46 - ...idate-variant-sales-channel-association.ts | 54 - .../validators/product-existence.ts | 37 - .../validators/sales-channel-existence.ts | 37 - .../middlewares/with-default-sales-channel.ts | 51 - .../create-analytics-config.ts | 33 - .../delete-analytics-config.ts | 23 - .../analytics-configs/get-analytics-config.ts | 14 - .../routes/admin/analytics-configs/index.ts | 43 - .../update-analytics-config.ts | 35 - .../api/routes/admin/apps/authorize-app.ts | 98 - .../medusa/src/api/routes/admin/apps/index.ts | 47 - .../medusa/src/api/routes/admin/apps/list.ts | 48 - .../api/routes/admin/auth/create-session.ts | 141 - .../api/routes/admin/auth/delete-session.ts | 77 - .../src/api/routes/admin/auth/get-session.ts | 84 - .../src/api/routes/admin/auth/get-token.ts | 99 - .../medusa/src/api/routes/admin/auth/index.ts | 60 - .../routes/admin/batch/cancel-batch-job.ts | 94 - .../routes/admin/batch/confirm-batch-job.ts | 94 - .../routes/admin/batch/create-batch-job.ts | 169 - .../api/routes/admin/batch/get-batch-job.ts | 78 - .../src/api/routes/admin/batch/index.ts | 110 - .../api/routes/admin/batch/list-batch-jobs.ts | 435 - .../collections/__tests__/add-products.js | 94 - .../__tests__/create-collection.js | 67 - .../__tests__/delete-collection.js | 42 - .../collections/__tests__/get-collection.js | 39 - .../collections/__tests__/list-collections.js | 28 - .../collections/__tests__/remove-products.js | 64 - .../__tests__/update-collection.js | 44 - .../routes/admin/collections/add-products.ts | 146 - .../admin/collections/create-collection.ts | 145 - .../admin/collections/delete-collection.ts | 103 - .../admin/collections/get-collection.ts | 91 - .../src/api/routes/admin/collections/index.ts | 176 - .../admin/collections/list-collections.ts | 265 - .../admin/collections/remove-products.ts | 145 - .../admin/collections/update-collection.ts | 152 - .../currencies/__tests__/list-currencies.ts | 52 - .../currencies/__tests__/update-currency.ts | 48 - .../src/api/routes/admin/currencies/index.ts | 80 - .../admin/currencies/list-currencies.ts | 157 - .../admin/currencies/update-currency.ts | 131 - .../__tests__/create-customer-group.ts | 65 - .../__tests__/get-customer-group.ts | 33 - .../customer-groups/add-customers-batch.ts | 163 - .../customer-groups/create-customer-group.ts | 133 - .../customer-groups/delete-customer-group.ts | 102 - .../customer-groups/delete-customers-batch.ts | 164 - .../get-customer-group-customers.ts | 149 - .../customer-groups/get-customer-group.ts | 100 - .../api/routes/admin/customer-groups/index.ts | 131 - .../customer-groups/list-customer-groups.ts | 242 - .../customer-groups/update-customer-group.ts | 159 - .../routes/admin/customers/create-customer.ts | 170 - .../routes/admin/customers/get-customer.ts | 105 - .../src/api/routes/admin/customers/index.ts | 77 - .../routes/admin/customers/list-customers.ts | 193 - .../routes/admin/customers/update-customer.ts | 227 - .../admin/discounts/__tests__/add-region.js | 62 - .../discounts/__tests__/create-discount.js | 318 - .../discounts/__tests__/delete-discount.js | 42 - .../admin/discounts/__tests__/get-discount.js | 58 - .../discounts/__tests__/list-discounts.js | 142 - .../discounts/__tests__/remove-region.js | 66 - .../discounts/__tests__/update-discount.js | 128 - .../api/routes/admin/discounts/add-region.ts | 104 - .../add-resources-to-condition-batch.ts | 182 - .../admin/discounts/create-condition.ts | 181 - .../routes/admin/discounts/create-discount.ts | 382 - .../admin/discounts/create-dynamic-code.ts | 165 - .../admin/discounts/delete-condition.ts | 149 - .../routes/admin/discounts/delete-discount.ts | 90 - .../admin/discounts/delete-dynamic-code.ts | 102 - .../delete-resources-from-condition-batch.ts | 182 - .../routes/admin/discounts/get-condition.ts | 111 - .../admin/discounts/get-discount-by-code.ts | 96 - .../routes/admin/discounts/get-discount.ts | 93 - .../src/api/routes/admin/discounts/index.ts | 366 - .../routes/admin/discounts/list-discounts.ts | 241 - .../routes/admin/discounts/remove-region.ts | 102 - .../admin/discounts/update-condition.ts | 183 - .../routes/admin/discounts/update-discount.ts | 343 - .../admin/draft-orders/create-draft-order.ts | 388 - .../admin/draft-orders/create-line-item.ts | 237 - .../admin/draft-orders/delete-draft-order.ts | 102 - .../admin/draft-orders/delete-line-item.ts | 130 - .../admin/draft-orders/get-draft-order.ts | 111 - .../api/routes/admin/draft-orders/index.ts | 259 - .../admin/draft-orders/list-draft-orders.ts | 228 - .../admin/draft-orders/register-payment.ts | 191 - .../admin/draft-orders/update-draft-order.ts | 260 - .../admin/draft-orders/update-line-item.ts | 217 - .../admin/gift-cards/create-gift-card.ts | 165 - .../admin/gift-cards/delete-gift-card.ts | 97 - .../routes/admin/gift-cards/get-gift-card.ts | 87 - .../src/api/routes/admin/gift-cards/index.ts | 143 - .../admin/gift-cards/list-gift-cards.ts | 146 - .../admin/gift-cards/update-gift-card.ts | 170 - packages/medusa/src/api/routes/admin/index.js | 122 - .../inventory-items/create-inventory-item.ts | 340 - .../inventory-items/create-location-level.ts | 172 - .../inventory-items/delete-inventory-item.ts | 95 - .../inventory-items/delete-location-level.ts | 111 - .../inventory-items/get-inventory-item.ts | 104 - .../api/routes/admin/inventory-items/index.ts | 330 - .../inventory-items/list-inventory-items.ts | 281 - .../inventory-items/list-location-levels.ts | 136 - .../inventory-items/update-inventory-item.ts | 221 - .../inventory-items/update-location-level.ts | 152 - .../inventory-items/utils/join-levels.ts | 84 - .../inventory-items/utils/join-variants.ts | 56 - .../admin/invites/__tests__/accept-invite.js | 38 - .../admin/invites/__tests__/create-invite.js | 65 - .../admin/invites/__tests__/resend-invite.js | 31 - .../api/routes/admin/invites/accept-invite.ts | 196 - .../api/routes/admin/invites/create-invite.ts | 108 - .../api/routes/admin/invites/delete-invite.ts | 96 - .../src/api/routes/admin/invites/index.ts | 78 - .../api/routes/admin/invites/list-invites.ts | 58 - .../api/routes/admin/invites/resend-invite.ts | 92 - .../src/api/routes/admin/notes/create-note.ts | 150 - .../src/api/routes/admin/notes/delete-note.ts | 88 - .../src/api/routes/admin/notes/get-note.ts | 84 - .../src/api/routes/admin/notes/index.ts | 94 - .../src/api/routes/admin/notes/list-notes.ts | 140 - .../src/api/routes/admin/notes/update-note.ts | 129 - .../api/routes/admin/notifications/index.ts | 89 - .../admin/notifications/list-notifications.ts | 250 - .../notifications/resend-notification.ts | 144 - .../__tests__/cancel-order-edit.ts | 49 - .../__tests__/confirm-order-edit.ts | 50 - .../__tests__/create-order-edit.ts | 47 - .../order-edits/__tests__/delete-line-item.ts | 40 - .../delete-order-edit-item-change.ts | 49 - .../__tests__/delete-order-edit.ts | 41 - .../admin/order-edits/__tests__/get-order.ts | 41 - .../order-edits/__tests__/list-order-edit.ts | 42 - .../__tests__/request-confirmation.ts | 49 - .../__tests__/update-order-edit-line-item.ts | 45 - .../routes/admin/order-edits/add-line-item.ts | 164 - .../admin/order-edits/cancel-order-edit.ts | 113 - .../admin/order-edits/confirm-order-edit.ts | 111 - .../admin/order-edits/create-order-edit.ts | 141 - .../admin/order-edits/delete-line-item.ts | 118 - .../delete-order-edit-item-change.ts | 98 - .../admin/order-edits/delete-order-edit.ts | 90 - .../admin/order-edits/get-order-edit.ts | 98 - .../src/api/routes/admin/order-edits/index.ts | 270 - .../admin/order-edits/list-order-edit.ts | 137 - .../admin/order-edits/request-confirmation.ts | 165 - .../update-order-edit-line-item.ts | 154 - .../admin/order-edits/update-order-edit.ts | 146 - .../admin/orders/__tests__/archive-order.js | 40 - .../admin/orders/__tests__/cancel-claim.js | 64 - .../__tests__/cancel-fulfillment-claim.js | 92 - .../__tests__/cancel-fulfillment-swap.js | 92 - .../orders/__tests__/cancel-fulfillment.js | 64 - .../admin/orders/__tests__/cancel-order.js | 40 - .../admin/orders/__tests__/cancel-swap.js | 64 - .../admin/orders/__tests__/capture-payment.js | 40 - .../admin/orders/__tests__/create-claim.js | 176 - .../orders/__tests__/create-fulfillment.js | 55 - .../admin/orders/__tests__/get-order.js | 75 - .../admin/orders/__tests__/return-order.js | 294 - .../admin/orders/__tests__/update-order.js | 63 - .../admin/orders/add-shipping-method.ts | 171 - .../api/routes/admin/orders/archive-order.ts | 106 - .../api/routes/admin/orders/cancel-claim.ts | 119 - .../admin/orders/cancel-fulfillment-claim.ts | 141 - .../admin/orders/cancel-fulfillment-swap.ts | 143 - .../routes/admin/orders/cancel-fulfillment.ts | 167 - .../api/routes/admin/orders/cancel-order.ts | 105 - .../api/routes/admin/orders/cancel-swap.ts | 126 - .../routes/admin/orders/capture-payment.ts | 108 - .../api/routes/admin/orders/complete-order.ts | 108 - .../admin/orders/create-claim-shipment.ts | 161 - .../api/routes/admin/orders/create-claim.ts | 583 - .../routes/admin/orders/create-fulfillment.ts | 311 - .../create-reservation-for-line-item.ts | 117 - .../routes/admin/orders/create-shipment.ts | 182 - .../admin/orders/create-swap-shipment.ts | 184 - .../api/routes/admin/orders/create-swap.ts | 487 - .../api/routes/admin/orders/fulfill-claim.ts | 203 - .../api/routes/admin/orders/fulfill-swap.ts | 214 - .../src/api/routes/admin/orders/get-order.ts | 105 - .../routes/admin/orders/get-reservations.ts | 75 - .../src/api/routes/admin/orders/index.ts | 783 - .../api/routes/admin/orders/list-orders.ts | 289 - .../admin/orders/process-swap-payment.ts | 118 - .../api/routes/admin/orders/refund-payment.ts | 179 - .../api/routes/admin/orders/request-return.ts | 449 - .../api/routes/admin/orders/update-claim.ts | 321 - .../api/routes/admin/orders/update-order.ts | 309 - .../delete-payment-collection.ts | 85 - .../get-payment-collection.ts | 103 - .../routes/admin/payment-collections/index.ts | 117 - .../mark-authorized-payment-collection.ts | 101 - .../update-payment-collection.ts | 144 - .../routes/admin/payments/capture-payment.ts | 91 - .../api/routes/admin/payments/get-payment.ts | 94 - .../src/api/routes/admin/payments/index.ts | 86 - .../routes/admin/payments/refund-payment.ts | 163 - .../price-lists/__tests__/add-prices-batch.ts | 105 - .../__tests__/create-price-list.ts | 120 - .../__tests__/delete-price-list.ts | 38 - .../__tests__/delete-prices-batch.ts | 76 - .../price-lists/__tests__/get-price-list.ts | 36 - .../price-lists/__tests__/list-price-lists.ts | 45 - .../__tests__/update-price-list.ts | 37 - .../admin/price-lists/add-prices-batch.ts | 195 - .../admin/price-lists/create-price-list.ts | 292 - .../admin/price-lists/delete-price-list.ts | 99 - .../admin/price-lists/delete-prices-batch.ts | 134 - .../price-lists/delete-product-prices.ts | 112 - .../delete-products-prices-batch.ts | 147 - .../price-lists/delete-variant-prices.ts | 110 - .../admin/price-lists/get-price-list.ts | 96 - .../src/api/routes/admin/price-lists/index.ts | 305 - .../price-lists/list-price-list-products.ts | 362 - .../admin/price-lists/list-price-lists.ts | 243 - .../admin/price-lists/update-price-list.ts | 270 - .../product-categories/add-products-batch.ts | 178 - .../create-product-category.ts | 170 - .../delete-product-category.ts | 110 - .../delete-products-batch.ts | 176 - .../get-product-category.ts | 107 - .../routes/admin/product-categories/index.ts | 229 - .../list-product-categories.ts | 178 - .../update-product-category.ts | 197 - .../api/routes/admin/product-tags/index.ts | 63 - .../admin/product-tags/list-product-tags.ts | 256 - .../api/routes/admin/product-types/index.ts | 63 - .../admin/product-types/list-product-types.ts | 235 - .../admin/products/__tests__/add-option.js | 42 - .../products/__tests__/create-product.js | 236 - .../products/__tests__/create-variant.js | 61 - .../admin/products/__tests__/delete-option.js | 46 - .../products/__tests__/delete-product.js | 46 - .../products/__tests__/delete-variant.js | 45 - .../admin/products/__tests__/get-product.js | 82 - .../admin/products/__tests__/list-products.js | 32 - .../admin/products/__tests__/list-variants.js | 74 - .../admin/products/__tests__/update-option.js | 43 - .../products/__tests__/update-product.js | 79 - .../products/__tests__/update-variant.js | 67 - .../api/routes/admin/products/add-option.ts | 146 - .../routes/admin/products/create-product.ts | 777 - .../routes/admin/products/create-variant.ts | 433 - .../routes/admin/products/delete-option.ts | 114 - .../routes/admin/products/delete-product.ts | 98 - .../routes/admin/products/delete-variant.ts | 124 - .../api/routes/admin/products/get-product.ts | 161 - .../src/api/routes/admin/products/index.ts | 561 - .../routes/admin/products/list-products.ts | 370 - .../admin/products/list-tag-usage-count.ts | 84 - .../api/routes/admin/products/list-types.ts | 60 - .../routes/admin/products/list-variants.ts | 255 - .../api/routes/admin/products/set-metadata.ts | 124 - .../transaction/create-product-variant.ts | 246 - .../routes/admin/products/update-option.ts | 150 - .../routes/admin/products/update-product.ts | 767 - .../routes/admin/products/update-variant.ts | 396 - .../add-channels-batch.ts | 170 - .../create-publishable-api-key.ts | 125 - .../delete-channels-batch.ts | 170 - .../delete-publishable-api-key.ts | 98 - .../get-publishable-api-key.ts | 97 - .../admin/publishable-api-keys/index.ts | 163 - ...list-publishable-api-key-sales-channels.ts | 129 - .../list-publishable-api-keys.ts | 237 - .../revoke-publishable-api-key.ts | 108 - .../update-publishable-api-key.ts | 136 - .../admin/regions/__tests__/add-country.js | 35 - .../__tests__/add-fulfillment-provider.js | 39 - .../regions/__tests__/add-payment-provider.js | 39 - .../admin/regions/__tests__/create-region.js | 43 - .../admin/regions/__tests__/delete-region.js | 31 - .../admin/regions/__tests__/get-region.js | 60 - .../admin/regions/__tests__/list-regions.js | 105 - .../admin/regions/__tests__/remove-country.js | 32 - .../__tests__/remove-fulfillment-provider.js | 38 - .../__tests__/remove-payment-provider.js | 36 - .../admin/regions/__tests__/update-region.js | 47 - .../api/routes/admin/regions/add-country.ts | 144 - .../admin/regions/add-fulfillment-provider.ts | 143 - .../admin/regions/add-payment-provider.ts | 143 - .../api/routes/admin/regions/create-region.ts | 235 - .../api/routes/admin/regions/delete-region.ts | 101 - .../admin/regions/get-fulfillment-options.ts | 117 - .../api/routes/admin/regions/get-region.ts | 91 - .../src/api/routes/admin/regions/index.ts | 234 - .../api/routes/admin/regions/list-regions.ts | 232 - .../routes/admin/regions/remove-country.ts | 114 - .../regions/remove-fulfillment-provider.ts | 109 - .../admin/regions/remove-payment-provider.ts | 109 - .../api/routes/admin/regions/update-region.ts | 240 - .../admin/reservations/create-reservation.ts | 181 - .../admin/reservations/delete-reservation.ts | 97 - .../admin/reservations/get-reservation.ts | 95 - .../api/routes/admin/reservations/index.ts | 162 - .../admin/reservations/list-reservations.ts | 304 - .../admin/reservations/update-reservation.ts | 167 - .../utils/join-inventory-items.ts | 32 - .../reservations/utils/join-line-items.ts | 30 - .../utils/validate-reservation-quantity.ts | 31 - .../admin/return-reasons/create-reason.ts | 167 - .../admin/return-reasons/delete-reason.ts | 102 - .../routes/admin/return-reasons/get-reason.ts | 96 - .../api/routes/admin/return-reasons/index.ts | 120 - .../admin/return-reasons/list-reasons.ts | 100 - .../admin/return-reasons/update-reason.ts | 166 - .../admin/returns/__tests__/receive-return.js | 59 - .../api/routes/admin/returns/cancel-return.ts | 109 - .../src/api/routes/admin/returns/index.ts | 156 - .../api/routes/admin/returns/list-returns.ts | 139 - .../routes/admin/returns/receive-return.ts | 221 - .../__tests__/add-product-batch.ts | 42 - .../__tests__/create-sales-channel.ts | 40 - .../__tests__/delete-products-batch.ts | 40 - .../__tests__/delete-sales-channel.ts | 44 - .../__tests__/get-sales-channel.ts | 45 - .../__tests__/list-sales-channels.js | 56 - .../__tests__/update-sales-channel.ts | 49 - .../admin/sales-channels/add-product-batch.ts | 161 - .../associate-stock-location.ts | 143 - .../sales-channels/create-sales-channel.ts | 140 - .../sales-channels/delete-products-batch.ts | 163 - .../sales-channels/delete-sales-channel.ts | 104 - .../admin/sales-channels/get-sales-channel.ts | 91 - .../api/routes/admin/sales-channels/index.ts | 184 - .../sales-channels/list-sales-channels.ts | 248 - .../sales-channels/remove-stock-location.ts | 138 - .../sales-channels/update-sales-channel.ts | 150 - .../__tests__/create-shipping-option.js | 95 - .../__tests__/delete-shipping-option.js | 34 - .../__tests__/get-shipping-options.js | 57 - .../__tests__/list-shipping-options.js | 41 - .../__tests__/update-shipping-option.js | 56 - .../create-shipping-option.ts | 297 - .../delete-shipping-option.ts | 99 - .../shipping-options/get-shipping-option.ts | 95 - .../routes/admin/shipping-options/index.ts | 156 - .../shipping-options/list-shipping-options.ts | 308 - .../update-shipping-option.ts | 260 - .../__tests__/create-shipping-profile.js | 35 - .../__tests__/delete-shipping-profile.js | 34 - .../__tests__/get-shipping-profile.js | 50 - .../__tests__/list-shipping-profiles.js | 28 - .../__tests__/update-shipping-profile.js | 40 - .../create-shipping-profile.ts | 147 - .../delete-shipping-profile.ts | 102 - .../shipping-profiles/get-shipping-profile.ts | 101 - .../routes/admin/shipping-profiles/index.ts | 110 - .../list-shipping-profiles.ts | 91 - .../update-shipping-profile.ts | 191 - .../stock-locations/create-stock-location.ts | 236 - .../stock-locations/delete-stock-location.ts | 106 - .../stock-locations/get-stock-location.ts | 118 - .../api/routes/admin/stock-locations/index.ts | 159 - .../stock-locations/list-stock-locations.ts | 275 - .../stock-locations/update-stock-location.ts | 219 - .../utils/join-sales-channels.ts | 32 - .../admin/store/__tests__/add-currency.js | 28 - .../routes/admin/store/__tests__/get-store.js | 30 - .../admin/store/__tests__/remove-currency.js | 28 - .../admin/store/__tests__/update-store.js | 89 - .../api/routes/admin/store/add-currency.ts | 99 - .../src/api/routes/admin/store/get-store.ts | 121 - .../src/api/routes/admin/store/index.ts | 104 - .../admin/store/list-payment-providers.ts | 90 - .../routes/admin/store/list-tax-providers.ts | 89 - .../api/routes/admin/store/remove-currency.ts | 98 - .../api/routes/admin/store/update-store.ts | 178 - .../routes/admin/swaps/__tests__/get-swap.js | 77 - .../admin/swaps/__tests__/list-swaps.js | 48 - .../src/api/routes/admin/swaps/get-swap.ts | 90 - .../src/api/routes/admin/swaps/index.ts | 121 - .../src/api/routes/admin/swaps/list-swaps.ts | 127 - .../admin/tax-rates/add-to-product-types.ts | 192 - .../routes/admin/tax-rates/add-to-products.ts | 185 - .../tax-rates/add-to-shipping-options.ts | 191 - .../routes/admin/tax-rates/create-tax-rate.ts | 259 - .../routes/admin/tax-rates/delete-tax-rate.ts | 96 - .../routes/admin/tax-rates/get-tax-rate.ts | 132 - .../src/api/routes/admin/tax-rates/index.ts | 175 - .../routes/admin/tax-rates/list-tax-rates.ts | 372 - .../tax-rates/remove-from-product-types.ts | 194 - .../admin/tax-rates/remove-from-products.ts | 185 - .../tax-rates/remove-from-shipping-options.ts | 192 - .../routes/admin/tax-rates/update-tax-rate.ts | 250 - .../admin/tax-rates/utils/get-query-config.ts | 81 - .../admin/uploads/create-protected-upload.ts | 105 - .../api/routes/admin/uploads/create-upload.ts | 104 - .../api/routes/admin/uploads/delete-upload.ts | 115 - .../routes/admin/uploads/get-download-url.ts | 111 - .../src/api/routes/admin/uploads/index.ts | 110 - .../admin/users/__tests__/create-user.js | 71 - .../admin/users/__tests__/delete-user.js | 46 - .../routes/admin/users/__tests__/get-user.js | 42 - .../admin/users/__tests__/list-users.js | 35 - .../users/__tests__/reset-password-token.js | 37 - .../admin/users/__tests__/reset-password.js | 51 - .../admin/users/__tests__/update-user.js | 42 - .../src/api/routes/admin/users/create-user.ts | 157 - .../src/api/routes/admin/users/delete-user.ts | 96 - .../src/api/routes/admin/users/get-user.ts | 86 - .../src/api/routes/admin/users/index.ts | 133 - .../src/api/routes/admin/users/list-users.ts | 278 - .../admin/users/reset-password-token.ts | 132 - .../api/routes/admin/users/reset-password.ts | 186 - .../src/api/routes/admin/users/update-user.ts | 161 - .../routes/admin/variants/get-inventory.ts | 268 - .../api/routes/admin/variants/get-variant.ts | 102 - .../src/api/routes/admin/variants/index.ts | 135 - .../routes/admin/variants/list-variants.ts | 350 - .../workflows-executions/get-execution.ts | 26 - .../admin/workflows-executions/index.ts | 84 - .../workflows-executions/list-execution.ts | 29 - .../workflows-executions/query-config.ts | 23 - .../workflows-executions/run-workflow.ts | 35 - .../workflows-executions/set-step-failure.ts | 41 - .../workflows-executions/set-step-success.ts | 41 - .../admin/workflows-executions/subscribe.ts | 62 - .../admin/workflows-executions/validators.ts | 54 - .../api/routes/store/auth/create-session.ts | 112 - .../api/routes/store/auth/delete-session.ts | 55 - .../src/api/routes/store/auth/exists.ts | 62 - .../src/api/routes/store/auth/get-session.ts | 61 - .../src/api/routes/store/auth/get-token.ts | 99 - .../medusa/src/api/routes/store/auth/index.ts | 78 - .../carts/__tests__/add-shipping-method.js | 141 - .../store/carts/__tests__/complete-cart.js | 56 - .../store/carts/__tests__/create-cart.js | 154 - .../store/carts/__tests__/create-line-item.js | 89 - .../__tests__/create-payment-sessions.js | 36 - .../routes/store/carts/__tests__/get-cart.js | 53 - .../__tests__/refresh-payment-session.js | 42 - .../store/carts/__tests__/update-cart.js | 105 - .../store/carts/__tests__/update-line-item.js | 234 - .../carts/__tests__/update-payment-session.js | 56 - .../routes/store/carts/add-shipping-method.ts | 156 - .../api/routes/store/carts/calculate-taxes.ts | 135 - .../api/routes/store/carts/complete-cart.ts | 130 - .../src/api/routes/store/carts/create-cart.ts | 301 - .../store/carts/create-line-item/index.ts | 259 - .../create-line-item/utils/handler-steps.ts | 79 - .../store/carts/create-payment-sessions.ts | 192 - .../api/routes/store/carts/delete-discount.ts | 88 - .../routes/store/carts/delete-line-item.ts | 119 - .../store/carts/delete-payment-session.ts | 109 - .../src/api/routes/store/carts/get-cart.ts | 134 - .../src/api/routes/store/carts/index.ts | 366 - .../store/carts/refresh-payment-session.ts | 101 - .../routes/store/carts/set-payment-session.ts | 139 - .../src/api/routes/store/carts/update-cart.ts | 332 - .../routes/store/carts/update-line-item.ts | 185 - .../store/carts/update-payment-session.ts | 145 - .../collections/__tests__/get-collection.js | 27 - .../collections/__tests__/list-collections.js | 108 - .../store/collections/get-collection.ts | 77 - .../src/api/routes/store/collections/index.ts | 83 - .../store/collections/list-collections.ts | 192 - .../customers/__tests__/create-customer.js | 73 - .../__tests__/reset-password-token.js | 42 - .../customers/__tests__/reset-password.js | 65 - .../customers/__tests__/update-customer.js | 174 - .../routes/store/customers/create-address.ts | 125 - .../routes/store/customers/create-customer.ts | 187 - .../routes/store/customers/delete-address.ts | 77 - .../routes/store/customers/get-customer.ts | 84 - .../store/customers/get-payment-methods.ts | 89 - .../src/api/routes/store/customers/index.ts | 295 - .../api/routes/store/customers/list-orders.ts | 375 - .../store/customers/reset-password-token.ts | 104 - .../routes/store/customers/reset-password.ts | 141 - .../routes/store/customers/update-address.ts | 105 - .../routes/store/customers/update-customer.ts | 185 - .../routes/store/gift-cards/get-gift-card.ts | 91 - .../src/api/routes/store/gift-cards/index.ts | 43 - packages/medusa/src/api/routes/store/index.js | 61 - .../__tests__/complete-order-edit.ts | 65 - .../__tests__/decline-order-edit.ts | 41 - .../store/order-edits/__tests__/get-order.ts | 35 - .../store/order-edits/complete-order-edit.ts | 157 - .../store/order-edits/decline-order-edit.ts | 128 - .../store/order-edits/get-order-edit.ts | 88 - .../src/api/routes/store/order-edits/index.ts | 97 - .../orders/__tests__/get-order-by-cart.js | 38 - .../store/orders/__tests__/get-order.js | 36 - .../store/orders/__tests__/lookup-order.js | 21 - .../store/orders/confirm-order-request.ts | 158 - .../routes/store/orders/get-order-by-cart.ts | 84 - .../src/api/routes/store/orders/get-order.ts | 87 - .../src/api/routes/store/orders/index.ts | 228 - .../api/routes/store/orders/lookup-order.ts | 177 - .../api/routes/store/orders/request-order.ts | 173 - .../authorize-batch-payment-sessions.ts | 127 - .../authorize-payment-session.ts | 112 - .../get-payment-collection.ts | 104 - .../routes/store/payment-collections/index.ts | 116 - .../manage-batch-payment-sessions.ts | 226 - .../manage-payment-session.ts | 135 - .../refresh-payment-session.ts | 101 - .../__tests__/get-product-category.ts | 70 - .../get-product-category.ts | 113 - .../routes/store/product-categories/index.ts | 133 - .../list-product-categories.ts | 171 - .../api/routes/store/product-tags/index.ts | 66 - .../store/product-tags/list-product-tags.ts | 228 - .../api/routes/store/product-types/index.ts | 70 - .../store/product-types/list-product-types.ts | 234 - .../store/products/__tests__/get-product.js | 71 - .../store/products/__tests__/list-products.js | 78 - .../routes/store/products/__tests__/search.js | 42 - .../api/routes/store/products/get-product.ts | 217 - .../src/api/routes/store/products/index.ts | 304 - .../routes/store/products/list-products.ts | 579 - .../src/api/routes/store/products/search.ts | 116 - .../store/regions/__tests__/get-region.js | 52 - .../store/regions/__tests__/list-regions.js | 55 - .../api/routes/store/regions/get-region.ts | 80 - .../src/api/routes/store/regions/index.ts | 127 - .../api/routes/store/regions/list-regions.ts | 154 - .../routes/store/return-reasons/get-reason.ts | 90 - .../api/routes/store/return-reasons/index.ts | 81 - .../store/return-reasons/list-reasons.ts | 90 - .../api/routes/store/returns/create-return.ts | 354 - .../src/api/routes/store/returns/index.ts | 39 - .../__tests__/list-options.js | 41 - .../__tests__/list-shipping-options.js | 47 - .../routes/store/shipping-options/index.ts | 64 - .../store/shipping-options/list-options.ts | 162 - .../shipping-options/list-shipping-options.ts | 102 - .../src/api/routes/store/swaps/create-swap.ts | 407 - .../routes/store/swaps/get-swap-by-cart.ts | 83 - .../src/api/routes/store/swaps/index.ts | 82 - .../store/variants/__tests__/get-variant.js | 37 - .../store/variants/__tests__/list-variants.js | 20 - .../api/routes/store/variants/get-variant.ts | 145 - .../src/api/routes/store/variants/index.ts | 97 - .../routes/store/variants/list-variants.ts | 264 - packages/medusa/src/commands/seed.ts | 297 - .../medusa/src/controllers/customers/index.ts | 2 - .../controllers/customers/list-customers.ts | 62 - packages/medusa/src/index.js | 3 - .../__tests__/event-bus-service.spec.ts | 139 - .../medusa/src/interfaces/abstract-parser.ts | 42 - .../src/interfaces/batch-job-strategy.ts | 114 - .../interfaces/cart-completion-strategy.ts | 44 - packages/medusa/src/interfaces/csv-parser.ts | 82 - .../medusa/src/interfaces/file-service.ts | 364 - .../src/interfaces/fulfillment-service.ts | 511 - packages/medusa/src/interfaces/index.ts | 10 - .../src/interfaces/notification-service.ts | 284 - .../src/interfaces/payment-processor.ts | 787 - .../medusa/src/interfaces/payment-service.ts | 269 - .../interfaces/price-selection-strategy.ts | 374 - .../interfaces/tax-calculation-strategy.ts | 170 - packages/medusa/src/interfaces/tax-service.ts | 259 - .../src/loaders/__tests__/default.spec.ts | 75 - .../src/loaders/__tests__/plugins.spec.ts | 20 +- packages/medusa/src/loaders/api.ts | 41 +- packages/medusa/src/loaders/database.ts | 1 - packages/medusa/src/loaders/defaults.ts | 288 - .../medusa/src/loaders/helpers/plugins.ts | 79 - .../helpers/routing/__tests__/index.spec.ts | 2 +- .../src/loaders/helpers/routing/index.ts | 4 +- .../subscribers/order-notifier.ts | 7 +- .../subscribers/product-updater.ts | 3 +- .../subscribers/variant-created.ts | 3 +- .../helpers/subscribers/__mocks__/index.ts | 2 +- .../subscribers/__tests__/index.spec.ts | 19 +- .../src/loaders/helpers/subscribers/index.ts | 24 +- packages/medusa/src/loaders/index.ts | 7 - .../src/loaders/load-medusa-project-apis.ts | 3 +- packages/medusa/src/loaders/passport.ts | 12 +- packages/medusa/src/loaders/plugins.ts | 44 +- packages/medusa/src/loaders/search-index.ts | 19 +- packages/medusa/src/loaders/strategies.ts | 27 +- packages/medusa/src/models/address.ts | 187 - .../medusa/src/models/analytics-config.ts | 26 - packages/medusa/src/models/batch-job.ts | 280 - packages/medusa/src/models/cart.ts | 484 - packages/medusa/src/models/claim-image.ts | 92 - packages/medusa/src/models/claim-item.ts | 194 - packages/medusa/src/models/claim-order.ts | 338 - packages/medusa/src/models/claim-tag.ts | 67 - packages/medusa/src/models/country.ts | 99 - packages/medusa/src/models/currency.ts | 58 - .../src/models/custom-shipping-option.ts | 114 - packages/medusa/src/models/customer-group.ts | 91 - packages/medusa/src/models/customer.ts | 182 - .../discount-condition-customer-group.ts | 84 - .../discount-condition-product-collection.ts | 86 - .../models/discount-condition-product-tag.ts | 86 - .../models/discount-condition-product-type.ts | 86 - .../src/models/discount-condition-product.ts | 86 - .../medusa/src/models/discount-condition.ts | 270 - packages/medusa/src/models/discount-rule.ts | 153 - packages/medusa/src/models/discount.ts | 203 - packages/medusa/src/models/draft-order.ts | 185 - .../medusa/src/models/fulfillment-item.ts | 65 - .../medusa/src/models/fulfillment-provider.ts | 30 - packages/medusa/src/models/fulfillment.ts | 230 - .../src/models/gift-card-transaction.ts | 115 - packages/medusa/src/models/gift-card.ts | 159 - packages/medusa/src/models/image.ts | 66 - packages/medusa/src/models/index.ts | 78 - packages/medusa/src/models/invite.ts | 109 - .../medusa/src/models/line-item-adjustment.ts | 114 - .../medusa/src/models/line-item-tax-line.ts | 93 - packages/medusa/src/models/line-item.ts | 440 - packages/medusa/src/models/money-amount.ts | 206 - packages/medusa/src/models/note.ts | 107 - .../src/models/notification-provider.ts | 30 - packages/medusa/src/models/notification.ts | 157 - packages/medusa/src/models/oauth.ts | 76 - packages/medusa/src/models/order-edit.ts | 306 - .../medusa/src/models/order-item-change.ts | 145 - .../medusa/src/models/order-sales-channel.ts | 29 - packages/medusa/src/models/order.ts | 754 - .../medusa/src/models/payment-collection.ts | 239 - .../medusa/src/models/payment-provider.ts | 30 - packages/medusa/src/models/payment-session.ts | 180 - packages/medusa/src/models/payment.ts | 210 - packages/medusa/src/models/price-list.ts | 158 - .../medusa/src/models/product-category.ts | 190 - .../medusa/src/models/product-collection.ts | 99 - .../medusa/src/models/product-option-value.ts | 114 - packages/medusa/src/models/product-option.ts | 104 - .../src/models/product-sales-channel.ts | 20 - packages/medusa/src/models/product-tag.ts | 66 - .../medusa/src/models/product-tax-rate.ts | 87 - .../src/models/product-type-tax-rate.ts | 86 - packages/medusa/src/models/product-type.ts | 66 - .../models/product-variant-inventory-item.ts | 86 - .../models/product-variant-money-amount.ts | 24 - packages/medusa/src/models/product-variant.ts | 302 - packages/medusa/src/models/product.ts | 464 - .../publishable-api-key-sales-channel.ts | 62 - .../medusa/src/models/publishable-api-key.ts | 73 - packages/medusa/src/models/refund.ts | 171 - packages/medusa/src/models/region.ts | 227 - packages/medusa/src/models/return-item.ts | 132 - packages/medusa/src/models/return-reason.ts | 121 - packages/medusa/src/models/return.ts | 243 - .../src/models/sales-channel-location.ts | 80 - packages/medusa/src/models/sales-channel.ts | 196 - .../src/models/shipping-method-tax-line.ts | 93 - packages/medusa/src/models/shipping-method.ts | 221 - .../src/models/shipping-option-requirement.ts | 105 - packages/medusa/src/models/shipping-option.ts | 216 - .../medusa/src/models/shipping-profile.ts | 137 - .../medusa/src/models/shipping-tax-rate.ts | 86 - packages/medusa/src/models/store.ts | 172 - packages/medusa/src/models/swap.ts | 341 - packages/medusa/src/models/tax-line.ts | 66 - packages/medusa/src/models/tax-provider.ts | 30 - packages/medusa/src/models/tax-rate.ts | 185 - packages/medusa/src/models/tracking-link.ts | 111 - packages/medusa/src/models/user.ts | 137 - packages/medusa/src/repositories/address.ts | 5 - .../src/repositories/analytics-config.ts | 5 - packages/medusa/src/repositories/batch-job.ts | 5 - packages/medusa/src/repositories/cart.ts | 46 - .../medusa/src/repositories/claim-image.ts | 5 - .../medusa/src/repositories/claim-item.ts | 5 - packages/medusa/src/repositories/claim-tag.ts | 5 - packages/medusa/src/repositories/claim.ts | 5 - packages/medusa/src/repositories/country.ts | 5 - packages/medusa/src/repositories/currency.ts | 5 - .../repositories/custom-shipping-option.ts | 6 - .../medusa/src/repositories/customer-group.ts | 180 - packages/medusa/src/repositories/customer.ts | 50 - .../src/repositories/discount-condition.ts | 383 - .../medusa/src/repositories/discount-rule.ts | 5 - packages/medusa/src/repositories/discount.ts | 5 - .../medusa/src/repositories/draft-order.ts | 5 - .../src/repositories/fulfillment-provider.ts | 6 - .../medusa/src/repositories/fulfillment.ts | 5 - .../src/repositories/gift-card-transaction.ts | 6 - packages/medusa/src/repositories/gift-card.ts | 41 - packages/medusa/src/repositories/image.ts | 54 - packages/medusa/src/repositories/invite.ts | 5 - .../src/repositories/line-item-adjustment.ts | 6 - .../src/repositories/line-item-tax-line.ts | 37 - packages/medusa/src/repositories/line-item.ts | 32 - .../medusa/src/repositories/money-amount.ts | 594 - packages/medusa/src/repositories/note.ts | 5 - .../src/repositories/notification-provider.ts | 6 - .../medusa/src/repositories/notification.ts | 5 - packages/medusa/src/repositories/oauth.ts | 5 - .../medusa/src/repositories/order-edit.ts | 5 - .../src/repositories/order-item-change.ts | 6 - packages/medusa/src/repositories/order.ts | 61 - .../src/repositories/payment-collection.ts | 63 - .../src/repositories/payment-provider.ts | 6 - .../src/repositories/payment-session.ts | 5 - packages/medusa/src/repositories/payment.ts | 5 - .../medusa/src/repositories/price-list.ts | 83 - .../src/repositories/product-category.ts | 211 - .../src/repositories/product-collection.ts | 26 - .../src/repositories/product-option-value.ts | 6 - .../medusa/src/repositories/product-option.ts | 5 - .../medusa/src/repositories/product-tag.ts | 109 - .../src/repositories/product-tax-rate.ts | 5 - .../medusa/src/repositories/product-type.ts | 62 - .../src/repositories/product-variant.ts | 12 - packages/medusa/src/repositories/product.ts | 862 - .../publishable-api-key-sales-channel.ts | 102 - .../src/repositories/publishable-api-key.ts | 6 - packages/medusa/src/repositories/refund.ts | 5 - packages/medusa/src/repositories/region.ts | 5 - .../medusa/src/repositories/return-item.ts | 5 - .../medusa/src/repositories/return-reason.ts | 5 - packages/medusa/src/repositories/return.ts | 5 - .../medusa/src/repositories/sales-channel.ts | 138 - .../repositories/shipping-method-tax-line.ts | 43 - .../src/repositories/shipping-method.ts | 5 - .../shipping-option-requirement.ts | 7 - .../src/repositories/shipping-option.ts | 22 - .../src/repositories/shipping-profile.ts | 25 - .../src/repositories/shipping-tax-rate.ts | 6 - packages/medusa/src/repositories/store.ts | 5 - packages/medusa/src/repositories/swap.ts | 5 - .../medusa/src/repositories/tax-provider.ts | 5 - packages/medusa/src/repositories/tax-rate.ts | 267 - .../medusa/src/repositories/tracking-link.ts | 5 - packages/medusa/src/repositories/user.ts | 5 - .../src/scripts/discount-rule-migration.ts | 132 - .../scripts/gift-card-tax-rate-migration.ts | 101 - .../scripts/line-item-adjustment-migration.ts | 103 - .../src/scripts/migrate-inventory-items.ts | 158 - .../src/scripts/migrate-to-pricing-module.ts | 3 + .../src/scripts/sales-channels-migration.ts | 85 - ...migrate-money-amounts-to-pricing-module.ts | 3 + .../src/services/__fixtures__/new-totals.ts | 82 - .../services/__fixtures__/payment-provider.ts | 145 - .../src/services/__fixtures__/tax-provider.ts | 45 - .../medusa/src/services/__mocks__/auth.js | 26 - .../medusa/src/services/__mocks__/cache.js | 11 - .../medusa/src/services/__mocks__/cart.js | 446 - .../medusa/src/services/__mocks__/claim.js | 26 - .../medusa/src/services/__mocks__/currency.js | 40 - .../src/services/__mocks__/customer-group.js | 20 - .../medusa/src/services/__mocks__/customer.js | 74 - .../medusa/src/services/__mocks__/discount.js | 190 - .../medusa/src/services/__mocks__/document.js | 21 - .../__mocks__/fulfillment-provider.js | 76 - .../src/services/__mocks__/fulfillment.js | 26 - .../src/services/__mocks__/inventory.js | 93 - .../medusa/src/services/__mocks__/invite.js | 27 - .../__mocks__/line-item-adjustment.js | 65 - .../src/services/__mocks__/line-item.js | 71 - .../src/services/__mocks__/new-totals.js | 44 - .../__mocks__/order-edit-item-change.js | 31 - .../src/services/__mocks__/order-edit.js | 161 - .../medusa/src/services/__mocks__/order.js | 245 - .../services/__mocks__/payment-collection.js | 17 - .../services/__mocks__/payment-provider.js | 82 - .../medusa/src/services/__mocks__/payment.js | 15 - .../src/services/__mocks__/price-list.js | 43 - .../medusa/src/services/__mocks__/pricing.js | 26 - .../services/__mocks__/product-category.js | 43 - .../services/__mocks__/product-collection.js | 45 - .../__mocks__/product-variant-inventory.js | 41 - .../src/services/__mocks__/product-variant.js | 328 - .../medusa/src/services/__mocks__/product.js | 222 - .../medusa/src/services/__mocks__/region.js | 103 - .../medusa/src/services/__mocks__/return.js | 23 - .../src/services/__mocks__/sales-channel.js | 74 - .../medusa/src/services/__mocks__/search.js | 9 - .../src/services/__mocks__/shipping-option.js | 166 - .../services/__mocks__/shipping-profile.js | 152 - .../src/services/__mocks__/staged-job.js | 25 - .../src/services/__mocks__/stock-location.js | 46 - .../medusa/src/services/__mocks__/store.js | 32 - .../medusa/src/services/__mocks__/swap.js | 49 - .../src/services/__mocks__/tax-provider.js | 26 - .../medusa/src/services/__mocks__/test-pay.js | 43 - .../medusa/src/services/__mocks__/totals.js | 49 - .../medusa/src/services/__mocks__/user.js | 111 - .../medusa/src/services/__tests__/auth.js | 81 - .../src/services/__tests__/batch-job.ts | 224 - .../medusa/src/services/__tests__/cart.js | 2710 --- .../src/services/__tests__/claim-item.js | 138 - .../medusa/src/services/__tests__/claim.js | 921 - .../src/services/__tests__/csv-parser.js | 403 - .../medusa/src/services/__tests__/currency.ts | 59 - .../__tests__/custom-shipping-option.js | 135 - .../medusa/src/services/__tests__/customer.js | 458 - .../medusa/src/services/__tests__/discount.js | 1348 -- .../src/services/__tests__/draft-order.js | 370 - .../src/services/__tests__/fulfillment.js | 216 - .../src/services/__tests__/gift-card.js | 240 - .../medusa/src/services/__tests__/invite.js | 226 - .../__tests__/line-item-adjustment.js | 307 - .../src/services/__tests__/line-item.js | 803 - .../src/services/__tests__/new-totals.ts | 1138 - .../medusa/src/services/__tests__/note.js | 209 - .../src/services/__tests__/notification.js | 81 - .../__tests__/order-edit-item-change.ts | 68 - .../src/services/__tests__/order-edit.ts | 470 - .../medusa/src/services/__tests__/order.js | 1700 -- .../services/__tests__/payment-collection.ts | 704 - .../services/__tests__/payment-provider.ts | 1043 - .../src/services/__tests__/price-list.js | 194 - .../services/__tests__/product-category.ts | 287 - .../services/__tests__/product-collection.js | 176 - .../src/services/__tests__/product-variant.js | 1005 - .../medusa/src/services/__tests__/product.js | 719 - .../services/__tests__/publishable-api-key.ts | 103 - .../medusa/src/services/__tests__/region.ts | 697 - .../medusa/src/services/__tests__/return.js | 500 - .../src/services/__tests__/sales-channel.ts | 379 - .../src/services/__tests__/shipping-option.js | 702 - .../services/__tests__/shipping-profile.js | 374 - .../medusa/src/services/__tests__/store.js | 214 - .../medusa/src/services/__tests__/swap.ts | 1285 -- .../src/services/__tests__/system-tax.js | 85 - .../src/services/__tests__/tax-provider.js | 257 - .../medusa/src/services/__tests__/totals.js | 1224 -- .../medusa/src/services/__tests__/user.js | 186 - .../medusa/src/services/analytics-config.ts | 109 - packages/medusa/src/services/auth.ts | 174 - packages/medusa/src/services/batch-job.ts | 382 - packages/medusa/src/services/cart.ts | 2984 --- packages/medusa/src/services/claim-item.ts | 253 - packages/medusa/src/services/claim.ts | 915 - packages/medusa/src/services/csv-parser.ts | 202 - packages/medusa/src/services/currency.ts | 156 - .../src/services/custom-shipping-option.ts | 104 - .../medusa/src/services/customer-group.ts | 284 - packages/medusa/src/services/customer.ts | 580 - .../medusa/src/services/discount-condition.ts | 236 - packages/medusa/src/services/discount.ts | 826 - packages/medusa/src/services/draft-order.ts | 489 - packages/medusa/src/services/file.ts | 62 - .../src/services/fulfillment-provider.ts | 195 - packages/medusa/src/services/fulfillment.ts | 359 - packages/medusa/src/services/gift-card.ts | 309 - packages/medusa/src/services/index.ts | 57 +- packages/medusa/src/services/invite.ts | 275 - .../src/services/line-item-adjustment.ts | 309 - packages/medusa/src/services/line-item.ts | 675 - packages/medusa/src/services/new-totals.ts | 770 - packages/medusa/src/services/note.ts | 204 - packages/medusa/src/services/notification.ts | 296 - packages/medusa/src/services/oauth.ts | 180 - .../src/services/order-edit-item-change.ts | 137 - packages/medusa/src/services/order-edit.ts | 873 - packages/medusa/src/services/order.ts | 2113 -- .../medusa/src/services/payment-collection.ts | 618 - .../medusa/src/services/payment-provider.ts | 962 - packages/medusa/src/services/payment.ts | 258 - packages/medusa/src/services/price-list.ts | 565 - packages/medusa/src/services/pricing.ts | 668 - .../medusa/src/services/product-category.ts | 546 - .../medusa/src/services/product-collection.ts | 345 - packages/medusa/src/services/product-tag.ts | 126 - .../medusa/src/services/product-tax-rate.ts | 37 - packages/medusa/src/services/product-type.ts | 108 - .../src/services/product-variant-inventory.ts | 1028 - .../medusa/src/services/product-variant.ts | 1152 - packages/medusa/src/services/product.ts | 1171 - .../src/services/publishable-api-key.ts | 346 - packages/medusa/src/services/region.ts | 845 - packages/medusa/src/services/return-reason.ts | 133 - packages/medusa/src/services/return.ts | 739 - .../src/services/sales-channel-inventory.ts | 53 - .../src/services/sales-channel-location.ts | 151 - packages/medusa/src/services/sales-channel.ts | 410 - packages/medusa/src/services/search.ts | 91 - .../medusa/src/services/shipping-option.ts | 823 - .../medusa/src/services/shipping-profile.ts | 542 - .../medusa/src/services/shipping-tax-rate.ts | 39 - packages/medusa/src/services/store.ts | 274 - .../medusa/src/services/strategy-resolver.ts | 27 - packages/medusa/src/services/swap.ts | 1269 -- .../src/services/system-payment-provider.ts | 51 - packages/medusa/src/services/system-tax.ts | 47 - packages/medusa/src/services/tax-provider.ts | 508 - packages/medusa/src/services/tax-rate.ts | 360 - packages/medusa/src/services/token.ts | 47 - packages/medusa/src/services/totals.ts | 1063 - packages/medusa/src/services/user.ts | 428 - .../__fixtures__/order-export-data.ts | 85 - .../__fixtures__/product-export-data.ts | 410 - .../strategies/__mocks__/cart-completion.js | 14 - .../order/__snapshots__/order-export.ts.snap | 23 - .../batch-jobs/order/order-export.ts | 304 - .../__tests__/batch-jobs/price-list/import.ts | 166 - .../product/__snapshots__/export.ts.snap | 36 - .../__tests__/batch-jobs/product/export.ts | 473 - .../__tests__/batch-jobs/product/import.ts | 195 - .../strategies/__tests__/cart-completion.js | 244 - .../strategies/__tests__/price-selection.js | 890 - .../strategies/__tests__/tax-calculation.js | 285 - .../src/strategies/batch-jobs/order/export.ts | 329 - .../src/strategies/batch-jobs/order/index.ts | 153 - .../batch-jobs/price-list/import.ts | 529 - .../strategies/batch-jobs/price-list/types.ts | 89 - .../strategies/batch-jobs/product/export.ts | 754 - .../strategies/batch-jobs/product/import.ts | 935 - .../product/types/columns-definition.ts | 834 - .../batch-jobs/product/types/index.ts | 158 - .../strategies/batch-jobs/product/utils.ts | 66 - .../medusa/src/strategies/cart-completion.ts | 503 - .../medusa/src/strategies/price-selection.ts | 347 - .../medusa/src/strategies/tax-calculation.ts | 118 - packages/medusa/src/subscribers/batch-job.ts | 2 + packages/medusa/src/subscribers/cart.ts | 3 + packages/medusa/src/subscribers/order.js | 3 + packages/medusa/src/subscribers/product.ts | 7 +- .../medusa/src/subscribers/search-indexing.ts | 3 + packages/medusa/src/types/auth.ts | 8 - packages/medusa/src/types/batch-job.ts | 2 + packages/medusa/src/types/cart.ts | 89 - packages/medusa/src/types/claim.ts | 84 - packages/medusa/src/types/currency.ts | 3 - packages/medusa/src/types/customer-groups.ts | 66 - packages/medusa/src/types/customers.ts | 84 - packages/medusa/src/types/discount.ts | 221 - packages/medusa/src/types/draft-orders.ts | 40 - .../medusa/src/types/fulfillment-provider.ts | 8 - packages/medusa/src/types/fulfillment.ts | 42 - packages/medusa/src/types/gift-card.ts | 27 - packages/medusa/src/types/global.ts | 3 +- packages/medusa/src/types/invites.ts | 5 - .../medusa/src/types/line-item-adjustment.ts | 27 - packages/medusa/src/types/line-item.ts | 18 - packages/medusa/src/types/note.ts | 26 - packages/medusa/src/types/oauth.ts | 10 - packages/medusa/src/types/order-edit.ts | 67 - packages/medusa/src/types/orders.ts | 400 - .../medusa/src/types/payment-collection.ts | 55 - packages/medusa/src/types/payment.ts | 37 - packages/medusa/src/types/price-list.ts | 228 - packages/medusa/src/types/price-selection.ts | 41 - packages/medusa/src/types/pricing.ts | 181 - packages/medusa/src/types/product-category.ts | 72 - .../medusa/src/types/product-collection.ts | 11 - packages/medusa/src/types/product-tax-rate.ts | 11 - packages/medusa/src/types/product-variant.ts | 223 - packages/medusa/src/types/product.ts | 340 - .../medusa/src/types/publishable-api-key.ts | 7 - packages/medusa/src/types/region.ts | 26 - packages/medusa/src/types/return-reason.ts | 14 - packages/medusa/src/types/return.ts | 31 - packages/medusa/src/types/routing.ts | 3 +- packages/medusa/src/types/sales-channels.ts | 14 - packages/medusa/src/types/shipping-options.ts | 90 - packages/medusa/src/types/shipping-profile.ts | 15 - .../medusa/src/types/shipping-tax-rate.ts | 11 - packages/medusa/src/types/store.ts | 64 - packages/medusa/src/types/tax-rate.ts | 34 - packages/medusa/src/types/tax-service.ts | 87 - packages/medusa/src/types/token.ts | 3 - packages/medusa/src/types/totals.ts | 75 - packages/medusa/src/types/user.ts | 39 - .../src/utils/__tests__/validator.spec.ts | 40 - packages/medusa/src/utils/index.ts | 2 - .../__tests__/transform-query.spec.ts | 0 .../middlewares/authenticate-customer.ts | 0 .../middlewares/authenticate.ts | 0 .../middlewares/await-middleware.ts | 0 .../middlewares/check-registered-modules.ts | 0 .../middlewares/error-handler.ts | 0 .../middlewares/feature-flag-enabled.ts | 0 .../medusa/src/utils/middlewares/index.ts | 10 + .../middlewares/normalized-query.ts | 0 .../require-customer-authentication.ts | 0 .../middlewares/transform-body.ts | 0 .../middlewares/transform-includes-options.ts | 0 .../middlewares/transform-query.ts | 0 packages/medusa/src/utils/naming-strategy.ts | 17 - .../src/utils/product-category/index.ts | 25 - packages/medusa/src/utils/queries/index.ts | 1 - .../products/get-variants-from-price-list.ts | 33 - .../src/utils/queries/products/index.ts | 3 - .../utils/queries/products/list-products.ts | 235 - .../queries/products/retrieve-product.ts | 28 - packages/modules/file/package.json | 2 +- packages/modules/product/package.json | 2 +- .../modules/region/src/loaders/defaults.ts | 6 +- www/apps/ui/package.json | 2 +- yarn.lock | 17811 ++++------------ 1452 files changed, 4737 insertions(+), 234780 deletions(-) rename packages/medusa/src/controllers/__mocks__/customers.ts => integration-tests/api/src/index.js (100%) delete mode 100644 integration-tests/api/src/services/local-file-service.js delete mode 100644 integration-tests/api/src/services/test-ful.js delete mode 100644 integration-tests/api/src/services/test-not.js delete mode 100644 integration-tests/api/src/services/test-pay.js delete mode 100644 integration-tests/development/.env.development delete mode 100644 integration-tests/development/create-database.js delete mode 100644 integration-tests/development/database/customer.js delete mode 100644 integration-tests/development/database/index.js delete mode 100644 integration-tests/development/database/region.js delete mode 100644 integration-tests/development/database/user.js delete mode 100644 integration-tests/development/dev-require.js delete mode 100644 integration-tests/development/medusa-config.js delete mode 100644 integration-tests/development/server.js delete mode 100644 integration-tests/development/src/services/local-file-service.js delete mode 100644 integration-tests/development/src/services/test-ful.js delete mode 100644 integration-tests/development/src/services/test-not.js delete mode 100644 integration-tests/development/src/services/test-pay.js delete mode 100644 integration-tests/development/use-db-development.js delete mode 100644 integration-tests/factories/simple-discount-condition-factory.ts delete mode 100644 integration-tests/modules/__tests__/workflow-engine/api.ts delete mode 100644 integration-tests/plugins/.babelrc.js delete mode 100644 integration-tests/plugins/.gitignore delete mode 100644 integration-tests/plugins/__tests__/cart/store/ff-medusa-v2.ts delete mode 100644 integration-tests/plugins/__tests__/cart/store/index.ts delete mode 100644 integration-tests/plugins/__tests__/inventory/cart/cart.js delete mode 100644 integration-tests/plugins/__tests__/inventory/inventory-items/ff-many-to-many.js delete mode 100644 integration-tests/plugins/__tests__/inventory/inventory-items/index.js delete mode 100644 integration-tests/plugins/__tests__/inventory/order/draft-order.js delete mode 100644 integration-tests/plugins/__tests__/inventory/order/order.js delete mode 100644 integration-tests/plugins/__tests__/inventory/products/create-variant.js delete mode 100644 integration-tests/plugins/__tests__/inventory/products/delete-variant.js delete mode 100644 integration-tests/plugins/__tests__/inventory/products/get-product.js delete mode 100644 integration-tests/plugins/__tests__/inventory/products/get-variant.js delete mode 100644 integration-tests/plugins/__tests__/inventory/products/list-products.js delete mode 100644 integration-tests/plugins/__tests__/inventory/products/list-variants.js delete mode 100644 integration-tests/plugins/__tests__/inventory/reservation-items/index.js delete mode 100644 integration-tests/plugins/__tests__/inventory/service.js delete mode 100644 integration-tests/plugins/__tests__/inventory/variant-inventory-service.js delete mode 100644 integration-tests/plugins/__tests__/stock-location/list-stock-locations.spec.ts delete mode 100644 integration-tests/plugins/__tests__/stock-location/service/delete-sales-channels.js delete mode 100644 integration-tests/plugins/__tests__/stock-location/service/delete-stock-location.js delete mode 100644 integration-tests/plugins/__tests__/stock-location/service/sales-channels.js delete mode 100644 integration-tests/plugins/__tests__/stock-location/service/service.js delete mode 100644 integration-tests/plugins/__tests__/workflows/inventory/create-inventory-items.ts delete mode 100644 integration-tests/plugins/__tests__/workflows/product/create-product.ts delete mode 100644 integration-tests/plugins/__tests__/workflows/product/update-product.ts delete mode 100644 integration-tests/plugins/helpers/call-helpers.js delete mode 100644 integration-tests/plugins/jest.config.js delete mode 100644 integration-tests/plugins/medusa-config.js delete mode 100644 integration-tests/plugins/package.json delete mode 100644 integration-tests/plugins/src/services/local-file-service.js delete mode 100644 integration-tests/plugins/src/services/test-ful.js delete mode 100644 integration-tests/plugins/src/services/test-not.js delete mode 100644 integration-tests/plugins/src/services/test-pay.js delete mode 100644 integration-tests/repositories/__tests__/product-categories/queries.ts delete mode 100644 integration-tests/repositories/jest.config.js delete mode 100644 integration-tests/repositories/medusa-config.js delete mode 100644 integration-tests/repositories/package.json create mode 100644 packages/generated/client-types/src/lib/models/AdminPostCampaignsReq.ts create mode 100644 packages/generated/client-types/src/lib/models/ApplicationMethod.ts create mode 100644 packages/generated/client-types/src/lib/models/ApplicationMethodsMethodPostReq.ts create mode 100644 packages/generated/client-types/src/lib/models/Campaign.ts create mode 100644 packages/generated/client-types/src/lib/models/CampaignBudget.ts create mode 100644 packages/generated/client-types/src/lib/models/CreateApplicationMethod.ts create mode 100644 packages/generated/client-types/src/lib/models/CreateCampaign.ts create mode 100644 packages/generated/client-types/src/lib/models/CreateCampaignBudget.ts create mode 100644 packages/generated/client-types/src/lib/models/CreateDefaultTaxRate.ts create mode 100644 packages/generated/client-types/src/lib/models/CreateProductType.ts create mode 100644 packages/generated/client-types/src/lib/models/StockLocationAddress.ts create mode 100644 packages/generated/client-types/src/lib/models/StorePostPaymentCollectionsPaymentSessionReq.ts delete mode 100644 packages/medusa-js/.gitignore delete mode 100644 packages/medusa-js/CHANGELOG.md delete mode 100644 packages/medusa-js/README.md delete mode 100644 packages/medusa-js/jest.config.js delete mode 100644 packages/medusa-js/package.json delete mode 100644 packages/medusa-js/src/error.ts delete mode 100644 packages/medusa-js/src/index.ts delete mode 100644 packages/medusa-js/src/jwt-token-manager.ts delete mode 100644 packages/medusa-js/src/key-manager.ts delete mode 100644 packages/medusa-js/src/request.ts delete mode 100644 packages/medusa-js/src/resources/addresses.ts delete mode 100644 packages/medusa-js/src/resources/admin/auth.ts delete mode 100644 packages/medusa-js/src/resources/admin/batch-jobs.ts delete mode 100644 packages/medusa-js/src/resources/admin/collections.ts delete mode 100644 packages/medusa-js/src/resources/admin/currencies.ts delete mode 100644 packages/medusa-js/src/resources/admin/custom.ts delete mode 100644 packages/medusa-js/src/resources/admin/customer-groups.ts delete mode 100644 packages/medusa-js/src/resources/admin/customers.ts delete mode 100644 packages/medusa-js/src/resources/admin/discounts.ts delete mode 100644 packages/medusa-js/src/resources/admin/draft-orders.ts delete mode 100644 packages/medusa-js/src/resources/admin/gift-cards.ts delete mode 100644 packages/medusa-js/src/resources/admin/index.ts delete mode 100644 packages/medusa-js/src/resources/admin/inventory-item.ts delete mode 100644 packages/medusa-js/src/resources/admin/invites.ts delete mode 100644 packages/medusa-js/src/resources/admin/notes.ts delete mode 100644 packages/medusa-js/src/resources/admin/notifications.ts delete mode 100644 packages/medusa-js/src/resources/admin/order-edits.ts delete mode 100644 packages/medusa-js/src/resources/admin/orders.ts delete mode 100644 packages/medusa-js/src/resources/admin/payment-collections.ts delete mode 100644 packages/medusa-js/src/resources/admin/payments.ts delete mode 100644 packages/medusa-js/src/resources/admin/price-lists.ts delete mode 100644 packages/medusa-js/src/resources/admin/product-categories.ts delete mode 100644 packages/medusa-js/src/resources/admin/product-tags.ts delete mode 100644 packages/medusa-js/src/resources/admin/product-types.ts delete mode 100644 packages/medusa-js/src/resources/admin/products.ts delete mode 100644 packages/medusa-js/src/resources/admin/publishable-api-keys.ts delete mode 100644 packages/medusa-js/src/resources/admin/regions.ts delete mode 100644 packages/medusa-js/src/resources/admin/reservations.ts delete mode 100644 packages/medusa-js/src/resources/admin/return-reasons.ts delete mode 100644 packages/medusa-js/src/resources/admin/returns.ts delete mode 100644 packages/medusa-js/src/resources/admin/sales-channels.ts delete mode 100644 packages/medusa-js/src/resources/admin/shipping-options.ts delete mode 100644 packages/medusa-js/src/resources/admin/shipping-profiles.ts delete mode 100644 packages/medusa-js/src/resources/admin/stock-locations.ts delete mode 100644 packages/medusa-js/src/resources/admin/store.ts delete mode 100644 packages/medusa-js/src/resources/admin/swaps.ts delete mode 100644 packages/medusa-js/src/resources/admin/tax-rates.ts delete mode 100644 packages/medusa-js/src/resources/admin/uploads.ts delete mode 100644 packages/medusa-js/src/resources/admin/users.ts delete mode 100644 packages/medusa-js/src/resources/admin/variants.ts delete mode 100644 packages/medusa-js/src/resources/auth.ts delete mode 100644 packages/medusa-js/src/resources/base.ts delete mode 100644 packages/medusa-js/src/resources/carts.ts delete mode 100644 packages/medusa-js/src/resources/collections.ts delete mode 100644 packages/medusa-js/src/resources/customers.ts delete mode 100644 packages/medusa-js/src/resources/gift-cards.ts delete mode 100644 packages/medusa-js/src/resources/index.ts delete mode 100644 packages/medusa-js/src/resources/line-items.ts delete mode 100644 packages/medusa-js/src/resources/order-edits.ts delete mode 100644 packages/medusa-js/src/resources/orders.ts delete mode 100644 packages/medusa-js/src/resources/payment-collections.ts delete mode 100644 packages/medusa-js/src/resources/payment-methods.ts delete mode 100644 packages/medusa-js/src/resources/product-categories.ts delete mode 100644 packages/medusa-js/src/resources/product-tags.ts delete mode 100644 packages/medusa-js/src/resources/product-types.ts delete mode 100644 packages/medusa-js/src/resources/product-variants.ts delete mode 100644 packages/medusa-js/src/resources/products.ts delete mode 100644 packages/medusa-js/src/resources/regions.ts delete mode 100644 packages/medusa-js/src/resources/return-reasons.ts delete mode 100644 packages/medusa-js/src/resources/returns.ts delete mode 100644 packages/medusa-js/src/resources/shipping-options.ts delete mode 100644 packages/medusa-js/src/resources/swaps.ts delete mode 100644 packages/medusa-js/src/test/utils/utils.test.ts delete mode 100644 packages/medusa-js/src/typings.ts delete mode 100644 packages/medusa-js/src/utils.ts delete mode 100644 packages/medusa-js/tsconfig.json delete mode 100644 packages/medusa-js/tsconfig.spec.json delete mode 100644 packages/medusa-js/tsup.config.ts delete mode 100644 packages/medusa-react/.github/workflows/main.yml delete mode 100644 packages/medusa-react/.github/workflows/size.yml delete mode 100644 packages/medusa-react/.gitignore delete mode 100644 packages/medusa-react/.storybook/main.js delete mode 100644 packages/medusa-react/.storybook/medusa-context.js delete mode 100644 packages/medusa-react/.storybook/preview.js delete mode 100644 packages/medusa-react/CHANGELOG.md delete mode 100644 packages/medusa-react/LICENSE delete mode 100644 packages/medusa-react/README.md delete mode 100644 packages/medusa-react/jest.config.js delete mode 100644 packages/medusa-react/jest.setup.js delete mode 100644 packages/medusa-react/mocks/data/fixtures.json delete mode 100644 packages/medusa-react/mocks/data/index.ts delete mode 100644 packages/medusa-react/mocks/handlers/admin.ts delete mode 100644 packages/medusa-react/mocks/handlers/index.ts delete mode 100644 packages/medusa-react/mocks/handlers/store.ts delete mode 100644 packages/medusa-react/mocks/server.ts delete mode 100644 packages/medusa-react/package.json delete mode 100644 packages/medusa-react/public/mockServiceWorker.js delete mode 100644 packages/medusa-react/src/contexts/cart.tsx delete mode 100644 packages/medusa-react/src/contexts/index.ts delete mode 100644 packages/medusa-react/src/contexts/medusa.tsx delete mode 100644 packages/medusa-react/src/contexts/session-cart.tsx delete mode 100644 packages/medusa-react/src/helpers/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/auth/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/auth/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/auth/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/batch-jobs/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/batch-jobs/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/batch-jobs/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/claims/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/claims/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/collections/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/collections/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/collections/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/currencies/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/currencies/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/currencies/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/custom/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/custom/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/custom/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/customer-groups/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/customer-groups/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/customer-groups/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/customers/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/customers/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/customers/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/discounts/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/discounts/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/discounts/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/draft-orders/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/draft-orders/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/draft-orders/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/gift-cards/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/gift-cards/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/gift-cards/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/inventory-item/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/inventory-item/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/inventory-item/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/invites/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/invites/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/invites/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/notes/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/notes/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/notes/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/notifications/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/notifications/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/notifications/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/order-edits/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/order-edits/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/order-edits/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/orders/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/orders/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/orders/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/payment-collections/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/payment-collections/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/payment-collections/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/payments/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/payments/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/payments/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/price-lists/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/price-lists/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/price-lists/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/product-categories/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/product-categories/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/product-categories/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/product-tags/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/product-tags/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/product-types/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/product-types/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/products/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/products/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/products/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/publishable-api-keys/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/publishable-api-keys/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/publishable-api-keys/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/regions/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/regions/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/regions/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/reservations/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/reservations/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/reservations/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/return-reasons/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/return-reasons/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/return-reasons/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/returns/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/returns/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/returns/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/sales-channels/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/sales-channels/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/sales-channels/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/shipping-options/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/shipping-options/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/shipping-options/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/shipping-profiles/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/shipping-profiles/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/shipping-profiles/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/stock-locations/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/stock-locations/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/stock-locations/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/store/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/store/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/store/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/swaps/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/swaps/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/swaps/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/tax-rates/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/tax-rates/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/tax-rates/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/uploads/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/uploads/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/users/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/users/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/admin/users/queries.ts delete mode 100644 packages/medusa-react/src/hooks/admin/variants/index.ts delete mode 100644 packages/medusa-react/src/hooks/admin/variants/queries.ts delete mode 100644 packages/medusa-react/src/hooks/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/carts/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/carts/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/store/carts/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/collections/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/collections/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/customers/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/customers/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/store/customers/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/gift-cards/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/gift-cards/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/line-items/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/line-items/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/store/order-edits/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/order-edits/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/store/order-edits/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/orders/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/orders/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/store/orders/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/payment-collections/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/payment-collections/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/store/payment-collections/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/product-categories/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/product-categories/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/product-tags/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/product-tags/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/product-types/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/product-types/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/products/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/products/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/regions/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/regions/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/return-reasons/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/return-reasons/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/returns/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/returns/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/store/shipping-options/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/shipping-options/queries.ts delete mode 100644 packages/medusa-react/src/hooks/store/swaps/index.ts delete mode 100644 packages/medusa-react/src/hooks/store/swaps/mutations.ts delete mode 100644 packages/medusa-react/src/hooks/store/swaps/queries.ts delete mode 100644 packages/medusa-react/src/hooks/utils/buildOptions.ts delete mode 100644 packages/medusa-react/src/hooks/utils/index.ts delete mode 100644 packages/medusa-react/src/hooks/utils/queryKeysFactory.ts delete mode 100644 packages/medusa-react/src/hooks/utils/useLocalStorage.ts delete mode 100644 packages/medusa-react/src/index.ts delete mode 100644 packages/medusa-react/src/types.ts delete mode 100644 packages/medusa-react/src/utils/index.ts delete mode 100644 packages/medusa-react/stories/Carts.stories.tsx delete mode 100644 packages/medusa-react/stories/Collections.stories.tsx delete mode 100644 packages/medusa-react/stories/Customers.stories.tsx delete mode 100644 packages/medusa-react/stories/Orders.stories.tsx delete mode 100644 packages/medusa-react/stories/Products.stories.tsx delete mode 100644 packages/medusa-react/stories/Regions.stories.tsx delete mode 100644 packages/medusa-react/stories/ReturnReasons.stories.tsx delete mode 100644 packages/medusa-react/stories/ShippingOptions.stories.tsx delete mode 100644 packages/medusa-react/stories/Swaps.stories.tsx delete mode 100644 packages/medusa-react/stories/components/Layout.tsx delete mode 100644 packages/medusa-react/test/cart-context/cart.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/auth/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/auth/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/batch-jobs/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/batch-jobs/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/claims/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/collections/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/collections/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/currencies/mutation.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/currencies/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/customer-groups/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/customer-groups/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/customers/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/customers/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/discounts/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/discounts/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/draft-orders/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/draft-orders/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/gift-cards/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/gift-cards/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/inventory-items/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/inventory-items/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/invites/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/invites/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/notes/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/notes/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/notifications/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/notifications/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/order-edits/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/order-edits/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/orders/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/orders/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/payment-collections/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/payment-collections/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/payments/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/payments/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/price-lists/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/price-lists/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/product-categories/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/product-categories/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/products/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/products/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/publishable-api-keys/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/publishable-api-keys/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/regions/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/regions/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/reservations/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/reservations/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/return-reasons/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/return-reasons/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/returns/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/returns/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/sales-channels/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/sales-channels/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/shipping-options/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/shipping-options/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/shipping-profiles/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/shipping-profiles/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/stock-location/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/stock-location/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/store/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/store/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/swaps/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/swaps/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/uploads/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/users/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/users/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/variants/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/admin/variants/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/carts/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/carts/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/collections/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/customers/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/customers/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/gift_cards/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/line-items/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/order-edits/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/order-edits/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/orders/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/orders/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/payment-collections/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/payment-collections/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/product-tags/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/products/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/regions/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/return-reasons/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/returns/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/shipping-options/queries.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/swaps/mutations.test.ts delete mode 100644 packages/medusa-react/test/hooks/store/swaps/queries.test.ts delete mode 100644 packages/medusa-react/test/session-cart-context/session-cart.test.ts delete mode 100644 packages/medusa-react/test/utils.tsx delete mode 100644 packages/medusa-react/test/utils/utils.test.ts delete mode 100644 packages/medusa-react/tsconfig.json delete mode 100644 packages/medusa-react/tsup.config.ts delete mode 100644 packages/medusa/src/api/index.js delete mode 100644 packages/medusa/src/api/middlewares/batch-job/can-access-batch-job.ts delete mode 100644 packages/medusa/src/api/middlewares/batch-job/get-requested-batch-job.ts delete mode 100644 packages/medusa/src/api/middlewares/discount/does-condition-belong-to-discount.ts delete mode 100644 packages/medusa/src/api/middlewares/index.ts delete mode 100644 packages/medusa/src/api/middlewares/publishable-api-key/extend-request-params.ts delete mode 100644 packages/medusa/src/api/middlewares/publishable-api-key/validate-product-sales-channel-association.ts delete mode 100644 packages/medusa/src/api/middlewares/publishable-api-key/validate-sales-channel-param.ts delete mode 100644 packages/medusa/src/api/middlewares/publishable-api-key/validate-variant-sales-channel-association.ts delete mode 100644 packages/medusa/src/api/middlewares/validators/product-existence.ts delete mode 100644 packages/medusa/src/api/middlewares/validators/sales-channel-existence.ts delete mode 100644 packages/medusa/src/api/middlewares/with-default-sales-channel.ts delete mode 100644 packages/medusa/src/api/routes/admin/analytics-configs/create-analytics-config.ts delete mode 100644 packages/medusa/src/api/routes/admin/analytics-configs/delete-analytics-config.ts delete mode 100644 packages/medusa/src/api/routes/admin/analytics-configs/get-analytics-config.ts delete mode 100644 packages/medusa/src/api/routes/admin/analytics-configs/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/analytics-configs/update-analytics-config.ts delete mode 100644 packages/medusa/src/api/routes/admin/apps/authorize-app.ts delete mode 100644 packages/medusa/src/api/routes/admin/apps/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/apps/list.ts delete mode 100644 packages/medusa/src/api/routes/admin/auth/create-session.ts delete mode 100644 packages/medusa/src/api/routes/admin/auth/delete-session.ts delete mode 100644 packages/medusa/src/api/routes/admin/auth/get-session.ts delete mode 100644 packages/medusa/src/api/routes/admin/auth/get-token.ts delete mode 100644 packages/medusa/src/api/routes/admin/auth/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/batch/cancel-batch-job.ts delete mode 100644 packages/medusa/src/api/routes/admin/batch/confirm-batch-job.ts delete mode 100644 packages/medusa/src/api/routes/admin/batch/create-batch-job.ts delete mode 100644 packages/medusa/src/api/routes/admin/batch/get-batch-job.ts delete mode 100644 packages/medusa/src/api/routes/admin/batch/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/batch/list-batch-jobs.ts delete mode 100644 packages/medusa/src/api/routes/admin/collections/__tests__/add-products.js delete mode 100644 packages/medusa/src/api/routes/admin/collections/__tests__/create-collection.js delete mode 100644 packages/medusa/src/api/routes/admin/collections/__tests__/delete-collection.js delete mode 100644 packages/medusa/src/api/routes/admin/collections/__tests__/get-collection.js delete mode 100644 packages/medusa/src/api/routes/admin/collections/__tests__/list-collections.js delete mode 100644 packages/medusa/src/api/routes/admin/collections/__tests__/remove-products.js delete mode 100644 packages/medusa/src/api/routes/admin/collections/__tests__/update-collection.js delete mode 100644 packages/medusa/src/api/routes/admin/collections/add-products.ts delete mode 100644 packages/medusa/src/api/routes/admin/collections/create-collection.ts delete mode 100644 packages/medusa/src/api/routes/admin/collections/delete-collection.ts delete mode 100644 packages/medusa/src/api/routes/admin/collections/get-collection.ts delete mode 100644 packages/medusa/src/api/routes/admin/collections/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/collections/list-collections.ts delete mode 100644 packages/medusa/src/api/routes/admin/collections/remove-products.ts delete mode 100644 packages/medusa/src/api/routes/admin/collections/update-collection.ts delete mode 100644 packages/medusa/src/api/routes/admin/currencies/__tests__/list-currencies.ts delete mode 100644 packages/medusa/src/api/routes/admin/currencies/__tests__/update-currency.ts delete mode 100644 packages/medusa/src/api/routes/admin/currencies/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/currencies/list-currencies.ts delete mode 100644 packages/medusa/src/api/routes/admin/currencies/update-currency.ts delete mode 100644 packages/medusa/src/api/routes/admin/customer-groups/__tests__/create-customer-group.ts delete mode 100644 packages/medusa/src/api/routes/admin/customer-groups/__tests__/get-customer-group.ts delete mode 100644 packages/medusa/src/api/routes/admin/customer-groups/add-customers-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/customer-groups/create-customer-group.ts delete mode 100644 packages/medusa/src/api/routes/admin/customer-groups/delete-customer-group.ts delete mode 100644 packages/medusa/src/api/routes/admin/customer-groups/delete-customers-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/customer-groups/get-customer-group-customers.ts delete mode 100644 packages/medusa/src/api/routes/admin/customer-groups/get-customer-group.ts delete mode 100644 packages/medusa/src/api/routes/admin/customer-groups/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/customer-groups/list-customer-groups.ts delete mode 100644 packages/medusa/src/api/routes/admin/customer-groups/update-customer-group.ts delete mode 100644 packages/medusa/src/api/routes/admin/customers/create-customer.ts delete mode 100644 packages/medusa/src/api/routes/admin/customers/get-customer.ts delete mode 100644 packages/medusa/src/api/routes/admin/customers/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/customers/list-customers.ts delete mode 100644 packages/medusa/src/api/routes/admin/customers/update-customer.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/__tests__/add-region.js delete mode 100644 packages/medusa/src/api/routes/admin/discounts/__tests__/create-discount.js delete mode 100644 packages/medusa/src/api/routes/admin/discounts/__tests__/delete-discount.js delete mode 100644 packages/medusa/src/api/routes/admin/discounts/__tests__/get-discount.js delete mode 100644 packages/medusa/src/api/routes/admin/discounts/__tests__/list-discounts.js delete mode 100644 packages/medusa/src/api/routes/admin/discounts/__tests__/remove-region.js delete mode 100644 packages/medusa/src/api/routes/admin/discounts/__tests__/update-discount.js delete mode 100644 packages/medusa/src/api/routes/admin/discounts/add-region.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/add-resources-to-condition-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/create-condition.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/create-discount.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/create-dynamic-code.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/delete-condition.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/delete-discount.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/delete-dynamic-code.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/delete-resources-from-condition-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/get-condition.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/get-discount-by-code.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/get-discount.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/list-discounts.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/remove-region.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/update-condition.ts delete mode 100644 packages/medusa/src/api/routes/admin/discounts/update-discount.ts delete mode 100644 packages/medusa/src/api/routes/admin/draft-orders/create-draft-order.ts delete mode 100644 packages/medusa/src/api/routes/admin/draft-orders/create-line-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/draft-orders/delete-draft-order.ts delete mode 100644 packages/medusa/src/api/routes/admin/draft-orders/delete-line-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/draft-orders/get-draft-order.ts delete mode 100644 packages/medusa/src/api/routes/admin/draft-orders/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/draft-orders/list-draft-orders.ts delete mode 100644 packages/medusa/src/api/routes/admin/draft-orders/register-payment.ts delete mode 100644 packages/medusa/src/api/routes/admin/draft-orders/update-draft-order.ts delete mode 100644 packages/medusa/src/api/routes/admin/draft-orders/update-line-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/gift-cards/create-gift-card.ts delete mode 100644 packages/medusa/src/api/routes/admin/gift-cards/delete-gift-card.ts delete mode 100644 packages/medusa/src/api/routes/admin/gift-cards/get-gift-card.ts delete mode 100644 packages/medusa/src/api/routes/admin/gift-cards/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/gift-cards/list-gift-cards.ts delete mode 100644 packages/medusa/src/api/routes/admin/gift-cards/update-gift-card.ts delete mode 100644 packages/medusa/src/api/routes/admin/index.js delete mode 100644 packages/medusa/src/api/routes/admin/inventory-items/create-inventory-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/inventory-items/create-location-level.ts delete mode 100644 packages/medusa/src/api/routes/admin/inventory-items/delete-inventory-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/inventory-items/delete-location-level.ts delete mode 100644 packages/medusa/src/api/routes/admin/inventory-items/get-inventory-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/inventory-items/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/inventory-items/list-inventory-items.ts delete mode 100644 packages/medusa/src/api/routes/admin/inventory-items/list-location-levels.ts delete mode 100644 packages/medusa/src/api/routes/admin/inventory-items/update-inventory-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/inventory-items/update-location-level.ts delete mode 100644 packages/medusa/src/api/routes/admin/inventory-items/utils/join-levels.ts delete mode 100644 packages/medusa/src/api/routes/admin/inventory-items/utils/join-variants.ts delete mode 100644 packages/medusa/src/api/routes/admin/invites/__tests__/accept-invite.js delete mode 100644 packages/medusa/src/api/routes/admin/invites/__tests__/create-invite.js delete mode 100644 packages/medusa/src/api/routes/admin/invites/__tests__/resend-invite.js delete mode 100644 packages/medusa/src/api/routes/admin/invites/accept-invite.ts delete mode 100644 packages/medusa/src/api/routes/admin/invites/create-invite.ts delete mode 100644 packages/medusa/src/api/routes/admin/invites/delete-invite.ts delete mode 100644 packages/medusa/src/api/routes/admin/invites/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/invites/list-invites.ts delete mode 100644 packages/medusa/src/api/routes/admin/invites/resend-invite.ts delete mode 100644 packages/medusa/src/api/routes/admin/notes/create-note.ts delete mode 100644 packages/medusa/src/api/routes/admin/notes/delete-note.ts delete mode 100644 packages/medusa/src/api/routes/admin/notes/get-note.ts delete mode 100644 packages/medusa/src/api/routes/admin/notes/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/notes/list-notes.ts delete mode 100644 packages/medusa/src/api/routes/admin/notes/update-note.ts delete mode 100644 packages/medusa/src/api/routes/admin/notifications/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/notifications/list-notifications.ts delete mode 100644 packages/medusa/src/api/routes/admin/notifications/resend-notification.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/__tests__/cancel-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/__tests__/confirm-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/__tests__/create-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/__tests__/delete-line-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/__tests__/delete-order-edit-item-change.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/__tests__/delete-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/__tests__/get-order.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/__tests__/list-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/__tests__/request-confirmation.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/__tests__/update-order-edit-line-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/add-line-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/cancel-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/confirm-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/create-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/delete-line-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/delete-order-edit-item-change.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/delete-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/get-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/list-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/request-confirmation.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/update-order-edit-line-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/order-edits/update-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/archive-order.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/cancel-claim.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/cancel-fulfillment-claim.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/cancel-fulfillment-swap.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/cancel-fulfillment.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/cancel-order.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/cancel-swap.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/capture-payment.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/create-claim.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/create-fulfillment.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/get-order.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/return-order.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/__tests__/update-order.js delete mode 100644 packages/medusa/src/api/routes/admin/orders/add-shipping-method.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/archive-order.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/cancel-claim.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-claim.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-swap.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/cancel-fulfillment.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/cancel-order.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/cancel-swap.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/capture-payment.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/complete-order.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/create-claim-shipment.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/create-claim.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/create-reservation-for-line-item.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/create-shipment.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/create-swap.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/fulfill-claim.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/fulfill-swap.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/get-order.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/get-reservations.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/list-orders.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/process-swap-payment.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/refund-payment.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/request-return.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/update-claim.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/update-order.ts delete mode 100644 packages/medusa/src/api/routes/admin/payment-collections/delete-payment-collection.ts delete mode 100644 packages/medusa/src/api/routes/admin/payment-collections/get-payment-collection.ts delete mode 100644 packages/medusa/src/api/routes/admin/payment-collections/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/payment-collections/mark-authorized-payment-collection.ts delete mode 100644 packages/medusa/src/api/routes/admin/payment-collections/update-payment-collection.ts delete mode 100644 packages/medusa/src/api/routes/admin/payments/capture-payment.ts delete mode 100644 packages/medusa/src/api/routes/admin/payments/get-payment.ts delete mode 100644 packages/medusa/src/api/routes/admin/payments/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/payments/refund-payment.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/__tests__/add-prices-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/__tests__/create-price-list.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/__tests__/delete-price-list.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/__tests__/delete-prices-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/__tests__/get-price-list.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/__tests__/list-price-lists.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/__tests__/update-price-list.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/add-prices-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/create-price-list.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/delete-price-list.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/delete-prices-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/delete-product-prices.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/delete-products-prices-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/delete-variant-prices.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/get-price-list.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/list-price-list-products.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/list-price-lists.ts delete mode 100644 packages/medusa/src/api/routes/admin/price-lists/update-price-list.ts delete mode 100644 packages/medusa/src/api/routes/admin/product-categories/add-products-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/product-categories/create-product-category.ts delete mode 100644 packages/medusa/src/api/routes/admin/product-categories/delete-product-category.ts delete mode 100644 packages/medusa/src/api/routes/admin/product-categories/delete-products-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/product-categories/get-product-category.ts delete mode 100644 packages/medusa/src/api/routes/admin/product-categories/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/product-categories/list-product-categories.ts delete mode 100644 packages/medusa/src/api/routes/admin/product-categories/update-product-category.ts delete mode 100644 packages/medusa/src/api/routes/admin/product-tags/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/product-tags/list-product-tags.ts delete mode 100644 packages/medusa/src/api/routes/admin/product-types/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/product-types/list-product-types.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/__tests__/add-option.js delete mode 100644 packages/medusa/src/api/routes/admin/products/__tests__/create-product.js delete mode 100644 packages/medusa/src/api/routes/admin/products/__tests__/create-variant.js delete mode 100644 packages/medusa/src/api/routes/admin/products/__tests__/delete-option.js delete mode 100644 packages/medusa/src/api/routes/admin/products/__tests__/delete-product.js delete mode 100644 packages/medusa/src/api/routes/admin/products/__tests__/delete-variant.js delete mode 100644 packages/medusa/src/api/routes/admin/products/__tests__/get-product.js delete mode 100644 packages/medusa/src/api/routes/admin/products/__tests__/list-products.js delete mode 100644 packages/medusa/src/api/routes/admin/products/__tests__/list-variants.js delete mode 100644 packages/medusa/src/api/routes/admin/products/__tests__/update-option.js delete mode 100644 packages/medusa/src/api/routes/admin/products/__tests__/update-product.js delete mode 100644 packages/medusa/src/api/routes/admin/products/__tests__/update-variant.js delete mode 100644 packages/medusa/src/api/routes/admin/products/add-option.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/create-product.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/create-variant.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/delete-option.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/delete-product.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/delete-variant.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/get-product.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/list-products.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/list-tag-usage-count.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/list-types.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/list-variants.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/set-metadata.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/transaction/create-product-variant.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/update-option.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/update-product.ts delete mode 100644 packages/medusa/src/api/routes/admin/products/update-variant.ts delete mode 100644 packages/medusa/src/api/routes/admin/publishable-api-keys/add-channels-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/publishable-api-keys/create-publishable-api-key.ts delete mode 100644 packages/medusa/src/api/routes/admin/publishable-api-keys/delete-channels-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/publishable-api-keys/delete-publishable-api-key.ts delete mode 100644 packages/medusa/src/api/routes/admin/publishable-api-keys/get-publishable-api-key.ts delete mode 100644 packages/medusa/src/api/routes/admin/publishable-api-keys/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/publishable-api-keys/list-publishable-api-key-sales-channels.ts delete mode 100644 packages/medusa/src/api/routes/admin/publishable-api-keys/list-publishable-api-keys.ts delete mode 100644 packages/medusa/src/api/routes/admin/publishable-api-keys/revoke-publishable-api-key.ts delete mode 100644 packages/medusa/src/api/routes/admin/publishable-api-keys/update-publishable-api-key.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/__tests__/add-country.js delete mode 100644 packages/medusa/src/api/routes/admin/regions/__tests__/add-fulfillment-provider.js delete mode 100644 packages/medusa/src/api/routes/admin/regions/__tests__/add-payment-provider.js delete mode 100644 packages/medusa/src/api/routes/admin/regions/__tests__/create-region.js delete mode 100644 packages/medusa/src/api/routes/admin/regions/__tests__/delete-region.js delete mode 100644 packages/medusa/src/api/routes/admin/regions/__tests__/get-region.js delete mode 100644 packages/medusa/src/api/routes/admin/regions/__tests__/list-regions.js delete mode 100644 packages/medusa/src/api/routes/admin/regions/__tests__/remove-country.js delete mode 100644 packages/medusa/src/api/routes/admin/regions/__tests__/remove-fulfillment-provider.js delete mode 100644 packages/medusa/src/api/routes/admin/regions/__tests__/remove-payment-provider.js delete mode 100644 packages/medusa/src/api/routes/admin/regions/__tests__/update-region.js delete mode 100644 packages/medusa/src/api/routes/admin/regions/add-country.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/add-fulfillment-provider.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/add-payment-provider.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/create-region.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/delete-region.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/get-fulfillment-options.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/get-region.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/list-regions.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/remove-country.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/remove-fulfillment-provider.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/remove-payment-provider.ts delete mode 100644 packages/medusa/src/api/routes/admin/regions/update-region.ts delete mode 100644 packages/medusa/src/api/routes/admin/reservations/create-reservation.ts delete mode 100644 packages/medusa/src/api/routes/admin/reservations/delete-reservation.ts delete mode 100644 packages/medusa/src/api/routes/admin/reservations/get-reservation.ts delete mode 100644 packages/medusa/src/api/routes/admin/reservations/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/reservations/list-reservations.ts delete mode 100644 packages/medusa/src/api/routes/admin/reservations/update-reservation.ts delete mode 100644 packages/medusa/src/api/routes/admin/reservations/utils/join-inventory-items.ts delete mode 100644 packages/medusa/src/api/routes/admin/reservations/utils/join-line-items.ts delete mode 100644 packages/medusa/src/api/routes/admin/reservations/utils/validate-reservation-quantity.ts delete mode 100644 packages/medusa/src/api/routes/admin/return-reasons/create-reason.ts delete mode 100644 packages/medusa/src/api/routes/admin/return-reasons/delete-reason.ts delete mode 100644 packages/medusa/src/api/routes/admin/return-reasons/get-reason.ts delete mode 100644 packages/medusa/src/api/routes/admin/return-reasons/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/return-reasons/list-reasons.ts delete mode 100644 packages/medusa/src/api/routes/admin/return-reasons/update-reason.ts delete mode 100644 packages/medusa/src/api/routes/admin/returns/__tests__/receive-return.js delete mode 100644 packages/medusa/src/api/routes/admin/returns/cancel-return.ts delete mode 100644 packages/medusa/src/api/routes/admin/returns/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/returns/list-returns.ts delete mode 100644 packages/medusa/src/api/routes/admin/returns/receive-return.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/__tests__/add-product-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/__tests__/create-sales-channel.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/__tests__/delete-products-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/__tests__/delete-sales-channel.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/__tests__/get-sales-channel.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/__tests__/list-sales-channels.js delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/__tests__/update-sales-channel.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/add-product-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/associate-stock-location.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/create-sales-channel.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/delete-products-batch.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/delete-sales-channel.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/get-sales-channel.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/list-sales-channels.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/remove-stock-location.ts delete mode 100644 packages/medusa/src/api/routes/admin/sales-channels/update-sales-channel.ts delete mode 100644 packages/medusa/src/api/routes/admin/shipping-options/__tests__/create-shipping-option.js delete mode 100644 packages/medusa/src/api/routes/admin/shipping-options/__tests__/delete-shipping-option.js delete mode 100644 packages/medusa/src/api/routes/admin/shipping-options/__tests__/get-shipping-options.js delete mode 100644 packages/medusa/src/api/routes/admin/shipping-options/__tests__/list-shipping-options.js delete mode 100644 packages/medusa/src/api/routes/admin/shipping-options/__tests__/update-shipping-option.js delete mode 100644 packages/medusa/src/api/routes/admin/shipping-options/create-shipping-option.ts delete mode 100644 packages/medusa/src/api/routes/admin/shipping-options/delete-shipping-option.ts delete mode 100644 packages/medusa/src/api/routes/admin/shipping-options/get-shipping-option.ts delete mode 100644 packages/medusa/src/api/routes/admin/shipping-options/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/shipping-options/list-shipping-options.ts delete mode 100644 packages/medusa/src/api/routes/admin/shipping-options/update-shipping-option.ts delete mode 100644 packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/create-shipping-profile.js delete mode 100644 packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/delete-shipping-profile.js delete mode 100644 packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/get-shipping-profile.js delete mode 100644 packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/list-shipping-profiles.js delete mode 100644 packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/update-shipping-profile.js delete mode 100644 packages/medusa/src/api/routes/admin/shipping-profiles/create-shipping-profile.ts delete mode 100644 packages/medusa/src/api/routes/admin/shipping-profiles/delete-shipping-profile.ts delete mode 100644 packages/medusa/src/api/routes/admin/shipping-profiles/get-shipping-profile.ts delete mode 100644 packages/medusa/src/api/routes/admin/shipping-profiles/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/shipping-profiles/list-shipping-profiles.ts delete mode 100644 packages/medusa/src/api/routes/admin/shipping-profiles/update-shipping-profile.ts delete mode 100644 packages/medusa/src/api/routes/admin/stock-locations/create-stock-location.ts delete mode 100644 packages/medusa/src/api/routes/admin/stock-locations/delete-stock-location.ts delete mode 100644 packages/medusa/src/api/routes/admin/stock-locations/get-stock-location.ts delete mode 100644 packages/medusa/src/api/routes/admin/stock-locations/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/stock-locations/list-stock-locations.ts delete mode 100644 packages/medusa/src/api/routes/admin/stock-locations/update-stock-location.ts delete mode 100644 packages/medusa/src/api/routes/admin/stock-locations/utils/join-sales-channels.ts delete mode 100644 packages/medusa/src/api/routes/admin/store/__tests__/add-currency.js delete mode 100644 packages/medusa/src/api/routes/admin/store/__tests__/get-store.js delete mode 100644 packages/medusa/src/api/routes/admin/store/__tests__/remove-currency.js delete mode 100644 packages/medusa/src/api/routes/admin/store/__tests__/update-store.js delete mode 100644 packages/medusa/src/api/routes/admin/store/add-currency.ts delete mode 100644 packages/medusa/src/api/routes/admin/store/get-store.ts delete mode 100644 packages/medusa/src/api/routes/admin/store/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/store/list-payment-providers.ts delete mode 100644 packages/medusa/src/api/routes/admin/store/list-tax-providers.ts delete mode 100644 packages/medusa/src/api/routes/admin/store/remove-currency.ts delete mode 100644 packages/medusa/src/api/routes/admin/store/update-store.ts delete mode 100644 packages/medusa/src/api/routes/admin/swaps/__tests__/get-swap.js delete mode 100644 packages/medusa/src/api/routes/admin/swaps/__tests__/list-swaps.js delete mode 100644 packages/medusa/src/api/routes/admin/swaps/get-swap.ts delete mode 100644 packages/medusa/src/api/routes/admin/swaps/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/swaps/list-swaps.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/add-to-product-types.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/add-to-products.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/add-to-shipping-options.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/create-tax-rate.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/delete-tax-rate.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/get-tax-rate.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/list-tax-rates.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/remove-from-product-types.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/remove-from-products.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/remove-from-shipping-options.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/update-tax-rate.ts delete mode 100644 packages/medusa/src/api/routes/admin/tax-rates/utils/get-query-config.ts delete mode 100644 packages/medusa/src/api/routes/admin/uploads/create-protected-upload.ts delete mode 100644 packages/medusa/src/api/routes/admin/uploads/create-upload.ts delete mode 100644 packages/medusa/src/api/routes/admin/uploads/delete-upload.ts delete mode 100644 packages/medusa/src/api/routes/admin/uploads/get-download-url.ts delete mode 100644 packages/medusa/src/api/routes/admin/uploads/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/users/__tests__/create-user.js delete mode 100644 packages/medusa/src/api/routes/admin/users/__tests__/delete-user.js delete mode 100644 packages/medusa/src/api/routes/admin/users/__tests__/get-user.js delete mode 100644 packages/medusa/src/api/routes/admin/users/__tests__/list-users.js delete mode 100644 packages/medusa/src/api/routes/admin/users/__tests__/reset-password-token.js delete mode 100644 packages/medusa/src/api/routes/admin/users/__tests__/reset-password.js delete mode 100644 packages/medusa/src/api/routes/admin/users/__tests__/update-user.js delete mode 100644 packages/medusa/src/api/routes/admin/users/create-user.ts delete mode 100644 packages/medusa/src/api/routes/admin/users/delete-user.ts delete mode 100644 packages/medusa/src/api/routes/admin/users/get-user.ts delete mode 100644 packages/medusa/src/api/routes/admin/users/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/users/list-users.ts delete mode 100644 packages/medusa/src/api/routes/admin/users/reset-password-token.ts delete mode 100644 packages/medusa/src/api/routes/admin/users/reset-password.ts delete mode 100644 packages/medusa/src/api/routes/admin/users/update-user.ts delete mode 100644 packages/medusa/src/api/routes/admin/variants/get-inventory.ts delete mode 100644 packages/medusa/src/api/routes/admin/variants/get-variant.ts delete mode 100644 packages/medusa/src/api/routes/admin/variants/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/variants/list-variants.ts delete mode 100644 packages/medusa/src/api/routes/admin/workflows-executions/get-execution.ts delete mode 100644 packages/medusa/src/api/routes/admin/workflows-executions/index.ts delete mode 100644 packages/medusa/src/api/routes/admin/workflows-executions/list-execution.ts delete mode 100644 packages/medusa/src/api/routes/admin/workflows-executions/query-config.ts delete mode 100644 packages/medusa/src/api/routes/admin/workflows-executions/run-workflow.ts delete mode 100644 packages/medusa/src/api/routes/admin/workflows-executions/set-step-failure.ts delete mode 100644 packages/medusa/src/api/routes/admin/workflows-executions/set-step-success.ts delete mode 100644 packages/medusa/src/api/routes/admin/workflows-executions/subscribe.ts delete mode 100644 packages/medusa/src/api/routes/admin/workflows-executions/validators.ts delete mode 100644 packages/medusa/src/api/routes/store/auth/create-session.ts delete mode 100644 packages/medusa/src/api/routes/store/auth/delete-session.ts delete mode 100644 packages/medusa/src/api/routes/store/auth/exists.ts delete mode 100644 packages/medusa/src/api/routes/store/auth/get-session.ts delete mode 100644 packages/medusa/src/api/routes/store/auth/get-token.ts delete mode 100644 packages/medusa/src/api/routes/store/auth/index.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/__tests__/add-shipping-method.js delete mode 100644 packages/medusa/src/api/routes/store/carts/__tests__/complete-cart.js delete mode 100644 packages/medusa/src/api/routes/store/carts/__tests__/create-cart.js delete mode 100644 packages/medusa/src/api/routes/store/carts/__tests__/create-line-item.js delete mode 100644 packages/medusa/src/api/routes/store/carts/__tests__/create-payment-sessions.js delete mode 100644 packages/medusa/src/api/routes/store/carts/__tests__/get-cart.js delete mode 100644 packages/medusa/src/api/routes/store/carts/__tests__/refresh-payment-session.js delete mode 100644 packages/medusa/src/api/routes/store/carts/__tests__/update-cart.js delete mode 100644 packages/medusa/src/api/routes/store/carts/__tests__/update-line-item.js delete mode 100644 packages/medusa/src/api/routes/store/carts/__tests__/update-payment-session.js delete mode 100644 packages/medusa/src/api/routes/store/carts/add-shipping-method.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/calculate-taxes.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/complete-cart.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/create-cart.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/create-line-item/index.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/create-line-item/utils/handler-steps.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/create-payment-sessions.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/delete-discount.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/delete-line-item.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/delete-payment-session.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/get-cart.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/index.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/refresh-payment-session.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/set-payment-session.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/update-cart.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/update-line-item.ts delete mode 100644 packages/medusa/src/api/routes/store/carts/update-payment-session.ts delete mode 100644 packages/medusa/src/api/routes/store/collections/__tests__/get-collection.js delete mode 100644 packages/medusa/src/api/routes/store/collections/__tests__/list-collections.js delete mode 100644 packages/medusa/src/api/routes/store/collections/get-collection.ts delete mode 100644 packages/medusa/src/api/routes/store/collections/index.ts delete mode 100644 packages/medusa/src/api/routes/store/collections/list-collections.ts delete mode 100644 packages/medusa/src/api/routes/store/customers/__tests__/create-customer.js delete mode 100644 packages/medusa/src/api/routes/store/customers/__tests__/reset-password-token.js delete mode 100644 packages/medusa/src/api/routes/store/customers/__tests__/reset-password.js delete mode 100644 packages/medusa/src/api/routes/store/customers/__tests__/update-customer.js delete mode 100644 packages/medusa/src/api/routes/store/customers/create-address.ts delete mode 100644 packages/medusa/src/api/routes/store/customers/create-customer.ts delete mode 100644 packages/medusa/src/api/routes/store/customers/delete-address.ts delete mode 100644 packages/medusa/src/api/routes/store/customers/get-customer.ts delete mode 100644 packages/medusa/src/api/routes/store/customers/get-payment-methods.ts delete mode 100644 packages/medusa/src/api/routes/store/customers/index.ts delete mode 100644 packages/medusa/src/api/routes/store/customers/list-orders.ts delete mode 100644 packages/medusa/src/api/routes/store/customers/reset-password-token.ts delete mode 100644 packages/medusa/src/api/routes/store/customers/reset-password.ts delete mode 100644 packages/medusa/src/api/routes/store/customers/update-address.ts delete mode 100644 packages/medusa/src/api/routes/store/customers/update-customer.ts delete mode 100644 packages/medusa/src/api/routes/store/gift-cards/get-gift-card.ts delete mode 100644 packages/medusa/src/api/routes/store/gift-cards/index.ts delete mode 100644 packages/medusa/src/api/routes/store/index.js delete mode 100644 packages/medusa/src/api/routes/store/order-edits/__tests__/complete-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/store/order-edits/__tests__/decline-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/store/order-edits/__tests__/get-order.ts delete mode 100644 packages/medusa/src/api/routes/store/order-edits/complete-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/store/order-edits/decline-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/store/order-edits/get-order-edit.ts delete mode 100644 packages/medusa/src/api/routes/store/order-edits/index.ts delete mode 100644 packages/medusa/src/api/routes/store/orders/__tests__/get-order-by-cart.js delete mode 100644 packages/medusa/src/api/routes/store/orders/__tests__/get-order.js delete mode 100644 packages/medusa/src/api/routes/store/orders/__tests__/lookup-order.js delete mode 100644 packages/medusa/src/api/routes/store/orders/confirm-order-request.ts delete mode 100644 packages/medusa/src/api/routes/store/orders/get-order-by-cart.ts delete mode 100644 packages/medusa/src/api/routes/store/orders/get-order.ts delete mode 100644 packages/medusa/src/api/routes/store/orders/index.ts delete mode 100644 packages/medusa/src/api/routes/store/orders/lookup-order.ts delete mode 100644 packages/medusa/src/api/routes/store/orders/request-order.ts delete mode 100644 packages/medusa/src/api/routes/store/payment-collections/authorize-batch-payment-sessions.ts delete mode 100644 packages/medusa/src/api/routes/store/payment-collections/authorize-payment-session.ts delete mode 100644 packages/medusa/src/api/routes/store/payment-collections/get-payment-collection.ts delete mode 100644 packages/medusa/src/api/routes/store/payment-collections/index.ts delete mode 100644 packages/medusa/src/api/routes/store/payment-collections/manage-batch-payment-sessions.ts delete mode 100644 packages/medusa/src/api/routes/store/payment-collections/manage-payment-session.ts delete mode 100644 packages/medusa/src/api/routes/store/payment-collections/refresh-payment-session.ts delete mode 100644 packages/medusa/src/api/routes/store/product-categories/__tests__/get-product-category.ts delete mode 100644 packages/medusa/src/api/routes/store/product-categories/get-product-category.ts delete mode 100644 packages/medusa/src/api/routes/store/product-categories/index.ts delete mode 100644 packages/medusa/src/api/routes/store/product-categories/list-product-categories.ts delete mode 100644 packages/medusa/src/api/routes/store/product-tags/index.ts delete mode 100644 packages/medusa/src/api/routes/store/product-tags/list-product-tags.ts delete mode 100644 packages/medusa/src/api/routes/store/product-types/index.ts delete mode 100644 packages/medusa/src/api/routes/store/product-types/list-product-types.ts delete mode 100644 packages/medusa/src/api/routes/store/products/__tests__/get-product.js delete mode 100644 packages/medusa/src/api/routes/store/products/__tests__/list-products.js delete mode 100644 packages/medusa/src/api/routes/store/products/__tests__/search.js delete mode 100644 packages/medusa/src/api/routes/store/products/get-product.ts delete mode 100644 packages/medusa/src/api/routes/store/products/index.ts delete mode 100644 packages/medusa/src/api/routes/store/products/list-products.ts delete mode 100644 packages/medusa/src/api/routes/store/products/search.ts delete mode 100644 packages/medusa/src/api/routes/store/regions/__tests__/get-region.js delete mode 100644 packages/medusa/src/api/routes/store/regions/__tests__/list-regions.js delete mode 100644 packages/medusa/src/api/routes/store/regions/get-region.ts delete mode 100644 packages/medusa/src/api/routes/store/regions/index.ts delete mode 100644 packages/medusa/src/api/routes/store/regions/list-regions.ts delete mode 100644 packages/medusa/src/api/routes/store/return-reasons/get-reason.ts delete mode 100644 packages/medusa/src/api/routes/store/return-reasons/index.ts delete mode 100644 packages/medusa/src/api/routes/store/return-reasons/list-reasons.ts delete mode 100644 packages/medusa/src/api/routes/store/returns/create-return.ts delete mode 100644 packages/medusa/src/api/routes/store/returns/index.ts delete mode 100644 packages/medusa/src/api/routes/store/shipping-options/__tests__/list-options.js delete mode 100644 packages/medusa/src/api/routes/store/shipping-options/__tests__/list-shipping-options.js delete mode 100644 packages/medusa/src/api/routes/store/shipping-options/index.ts delete mode 100644 packages/medusa/src/api/routes/store/shipping-options/list-options.ts delete mode 100644 packages/medusa/src/api/routes/store/shipping-options/list-shipping-options.ts delete mode 100644 packages/medusa/src/api/routes/store/swaps/create-swap.ts delete mode 100644 packages/medusa/src/api/routes/store/swaps/get-swap-by-cart.ts delete mode 100644 packages/medusa/src/api/routes/store/swaps/index.ts delete mode 100644 packages/medusa/src/api/routes/store/variants/__tests__/get-variant.js delete mode 100644 packages/medusa/src/api/routes/store/variants/__tests__/list-variants.js delete mode 100644 packages/medusa/src/api/routes/store/variants/get-variant.ts delete mode 100644 packages/medusa/src/api/routes/store/variants/index.ts delete mode 100644 packages/medusa/src/api/routes/store/variants/list-variants.ts delete mode 100644 packages/medusa/src/commands/seed.ts delete mode 100644 packages/medusa/src/controllers/customers/index.ts delete mode 100644 packages/medusa/src/controllers/customers/list-customers.ts delete mode 100644 packages/medusa/src/interfaces/__tests__/event-bus-service.spec.ts delete mode 100644 packages/medusa/src/interfaces/abstract-parser.ts delete mode 100644 packages/medusa/src/interfaces/batch-job-strategy.ts delete mode 100644 packages/medusa/src/interfaces/cart-completion-strategy.ts delete mode 100644 packages/medusa/src/interfaces/csv-parser.ts delete mode 100644 packages/medusa/src/interfaces/file-service.ts delete mode 100644 packages/medusa/src/interfaces/fulfillment-service.ts delete mode 100644 packages/medusa/src/interfaces/notification-service.ts delete mode 100644 packages/medusa/src/interfaces/payment-processor.ts delete mode 100644 packages/medusa/src/interfaces/payment-service.ts delete mode 100644 packages/medusa/src/interfaces/price-selection-strategy.ts delete mode 100644 packages/medusa/src/interfaces/tax-calculation-strategy.ts delete mode 100644 packages/medusa/src/interfaces/tax-service.ts delete mode 100644 packages/medusa/src/loaders/__tests__/default.spec.ts delete mode 100644 packages/medusa/src/loaders/defaults.ts delete mode 100644 packages/medusa/src/loaders/helpers/plugins.ts delete mode 100644 packages/medusa/src/models/address.ts delete mode 100644 packages/medusa/src/models/analytics-config.ts delete mode 100644 packages/medusa/src/models/batch-job.ts delete mode 100644 packages/medusa/src/models/cart.ts delete mode 100644 packages/medusa/src/models/claim-image.ts delete mode 100644 packages/medusa/src/models/claim-item.ts delete mode 100644 packages/medusa/src/models/claim-order.ts delete mode 100644 packages/medusa/src/models/claim-tag.ts delete mode 100644 packages/medusa/src/models/country.ts delete mode 100644 packages/medusa/src/models/currency.ts delete mode 100644 packages/medusa/src/models/custom-shipping-option.ts delete mode 100644 packages/medusa/src/models/customer-group.ts delete mode 100644 packages/medusa/src/models/customer.ts delete mode 100644 packages/medusa/src/models/discount-condition-customer-group.ts delete mode 100644 packages/medusa/src/models/discount-condition-product-collection.ts delete mode 100644 packages/medusa/src/models/discount-condition-product-tag.ts delete mode 100644 packages/medusa/src/models/discount-condition-product-type.ts delete mode 100644 packages/medusa/src/models/discount-condition-product.ts delete mode 100644 packages/medusa/src/models/discount-condition.ts delete mode 100644 packages/medusa/src/models/discount-rule.ts delete mode 100644 packages/medusa/src/models/discount.ts delete mode 100644 packages/medusa/src/models/draft-order.ts delete mode 100644 packages/medusa/src/models/fulfillment-item.ts delete mode 100644 packages/medusa/src/models/fulfillment-provider.ts delete mode 100644 packages/medusa/src/models/fulfillment.ts delete mode 100644 packages/medusa/src/models/gift-card-transaction.ts delete mode 100644 packages/medusa/src/models/gift-card.ts delete mode 100644 packages/medusa/src/models/image.ts delete mode 100644 packages/medusa/src/models/invite.ts delete mode 100644 packages/medusa/src/models/line-item-adjustment.ts delete mode 100644 packages/medusa/src/models/line-item-tax-line.ts delete mode 100644 packages/medusa/src/models/line-item.ts delete mode 100644 packages/medusa/src/models/money-amount.ts delete mode 100644 packages/medusa/src/models/note.ts delete mode 100644 packages/medusa/src/models/notification-provider.ts delete mode 100644 packages/medusa/src/models/notification.ts delete mode 100644 packages/medusa/src/models/oauth.ts delete mode 100644 packages/medusa/src/models/order-edit.ts delete mode 100644 packages/medusa/src/models/order-item-change.ts delete mode 100644 packages/medusa/src/models/order-sales-channel.ts delete mode 100644 packages/medusa/src/models/order.ts delete mode 100644 packages/medusa/src/models/payment-collection.ts delete mode 100644 packages/medusa/src/models/payment-provider.ts delete mode 100644 packages/medusa/src/models/payment-session.ts delete mode 100644 packages/medusa/src/models/payment.ts delete mode 100644 packages/medusa/src/models/price-list.ts delete mode 100644 packages/medusa/src/models/product-category.ts delete mode 100644 packages/medusa/src/models/product-collection.ts delete mode 100644 packages/medusa/src/models/product-option-value.ts delete mode 100644 packages/medusa/src/models/product-option.ts delete mode 100644 packages/medusa/src/models/product-sales-channel.ts delete mode 100644 packages/medusa/src/models/product-tag.ts delete mode 100644 packages/medusa/src/models/product-tax-rate.ts delete mode 100644 packages/medusa/src/models/product-type-tax-rate.ts delete mode 100644 packages/medusa/src/models/product-type.ts delete mode 100644 packages/medusa/src/models/product-variant-inventory-item.ts delete mode 100644 packages/medusa/src/models/product-variant-money-amount.ts delete mode 100644 packages/medusa/src/models/product-variant.ts delete mode 100644 packages/medusa/src/models/product.ts delete mode 100644 packages/medusa/src/models/publishable-api-key-sales-channel.ts delete mode 100644 packages/medusa/src/models/publishable-api-key.ts delete mode 100644 packages/medusa/src/models/refund.ts delete mode 100644 packages/medusa/src/models/region.ts delete mode 100644 packages/medusa/src/models/return-item.ts delete mode 100644 packages/medusa/src/models/return-reason.ts delete mode 100644 packages/medusa/src/models/return.ts delete mode 100644 packages/medusa/src/models/sales-channel-location.ts delete mode 100644 packages/medusa/src/models/sales-channel.ts delete mode 100644 packages/medusa/src/models/shipping-method-tax-line.ts delete mode 100644 packages/medusa/src/models/shipping-method.ts delete mode 100644 packages/medusa/src/models/shipping-option-requirement.ts delete mode 100644 packages/medusa/src/models/shipping-option.ts delete mode 100644 packages/medusa/src/models/shipping-profile.ts delete mode 100644 packages/medusa/src/models/shipping-tax-rate.ts delete mode 100644 packages/medusa/src/models/store.ts delete mode 100644 packages/medusa/src/models/swap.ts delete mode 100644 packages/medusa/src/models/tax-line.ts delete mode 100644 packages/medusa/src/models/tax-provider.ts delete mode 100644 packages/medusa/src/models/tax-rate.ts delete mode 100644 packages/medusa/src/models/tracking-link.ts delete mode 100644 packages/medusa/src/models/user.ts delete mode 100644 packages/medusa/src/repositories/address.ts delete mode 100644 packages/medusa/src/repositories/analytics-config.ts delete mode 100644 packages/medusa/src/repositories/batch-job.ts delete mode 100644 packages/medusa/src/repositories/cart.ts delete mode 100644 packages/medusa/src/repositories/claim-image.ts delete mode 100644 packages/medusa/src/repositories/claim-item.ts delete mode 100644 packages/medusa/src/repositories/claim-tag.ts delete mode 100644 packages/medusa/src/repositories/claim.ts delete mode 100644 packages/medusa/src/repositories/country.ts delete mode 100644 packages/medusa/src/repositories/currency.ts delete mode 100644 packages/medusa/src/repositories/custom-shipping-option.ts delete mode 100644 packages/medusa/src/repositories/customer-group.ts delete mode 100644 packages/medusa/src/repositories/customer.ts delete mode 100644 packages/medusa/src/repositories/discount-condition.ts delete mode 100644 packages/medusa/src/repositories/discount-rule.ts delete mode 100644 packages/medusa/src/repositories/discount.ts delete mode 100644 packages/medusa/src/repositories/draft-order.ts delete mode 100644 packages/medusa/src/repositories/fulfillment-provider.ts delete mode 100644 packages/medusa/src/repositories/fulfillment.ts delete mode 100644 packages/medusa/src/repositories/gift-card-transaction.ts delete mode 100644 packages/medusa/src/repositories/gift-card.ts delete mode 100644 packages/medusa/src/repositories/image.ts delete mode 100644 packages/medusa/src/repositories/invite.ts delete mode 100644 packages/medusa/src/repositories/line-item-adjustment.ts delete mode 100644 packages/medusa/src/repositories/line-item-tax-line.ts delete mode 100644 packages/medusa/src/repositories/line-item.ts delete mode 100644 packages/medusa/src/repositories/money-amount.ts delete mode 100644 packages/medusa/src/repositories/note.ts delete mode 100644 packages/medusa/src/repositories/notification-provider.ts delete mode 100644 packages/medusa/src/repositories/notification.ts delete mode 100644 packages/medusa/src/repositories/oauth.ts delete mode 100644 packages/medusa/src/repositories/order-edit.ts delete mode 100644 packages/medusa/src/repositories/order-item-change.ts delete mode 100644 packages/medusa/src/repositories/order.ts delete mode 100644 packages/medusa/src/repositories/payment-collection.ts delete mode 100644 packages/medusa/src/repositories/payment-provider.ts delete mode 100644 packages/medusa/src/repositories/payment-session.ts delete mode 100644 packages/medusa/src/repositories/payment.ts delete mode 100644 packages/medusa/src/repositories/price-list.ts delete mode 100644 packages/medusa/src/repositories/product-category.ts delete mode 100644 packages/medusa/src/repositories/product-collection.ts delete mode 100644 packages/medusa/src/repositories/product-option-value.ts delete mode 100644 packages/medusa/src/repositories/product-option.ts delete mode 100644 packages/medusa/src/repositories/product-tag.ts delete mode 100644 packages/medusa/src/repositories/product-tax-rate.ts delete mode 100644 packages/medusa/src/repositories/product-type.ts delete mode 100644 packages/medusa/src/repositories/product-variant.ts delete mode 100644 packages/medusa/src/repositories/product.ts delete mode 100644 packages/medusa/src/repositories/publishable-api-key-sales-channel.ts delete mode 100644 packages/medusa/src/repositories/publishable-api-key.ts delete mode 100644 packages/medusa/src/repositories/refund.ts delete mode 100644 packages/medusa/src/repositories/region.ts delete mode 100644 packages/medusa/src/repositories/return-item.ts delete mode 100644 packages/medusa/src/repositories/return-reason.ts delete mode 100644 packages/medusa/src/repositories/return.ts delete mode 100644 packages/medusa/src/repositories/sales-channel.ts delete mode 100644 packages/medusa/src/repositories/shipping-method-tax-line.ts delete mode 100644 packages/medusa/src/repositories/shipping-method.ts delete mode 100644 packages/medusa/src/repositories/shipping-option-requirement.ts delete mode 100644 packages/medusa/src/repositories/shipping-option.ts delete mode 100644 packages/medusa/src/repositories/shipping-profile.ts delete mode 100644 packages/medusa/src/repositories/shipping-tax-rate.ts delete mode 100644 packages/medusa/src/repositories/store.ts delete mode 100644 packages/medusa/src/repositories/swap.ts delete mode 100644 packages/medusa/src/repositories/tax-provider.ts delete mode 100644 packages/medusa/src/repositories/tax-rate.ts delete mode 100644 packages/medusa/src/repositories/tracking-link.ts delete mode 100644 packages/medusa/src/repositories/user.ts delete mode 100644 packages/medusa/src/scripts/discount-rule-migration.ts delete mode 100644 packages/medusa/src/scripts/gift-card-tax-rate-migration.ts delete mode 100644 packages/medusa/src/scripts/line-item-adjustment-migration.ts delete mode 100644 packages/medusa/src/scripts/migrate-inventory-items.ts delete mode 100644 packages/medusa/src/scripts/sales-channels-migration.ts delete mode 100644 packages/medusa/src/services/__fixtures__/new-totals.ts delete mode 100644 packages/medusa/src/services/__fixtures__/payment-provider.ts delete mode 100644 packages/medusa/src/services/__fixtures__/tax-provider.ts delete mode 100644 packages/medusa/src/services/__mocks__/auth.js delete mode 100644 packages/medusa/src/services/__mocks__/cache.js delete mode 100644 packages/medusa/src/services/__mocks__/cart.js delete mode 100644 packages/medusa/src/services/__mocks__/claim.js delete mode 100644 packages/medusa/src/services/__mocks__/currency.js delete mode 100644 packages/medusa/src/services/__mocks__/customer-group.js delete mode 100644 packages/medusa/src/services/__mocks__/customer.js delete mode 100644 packages/medusa/src/services/__mocks__/discount.js delete mode 100644 packages/medusa/src/services/__mocks__/document.js delete mode 100644 packages/medusa/src/services/__mocks__/fulfillment-provider.js delete mode 100644 packages/medusa/src/services/__mocks__/fulfillment.js delete mode 100644 packages/medusa/src/services/__mocks__/inventory.js delete mode 100644 packages/medusa/src/services/__mocks__/invite.js delete mode 100644 packages/medusa/src/services/__mocks__/line-item-adjustment.js delete mode 100644 packages/medusa/src/services/__mocks__/line-item.js delete mode 100644 packages/medusa/src/services/__mocks__/new-totals.js delete mode 100644 packages/medusa/src/services/__mocks__/order-edit-item-change.js delete mode 100644 packages/medusa/src/services/__mocks__/order-edit.js delete mode 100644 packages/medusa/src/services/__mocks__/order.js delete mode 100644 packages/medusa/src/services/__mocks__/payment-collection.js delete mode 100644 packages/medusa/src/services/__mocks__/payment-provider.js delete mode 100644 packages/medusa/src/services/__mocks__/payment.js delete mode 100644 packages/medusa/src/services/__mocks__/price-list.js delete mode 100644 packages/medusa/src/services/__mocks__/pricing.js delete mode 100644 packages/medusa/src/services/__mocks__/product-category.js delete mode 100644 packages/medusa/src/services/__mocks__/product-collection.js delete mode 100644 packages/medusa/src/services/__mocks__/product-variant-inventory.js delete mode 100644 packages/medusa/src/services/__mocks__/product-variant.js delete mode 100644 packages/medusa/src/services/__mocks__/product.js delete mode 100644 packages/medusa/src/services/__mocks__/region.js delete mode 100644 packages/medusa/src/services/__mocks__/return.js delete mode 100644 packages/medusa/src/services/__mocks__/sales-channel.js delete mode 100644 packages/medusa/src/services/__mocks__/search.js delete mode 100644 packages/medusa/src/services/__mocks__/shipping-option.js delete mode 100644 packages/medusa/src/services/__mocks__/shipping-profile.js delete mode 100644 packages/medusa/src/services/__mocks__/staged-job.js delete mode 100644 packages/medusa/src/services/__mocks__/stock-location.js delete mode 100644 packages/medusa/src/services/__mocks__/store.js delete mode 100644 packages/medusa/src/services/__mocks__/swap.js delete mode 100644 packages/medusa/src/services/__mocks__/tax-provider.js delete mode 100644 packages/medusa/src/services/__mocks__/test-pay.js delete mode 100644 packages/medusa/src/services/__mocks__/totals.js delete mode 100644 packages/medusa/src/services/__mocks__/user.js delete mode 100644 packages/medusa/src/services/__tests__/auth.js delete mode 100644 packages/medusa/src/services/__tests__/batch-job.ts delete mode 100644 packages/medusa/src/services/__tests__/cart.js delete mode 100644 packages/medusa/src/services/__tests__/claim-item.js delete mode 100644 packages/medusa/src/services/__tests__/claim.js delete mode 100644 packages/medusa/src/services/__tests__/csv-parser.js delete mode 100644 packages/medusa/src/services/__tests__/currency.ts delete mode 100644 packages/medusa/src/services/__tests__/custom-shipping-option.js delete mode 100644 packages/medusa/src/services/__tests__/customer.js delete mode 100644 packages/medusa/src/services/__tests__/discount.js delete mode 100644 packages/medusa/src/services/__tests__/draft-order.js delete mode 100644 packages/medusa/src/services/__tests__/fulfillment.js delete mode 100644 packages/medusa/src/services/__tests__/gift-card.js delete mode 100644 packages/medusa/src/services/__tests__/invite.js delete mode 100644 packages/medusa/src/services/__tests__/line-item-adjustment.js delete mode 100644 packages/medusa/src/services/__tests__/line-item.js delete mode 100644 packages/medusa/src/services/__tests__/new-totals.ts delete mode 100644 packages/medusa/src/services/__tests__/note.js delete mode 100644 packages/medusa/src/services/__tests__/notification.js delete mode 100644 packages/medusa/src/services/__tests__/order-edit-item-change.ts delete mode 100644 packages/medusa/src/services/__tests__/order-edit.ts delete mode 100644 packages/medusa/src/services/__tests__/order.js delete mode 100644 packages/medusa/src/services/__tests__/payment-collection.ts delete mode 100644 packages/medusa/src/services/__tests__/payment-provider.ts delete mode 100644 packages/medusa/src/services/__tests__/price-list.js delete mode 100644 packages/medusa/src/services/__tests__/product-category.ts delete mode 100644 packages/medusa/src/services/__tests__/product-collection.js delete mode 100644 packages/medusa/src/services/__tests__/product-variant.js delete mode 100644 packages/medusa/src/services/__tests__/product.js delete mode 100644 packages/medusa/src/services/__tests__/publishable-api-key.ts delete mode 100644 packages/medusa/src/services/__tests__/region.ts delete mode 100644 packages/medusa/src/services/__tests__/return.js delete mode 100644 packages/medusa/src/services/__tests__/sales-channel.ts delete mode 100644 packages/medusa/src/services/__tests__/shipping-option.js delete mode 100644 packages/medusa/src/services/__tests__/shipping-profile.js delete mode 100644 packages/medusa/src/services/__tests__/store.js delete mode 100644 packages/medusa/src/services/__tests__/swap.ts delete mode 100644 packages/medusa/src/services/__tests__/system-tax.js delete mode 100644 packages/medusa/src/services/__tests__/tax-provider.js delete mode 100644 packages/medusa/src/services/__tests__/totals.js delete mode 100644 packages/medusa/src/services/__tests__/user.js delete mode 100644 packages/medusa/src/services/analytics-config.ts delete mode 100644 packages/medusa/src/services/auth.ts delete mode 100644 packages/medusa/src/services/batch-job.ts delete mode 100644 packages/medusa/src/services/cart.ts delete mode 100644 packages/medusa/src/services/claim-item.ts delete mode 100644 packages/medusa/src/services/claim.ts delete mode 100644 packages/medusa/src/services/csv-parser.ts delete mode 100644 packages/medusa/src/services/currency.ts delete mode 100644 packages/medusa/src/services/custom-shipping-option.ts delete mode 100644 packages/medusa/src/services/customer-group.ts delete mode 100644 packages/medusa/src/services/customer.ts delete mode 100644 packages/medusa/src/services/discount-condition.ts delete mode 100644 packages/medusa/src/services/discount.ts delete mode 100644 packages/medusa/src/services/draft-order.ts delete mode 100644 packages/medusa/src/services/file.ts delete mode 100644 packages/medusa/src/services/fulfillment-provider.ts delete mode 100644 packages/medusa/src/services/fulfillment.ts delete mode 100644 packages/medusa/src/services/gift-card.ts delete mode 100644 packages/medusa/src/services/invite.ts delete mode 100644 packages/medusa/src/services/line-item-adjustment.ts delete mode 100644 packages/medusa/src/services/line-item.ts delete mode 100644 packages/medusa/src/services/new-totals.ts delete mode 100644 packages/medusa/src/services/note.ts delete mode 100644 packages/medusa/src/services/notification.ts delete mode 100644 packages/medusa/src/services/oauth.ts delete mode 100644 packages/medusa/src/services/order-edit-item-change.ts delete mode 100644 packages/medusa/src/services/order-edit.ts delete mode 100644 packages/medusa/src/services/order.ts delete mode 100644 packages/medusa/src/services/payment-collection.ts delete mode 100644 packages/medusa/src/services/payment-provider.ts delete mode 100644 packages/medusa/src/services/payment.ts delete mode 100644 packages/medusa/src/services/price-list.ts delete mode 100644 packages/medusa/src/services/pricing.ts delete mode 100644 packages/medusa/src/services/product-category.ts delete mode 100644 packages/medusa/src/services/product-collection.ts delete mode 100644 packages/medusa/src/services/product-tag.ts delete mode 100644 packages/medusa/src/services/product-tax-rate.ts delete mode 100644 packages/medusa/src/services/product-type.ts delete mode 100644 packages/medusa/src/services/product-variant-inventory.ts delete mode 100644 packages/medusa/src/services/product-variant.ts delete mode 100644 packages/medusa/src/services/product.ts delete mode 100644 packages/medusa/src/services/publishable-api-key.ts delete mode 100644 packages/medusa/src/services/region.ts delete mode 100644 packages/medusa/src/services/return-reason.ts delete mode 100644 packages/medusa/src/services/return.ts delete mode 100644 packages/medusa/src/services/sales-channel-inventory.ts delete mode 100644 packages/medusa/src/services/sales-channel-location.ts delete mode 100644 packages/medusa/src/services/sales-channel.ts delete mode 100644 packages/medusa/src/services/search.ts delete mode 100644 packages/medusa/src/services/shipping-option.ts delete mode 100644 packages/medusa/src/services/shipping-profile.ts delete mode 100644 packages/medusa/src/services/shipping-tax-rate.ts delete mode 100644 packages/medusa/src/services/store.ts delete mode 100644 packages/medusa/src/services/strategy-resolver.ts delete mode 100644 packages/medusa/src/services/swap.ts delete mode 100644 packages/medusa/src/services/system-payment-provider.ts delete mode 100644 packages/medusa/src/services/system-tax.ts delete mode 100644 packages/medusa/src/services/tax-provider.ts delete mode 100644 packages/medusa/src/services/tax-rate.ts delete mode 100644 packages/medusa/src/services/token.ts delete mode 100644 packages/medusa/src/services/totals.ts delete mode 100644 packages/medusa/src/services/user.ts delete mode 100644 packages/medusa/src/strategies/__fixtures__/order-export-data.ts delete mode 100644 packages/medusa/src/strategies/__fixtures__/product-export-data.ts delete mode 100644 packages/medusa/src/strategies/__mocks__/cart-completion.js delete mode 100644 packages/medusa/src/strategies/__tests__/batch-jobs/order/__snapshots__/order-export.ts.snap delete mode 100644 packages/medusa/src/strategies/__tests__/batch-jobs/order/order-export.ts delete mode 100644 packages/medusa/src/strategies/__tests__/batch-jobs/price-list/import.ts delete mode 100644 packages/medusa/src/strategies/__tests__/batch-jobs/product/__snapshots__/export.ts.snap delete mode 100644 packages/medusa/src/strategies/__tests__/batch-jobs/product/export.ts delete mode 100644 packages/medusa/src/strategies/__tests__/batch-jobs/product/import.ts delete mode 100644 packages/medusa/src/strategies/__tests__/cart-completion.js delete mode 100644 packages/medusa/src/strategies/__tests__/price-selection.js delete mode 100644 packages/medusa/src/strategies/__tests__/tax-calculation.js delete mode 100644 packages/medusa/src/strategies/batch-jobs/order/export.ts delete mode 100644 packages/medusa/src/strategies/batch-jobs/order/index.ts delete mode 100644 packages/medusa/src/strategies/batch-jobs/price-list/import.ts delete mode 100644 packages/medusa/src/strategies/batch-jobs/price-list/types.ts delete mode 100644 packages/medusa/src/strategies/batch-jobs/product/export.ts delete mode 100644 packages/medusa/src/strategies/batch-jobs/product/import.ts delete mode 100644 packages/medusa/src/strategies/batch-jobs/product/types/columns-definition.ts delete mode 100644 packages/medusa/src/strategies/batch-jobs/product/types/index.ts delete mode 100644 packages/medusa/src/strategies/batch-jobs/product/utils.ts delete mode 100644 packages/medusa/src/strategies/cart-completion.ts delete mode 100644 packages/medusa/src/strategies/price-selection.ts delete mode 100644 packages/medusa/src/strategies/tax-calculation.ts delete mode 100644 packages/medusa/src/types/auth.ts delete mode 100644 packages/medusa/src/types/cart.ts delete mode 100644 packages/medusa/src/types/claim.ts delete mode 100644 packages/medusa/src/types/currency.ts delete mode 100644 packages/medusa/src/types/customer-groups.ts delete mode 100644 packages/medusa/src/types/customers.ts delete mode 100644 packages/medusa/src/types/discount.ts delete mode 100644 packages/medusa/src/types/draft-orders.ts delete mode 100644 packages/medusa/src/types/fulfillment-provider.ts delete mode 100644 packages/medusa/src/types/fulfillment.ts delete mode 100644 packages/medusa/src/types/gift-card.ts delete mode 100644 packages/medusa/src/types/invites.ts delete mode 100644 packages/medusa/src/types/line-item-adjustment.ts delete mode 100644 packages/medusa/src/types/line-item.ts delete mode 100644 packages/medusa/src/types/note.ts delete mode 100644 packages/medusa/src/types/oauth.ts delete mode 100644 packages/medusa/src/types/order-edit.ts delete mode 100644 packages/medusa/src/types/orders.ts delete mode 100644 packages/medusa/src/types/payment-collection.ts delete mode 100644 packages/medusa/src/types/payment.ts delete mode 100644 packages/medusa/src/types/price-list.ts delete mode 100644 packages/medusa/src/types/price-selection.ts delete mode 100644 packages/medusa/src/types/pricing.ts delete mode 100644 packages/medusa/src/types/product-category.ts delete mode 100644 packages/medusa/src/types/product-collection.ts delete mode 100644 packages/medusa/src/types/product-tax-rate.ts delete mode 100644 packages/medusa/src/types/product-variant.ts delete mode 100644 packages/medusa/src/types/product.ts delete mode 100644 packages/medusa/src/types/publishable-api-key.ts delete mode 100644 packages/medusa/src/types/region.ts delete mode 100644 packages/medusa/src/types/return-reason.ts delete mode 100644 packages/medusa/src/types/return.ts delete mode 100644 packages/medusa/src/types/sales-channels.ts delete mode 100644 packages/medusa/src/types/shipping-options.ts delete mode 100644 packages/medusa/src/types/shipping-profile.ts delete mode 100644 packages/medusa/src/types/shipping-tax-rate.ts delete mode 100644 packages/medusa/src/types/store.ts delete mode 100644 packages/medusa/src/types/tax-rate.ts delete mode 100644 packages/medusa/src/types/tax-service.ts delete mode 100644 packages/medusa/src/types/token.ts delete mode 100644 packages/medusa/src/types/totals.ts delete mode 100644 packages/medusa/src/types/user.ts delete mode 100644 packages/medusa/src/utils/__tests__/validator.spec.ts rename packages/medusa/src/{api => utils}/middlewares/__tests__/transform-query.spec.ts (100%) rename packages/medusa/src/{api => utils}/middlewares/authenticate-customer.ts (100%) rename packages/medusa/src/{api => utils}/middlewares/authenticate.ts (100%) rename packages/medusa/src/{api => utils}/middlewares/await-middleware.ts (100%) rename packages/medusa/src/{api => utils}/middlewares/check-registered-modules.ts (100%) rename packages/medusa/src/{api => utils}/middlewares/error-handler.ts (100%) rename packages/medusa/src/{api => utils}/middlewares/feature-flag-enabled.ts (100%) create mode 100644 packages/medusa/src/utils/middlewares/index.ts rename packages/medusa/src/{api => utils}/middlewares/normalized-query.ts (100%) rename packages/medusa/src/{api => utils}/middlewares/require-customer-authentication.ts (100%) rename packages/medusa/src/{api => utils}/middlewares/transform-body.ts (100%) rename packages/medusa/src/{api => utils}/middlewares/transform-includes-options.ts (100%) rename packages/medusa/src/{api => utils}/middlewares/transform-query.ts (100%) delete mode 100644 packages/medusa/src/utils/naming-strategy.ts delete mode 100644 packages/medusa/src/utils/product-category/index.ts delete mode 100644 packages/medusa/src/utils/queries/index.ts delete mode 100644 packages/medusa/src/utils/queries/products/get-variants-from-price-list.ts delete mode 100644 packages/medusa/src/utils/queries/products/index.ts delete mode 100644 packages/medusa/src/utils/queries/products/list-products.ts delete mode 100644 packages/medusa/src/utils/queries/products/retrieve-product.ts diff --git a/.changeset/config.json b/.changeset/config.json index 98b3747bcc..f9bfe7d8a3 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -9,9 +9,7 @@ "updateInternalDependencies": "patch", "ignore": [ "integration-tests-api", - "integration-tests-plugins", "integration-tests-modules", - "integration-tests-repositories", "@medusajs/dashboard", "@medusajs/admin-shared", "@medusajs/admin-bundler", diff --git a/.github/actions/cache-deps/action.yml b/.github/actions/cache-deps/action.yml index 414329e6f0..bb80c6a23e 100644 --- a/.github/actions/cache-deps/action.yml +++ b/.github/actions/cache-deps/action.yml @@ -11,9 +11,9 @@ runs: with: path: | .yarn/cache - key: ${{ runner.os }}-yarn-${{inputs.extension}}-v8-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-yarn-${{inputs.extension}}-v8-${{ hashFiles('**/yarn.lock') }}-3 restore-keys: | - ${{ runner.os }}-yarn-${{inputs.extension}}-v8 + ${{ runner.os }}-yarn-${{inputs.extension}}-v8-3 # We want to only bootstrap and install if no cache is found. - run: yarn install --immutable shell: bash diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index 376a135ad9..742e5fe6d5 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -2,12 +2,12 @@ name: Medusa Pipeline on: push: branches: - - develop - - v1.x + - develop + - v1.x pull_request: branches: - - develop - - v1.x + - develop + - v1.x jobs: setup: @@ -157,75 +157,75 @@ jobs: DB_PASSWORD: postgres DB_USERNAME: postgres - integration-tests-api-matrix: - needs: setup - name: Shard (${{ matrix.chunk }}) API Integration Tests - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - chunk: ${{ fromJSON(needs.setup.outputs.api-matrix) }} - env: - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + #integration-tests-api-matrix: + # needs: setup + # name: Shard (${{ matrix.chunk }}) API Integration Tests + # runs-on: ubuntu-latest + # strategy: + # fail-fast: false + # matrix: + # chunk: ${{ fromJSON(needs.setup.outputs.api-matrix) }} + # env: + # TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + # TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + # + # services: + # redis: + # image: redis + # options: >- + # --health-cmd "redis-cli ping" + # --health-interval 1s + # --health-timeout 10s + # --health-retries 10 + # ports: + # - 6379:6379 + # postgres: + # image: postgres + # env: + # POSTGRES_PASSWORD: postgres + # POSTGRES_USER: postgres + # options: >- + # --health-cmd pg_isready + # --health-interval 1s + # --health-timeout 10s + # --health-retries 10 + # ports: + # - 5432:5432 - services: - redis: - image: redis - options: >- - --health-cmd "redis-cli ping" - --health-interval 1s - --health-timeout 10s - --health-retries 10 - ports: - - 6379:6379 - postgres: - image: postgres - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 1s - --health-timeout 10s - --health-retries 10 - ports: - - 5432:5432 + # steps: + # - name: Checkout + # uses: actions/checkout@v3 + # with: + # fetch-depth: 0 + # + # - name: Install dependencies + # uses: ./.github/actions/cache-deps + # with: + # extension: pipeline + # + # - name: Run API integration tests + # run: yarn test:integration:api + # env: + # DB_USERNAME: postgres + # DB_PASSWORD: postgres + # NODE_OPTIONS: "--max_old_space_size=4096" + # CHUNK: ${{ matrix.chunk }} + # CHUNKS: ${{ needs.setup.outputs.api-chunks }} - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Install dependencies - uses: ./.github/actions/cache-deps - with: - extension: pipeline - - - name: Run API integration tests - run: yarn test:integration:api - env: - DB_USERNAME: postgres - DB_PASSWORD: postgres - NODE_OPTIONS: "--max_old_space_size=4096" - CHUNK: ${{ matrix.chunk }} - CHUNKS: ${{ needs.setup.outputs.api-chunks }} - - integration-tests-api: - if: ${{ always() }} - runs-on: ubuntu-latest - needs: integration-tests-api-matrix - steps: - - run: exit 1 - if: >- - ${{ - contains(needs.integration-tests-api-matrix.result, 'failure') - || contains(needs.integration-tests-api-matrix.result, 'cancelled') - || contains(needs.integration-tests-api-matrix.result, 'skipped') - }} - - run: exit 0 - if: ${{ contains(needs.integration-tests-api-matrix.result, 'success') }} + #integration-tests-api: + # if: ${{ always() }} + # runs-on: ubuntu-latest + # needs: integration-tests-api-matrix + # steps: + # - run: exit 1 + # if: >- + # ${{ + # contains(needs.integration-tests-api-matrix.result, 'failure') + # || contains(needs.integration-tests-api-matrix.result, 'cancelled') + # || contains(needs.integration-tests-api-matrix.result, 'skipped') + # }} + # - run: exit 0 + # if: ${{ contains(needs.integration-tests-api-matrix.result, 'success') }} unit-tests: if: ${{ always() }} @@ -242,51 +242,6 @@ jobs: - run: exit 0 if: ${{ contains(needs.unit-tests-matrix.result, 'success') }} - integration-tests-plugins: - needs: setup - runs-on: ubuntu-latest - env: - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - - services: - postgres: - image: postgres - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 1s - --health-timeout 10s - --health-retries 10 - ports: - - 5432:5432 - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Setup Node.js environment - uses: actions/setup-node@v3 - with: - node-version: "16.10.0" - cache: "yarn" - - - name: Install dependencies - uses: ./.github/actions/cache-deps - with: - extension: pipeline - - - name: Run plugin integration tests - run: yarn test:integration:plugins - env: - DB_USERNAME: postgres - DB_PASSWORD: postgres - NODE_OPTIONS: "--max_old_space_size=4096" - integration-tests-modules-matrix: needs: setup name: Shard (${{ matrix.chunk }}) Module Integration Tests @@ -346,41 +301,3 @@ jobs: }} - run: exit 0 if: ${{ contains(needs.integration-tests-modules-matrix.result, 'success') }} - - integration-tests-repositories: - needs: setup - runs-on: ubuntu-latest - env: - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - - services: - postgres: - image: postgres - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 1s - --health-timeout 10s - --health-retries 10 - ports: - - 5432:5432 - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Install dependencies - uses: ./.github/actions/cache-deps - with: - extension: pipeline - - - name: Run repository integration tests - run: yarn test:integration:repositories - env: - DB_USERNAME: postgres - DB_PASSWORD: postgres diff --git a/.github/workflows/test-cli-with-database.yml b/.github/workflows/test-cli-with-database.yml index 400b89e8ae..4e55729817 100644 --- a/.github/workflows/test-cli-with-database.yml +++ b/.github/workflows/test-cli-with-database.yml @@ -1,90 +1,90 @@ -name: CLI Pipeline -on: - pull_request: - -jobs: - test-cli-with-database: - env: - NODE_ENV: CI - REDIS_URL: redis://localhost:6379 - DATABASE_URL: "postgres://postgres:postgres@localhost/cli-test" - services: - redis: - image: redis - # Set health checks to wait until redis has started - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 6379:6379 - - postgres: - image: postgres - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - POSTGRES_DB: cli-test - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Setup development server - uses: ./.github/actions/setup-server - with: - cache-extension: "cli-test" - node-version: "16.14" - - - name: Install Medusa cli - run: npm i -g @medusajs/medusa-cli - - - name: Create Medusa project - run: | - medusa new cli-test --skip-db - working-directory: .. - - - name: run medusa dev - run: medusa-dev --force-install - working-directory: ../cli-test - - - name: Run migrations - run: medusa migrations run - working-directory: ../cli-test - - - name: Seed db - run: yarn seed - working-directory: ../cli-test - - - name: Create admin user - run: medusa user -e test@test.com -p password -i admin_123 - working-directory: ../cli-test - - ########################## Test medusa develop ############################### - - - name: Run development server - run: medusa develop & - working-directory: ../cli-test - - - name: Testing development server - uses: ./.github/actions/test-server - - ########################### Test medusa start ################################ - - - name: Starting medusa - run: medusa start & - working-directory: ../cli-test - - - name: Testing server - uses: ./.github/actions/test-server +#name: CLI Pipeline +#on: +# pull_request: +# +#jobs: +# test-cli-with-database: +# env: +# NODE_ENV: CI +# REDIS_URL: redis://localhost:6379 +# DATABASE_URL: "postgres://postgres:postgres@localhost/cli-test" +# services: +# redis: +# image: redis +# Set health checks to wait until redis has started +# options: >- +# --health-cmd "redis-cli ping" +# --health-interval 10s +# --health-timeout 5s +# --health-retries 5 +# ports: +# - 6379:6379 +# +# postgres: +# image: postgres +# env: +# POSTGRES_PASSWORD: postgres +# POSTGRES_USER: postgres +# POSTGRES_DB: cli-test +# options: >- +# --health-cmd pg_isready +# --health-interval 10s +# --health-timeout 5s +# --health-retries 5 +# ports: +# - 5432:5432 +# +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v3 +# with: +# fetch-depth: 0 +# +# - name: Setup development server +# uses: ./.github/actions/setup-server +# with: +# cache-extension: "cli-test" +# node-version: "16.14" +# +# - name: Install Medusa cli +# run: npm i -g @medusajs/medusa-cli +# +# - name: Create Medusa project +# run: | +# medusa new cli-test --skip-db +# working-directory: .. +# +# - name: run medusa dev +# run: medusa-dev --force-install +# working-directory: ../cli-test +# +# - name: Run migrations +# run: medusa migrations run +# working-directory: ../cli-test +# +# - name: Seed db +# run: yarn seed +# working-directory: ../cli-test +# +# - name: Create admin user +# run: medusa user -e test@test.com -p password -i admin_123 +# working-directory: ../cli-test +# +# Test medusa develop +# +# - name: Run development server +# run: medusa develop & +# working-directory: ../cli-test +# +# - name: Testing development server +# uses: ./.github/actions/test-server +# +# Test medusa start +# +# - name: Starting medusa +# run: medusa start & +# working-directory: ../cli-test +# +# - name: Testing server +# uses: ./.github/actions/test-server diff --git a/packages/medusa/src/controllers/__mocks__/customers.ts b/integration-tests/api/src/index.js similarity index 100% rename from packages/medusa/src/controllers/__mocks__/customers.ts rename to integration-tests/api/src/index.js diff --git a/integration-tests/api/src/services/local-file-service.js b/integration-tests/api/src/services/local-file-service.js deleted file mode 100644 index dc4fbfbe33..0000000000 --- a/integration-tests/api/src/services/local-file-service.js +++ /dev/null @@ -1,96 +0,0 @@ -import { AbstractFileService } from "@medusajs/medusa" -import * as fs from "fs" -import mkdirp from "mkdirp" -import { resolve } from "path" -import stream from "stream" - -export default class LocalFileService extends AbstractFileService { - constructor({}, options) { - super({}, options) - this.upload_dir_ = - process.env.UPLOAD_DIR ?? options.upload_dir ?? "uploads/images" - - if (!fs.existsSync(this.upload_dir_)) { - fs.mkdirSync(this.upload_dir_) - } - } - - upload(file) { - return new Promise((resolvePromise, reject) => { - const path = resolve(this.upload_dir_, file.originalname) - - let content = "" - if (file.filename) { - content = fs.readFileSync( - resolve(process.cwd(), "uploads", file.filename) - ) - } - - const pathSegments = path.split("/") - pathSegments.splice(-1) - const dirname = pathSegments.join("/") - mkdirp.sync(dirname, { recursive: true }) - - fs.writeFile(path, content.toString(), (err) => { - if (err) { - reject(err) - } - - resolvePromise({ url: path }) - }) - }) - } - - delete({ fileKey }) { - return new Promise((resolvePromise, reject) => { - const path = resolve(this.upload_dir_, fileKey) - fs.unlink(path, (err) => { - if (err) { - reject(err) - } - - resolvePromise("file unlinked") - }) - }) - } - - async getUploadStreamDescriptor({ name, ext }) { - const fileKey = `${name}.${ext}` - const path = resolve(this.upload_dir_, fileKey) - - const isFileExists = fs.existsSync(path) - if (!isFileExists) { - await this.upload({ originalname: fileKey }) - } - - const pass = new stream.PassThrough() - pass.pipe(fs.createWriteStream(path)) - - return { - writeStream: pass, - promise: Promise.resolve(), - url: `${this.upload_dir_}/${fileKey}`, - fileKey, - } - } - - async getDownloadStream({ fileKey }) { - return new Promise((resolvePromise, reject) => { - try { - const path = resolve(this.upload_dir_, fileKey) - const data = fs.readFileSync(path) - const readable = stream.Readable() - readable._read = function () {} - readable.push(data.toString()) - readable.push(null) - resolvePromise(readable) - } catch (e) { - reject(e) - } - }) - } - - async getPresignedDownloadUrl({ fileKey }) { - return `${this.upload_dir_}/${fileKey}` - } -} diff --git a/integration-tests/api/src/services/test-ful.js b/integration-tests/api/src/services/test-ful.js deleted file mode 100644 index 4c2f4688ee..0000000000 --- a/integration-tests/api/src/services/test-ful.js +++ /dev/null @@ -1,53 +0,0 @@ -import { FulfillmentService } from "medusa-interfaces" - -class TestFulService extends FulfillmentService { - static identifier = "test-ful" - - constructor() { - super() - } - - getFulfillmentOptions() { - return [ - { - id: "manual-fulfillment", - }, - ] - } - - validateFulfillmentData(data, cart) { - return data - } - - validateOption(data) { - return true - } - - canCalculate() { - return true - } - - calculatePrice(data) { - return data.price - } - - createOrder() { - // No data is being sent anywhere - return Promise.resolve({}) - } - - createReturn() { - return Promise.resolve({}) - } - - createFulfillment() { - // No data is being sent anywhere - return Promise.resolve({}) - } - - cancelFulfillment() { - return Promise.resolve({}) - } -} - -export default TestFulService diff --git a/integration-tests/api/src/services/test-not.js b/integration-tests/api/src/services/test-not.js deleted file mode 100644 index 39c5ba665a..0000000000 --- a/integration-tests/api/src/services/test-not.js +++ /dev/null @@ -1,19 +0,0 @@ -import { NotificationService } from "medusa-interfaces" - -class TestNotiService extends NotificationService { - static identifier = "test-not" - - constructor() { - super() - } - - async sendNotification() { - return Promise.resolve() - } - - async resendNotification() { - return Promise.resolve() - } -} - -export default TestNotiService diff --git a/integration-tests/api/src/services/test-pay.js b/integration-tests/api/src/services/test-pay.js deleted file mode 100644 index e37f3e9dab..0000000000 --- a/integration-tests/api/src/services/test-pay.js +++ /dev/null @@ -1,87 +0,0 @@ -import { AbstractPaymentService } from "@medusajs/medusa" - -class TestPayService extends AbstractPaymentService { - static identifier = "test-pay" - - constructor(_) { - super(_) - } - - async getStatus(paymentData) { - return "authorized" - } - - async retrieveSavedMethods(customer) { - return [] - } - - async createPayment(cart) { - const fields = [ - "total", - "subtotal", - "tax_total", - "discount_total", - "shipping_total", - "gift_card_total", - ] - - const data = {} - for (const k of fields) { - data[k] = cart[k] - } - - return data - } - - async createPaymentNew(inputData) { - return inputData - } - - async retrievePayment(data) { - return {} - } - - async getPaymentData(sessionData) { - return {} - } - - async authorizePayment(sessionData, context = {}) { - if ( - sessionData.cart_id === "cart-id-tax-line-testing-for-pending-payment" - ) { - return { data: {}, status: "pending" } - } - - return { data: {}, status: "authorized" } - } - - async updatePaymentData(sessionData, update) { - return {} - } - - async updatePayment(sessionData, cart) { - return {} - } - - async updatePaymentNew(sessionData) { - return sessionData - } - - async deletePayment(payment) { - return {} - } - - async capturePayment(payment) { - return {} - } - - async refundPayment(payment, amountToRefund) { - return {} - } - - async cancelPayment(payment) { - return {} - } -} - -export default TestPayService diff --git a/integration-tests/development/.env.development b/integration-tests/development/.env.development deleted file mode 100644 index fafc0177f9..0000000000 --- a/integration-tests/development/.env.development +++ /dev/null @@ -1,7 +0,0 @@ -# Default postgres credentials -DB_HOST=localhost -DB_USERNAME=postgres -DB_PASSWORD='' -DB_NAME=development - -SERVER_PORT=9000 \ No newline at end of file diff --git a/integration-tests/development/create-database.js b/integration-tests/development/create-database.js deleted file mode 100644 index 7d17619d78..0000000000 --- a/integration-tests/development/create-database.js +++ /dev/null @@ -1,31 +0,0 @@ -const path = require("path") - -require("dotenv").config({ path: path.join(__dirname, ".env.development") }) - -const { initDb } = require("./use-db-development") - -require("./dev-require") - -const seedDB = async (db) => { - const seeder = require("./database/index.js") - try { - await seeder(db) - } catch (err) { - console.log("Error", err) - } -} - -const start = async () => { - console.log("Creating DB...") - const dbConnection = await initDb() - console.log("Creating DB. DONE") - - console.log("Seeding DB...") - await seedDB(dbConnection) - console.log("Seeding DB... DONE") - - await dbConnection.close() - process.exit() -} - -start() diff --git a/integration-tests/development/database/customer.js b/integration-tests/development/database/customer.js deleted file mode 100644 index 6277fac991..0000000000 --- a/integration-tests/development/database/customer.js +++ /dev/null @@ -1,17 +0,0 @@ -const { Customer } = require("@medusajs/medusa") - -module.exports = async (connection) => { - const manager = connection.manager - - const customer = manager.create(Customer, { - id: "customer-1", - email: "test1@email.com", - first_name: "John", - last_name: "Doe", - password_hash: - "c2NyeXB0AAEAAAABAAAAAVMdaddoGjwU1TafDLLlBKnOTQga7P2dbrfgf3fB+rCD/cJOMuGzAvRdKutbYkVpuJWTU39P7OpuWNkUVoEETOVLMJafbI8qs8Qx/7jMQXkN", - // password matching "test" - has_account: true, - }) - await manager.save(customer) -} diff --git a/integration-tests/development/database/index.js b/integration-tests/development/database/index.js deleted file mode 100644 index f54eb5fd38..0000000000 --- a/integration-tests/development/database/index.js +++ /dev/null @@ -1,9 +0,0 @@ -const user = require("./user") -const region = require("./region") -const customer = require("./customer") - -module.exports = async (db) => { - await user(db) - await region(db) - await customer(db) -} diff --git a/integration-tests/development/database/region.js b/integration-tests/development/database/region.js deleted file mode 100644 index 0acf19fdca..0000000000 --- a/integration-tests/development/database/region.js +++ /dev/null @@ -1,45 +0,0 @@ -const { Region } = require("@medusajs/medusa") - -module.exports = async (connection) => { - const manager = connection.manager - - const r = manager.create(Region, { - id: "test-region", - name: "Test Region", - payment_providers: [{ id: "test-pay" }], - currency_code: "usd", - tax_rate: 0, - }) - - await manager.save(r) - - const europeRegion = manager.create(Region, { - id: "eur-region", - name: "Europe Region", - payment_providers: [{ id: "test-pay" }], - currency_code: "eur", - tax_rate: 0, - }) - - await manager.save(europeRegion) - - // Region with multiple countries - const regionWithMultipleCoutries = manager.create(Region, { - id: "test-region-multiple", - name: "Test Region", - currency_code: "eur", - tax_rate: 0, - }) - - await manager.save(regionWithMultipleCoutries) - - await manager.query( - `UPDATE "country" SET region_id='test-region-multiple' WHERE iso_2 = 'no'` - ) - await manager.query( - `UPDATE "country" SET region_id='test-region-multiple' WHERE iso_2 = 'dk'` - ) - await manager.query( - `UPDATE "country" SET region_id='test-region' WHERE iso_2 = 'us'` - ) -} diff --git a/integration-tests/development/database/user.js b/integration-tests/development/database/user.js deleted file mode 100644 index 60c1e03af5..0000000000 --- a/integration-tests/development/database/user.js +++ /dev/null @@ -1,17 +0,0 @@ -const Scrypt = require("scrypt-kdf") -const { User } = require("@medusajs/medusa") - -module.exports = async (connection) => { - const manager = connection.manager - - const buf = await Scrypt.kdf("secret_password", { logN: 1, r: 1, p: 1 }) - const password_hash = buf.toString("base64") - - await manager.insert(User, { - id: "admin_user", - email: "admin@medusa.js", - api_token: "test_token", - role: "admin", - password_hash, - }) -} diff --git a/integration-tests/development/dev-require.js b/integration-tests/development/dev-require.js deleted file mode 100644 index 19468a44dd..0000000000 --- a/integration-tests/development/dev-require.js +++ /dev/null @@ -1,69 +0,0 @@ -if (process.env.NODE_ENV !== "development") { - return -} -const path = require("path") - -const Module = require("module") -const originalRequire = Module.prototype.require -const medusaCore = path.resolve(path.join(__dirname, "../../packages")) - -function replacePath(requirePath, pack, concatPackage = true) { - const idx = requirePath.indexOf(pack) - const packPath = requirePath.substring(idx + pack.length).replace(/\\/g, "/") - - let newPath = - medusaCore + - "/" + - (concatPackage ? pack + "/" : "") + - packPath.replace("/dist", "/src").replace(".js", "") - - if (!newPath.includes("/src")) { - newPath += "/src" - } - - return path.resolve(newPath) -} - -function checkAndReplacePaths(path) { - const interfaces = "medusa-interfaces" - const utils = "medusa-core-utils" - const base = "@medusajs" - - if (path.includes(base)) { - path = replacePath(path, base, false) - } else if (path.includes(interfaces)) { - path = replacePath(path, interfaces) - } else if (path.includes(utils)) { - path = replacePath(path, utils) - } - - return path -} - -Module.prototype.require = function (...args) { - args[0] = checkAndReplacePaths(args[0]) - - if (args[0] === "glob") { - const glob = originalRequire.apply(this, args) - const originalGlobSync = glob.sync - glob.GlobSync = glob.sync = (pattern, options) => { - if (pattern.endsWith(".js") || pattern.endsWith(".ts")) { - pattern = checkAndReplacePaths(pattern) - pattern = pattern.replace(".js", ".{j,t}s").replace("/dist/", "/src/") - } - - return originalGlobSync.apply(this, [pattern, options]) - } - return glob - } else if (args[0] === "resolve-cwd") { - const resolveCwd = originalRequire.apply(this, args) - const newResolveCwd = (pattern) => { - pattern = checkAndReplacePaths(pattern) - - return resolveCwd.apply(this, [pattern]) - } - return newResolveCwd - } - - return originalRequire.apply(this, args) -} diff --git a/integration-tests/development/medusa-config.js b/integration-tests/development/medusa-config.js deleted file mode 100644 index 229df9218b..0000000000 --- a/integration-tests/development/medusa-config.js +++ /dev/null @@ -1,23 +0,0 @@ -const DB_HOST = process.env.DB_HOST -const DB_USERNAME = process.env.DB_USERNAME -const DB_PASSWORD = process.env.DB_PASSWORD -const DB_NAME = process.env.DB_NAME - -module.exports = { - plugins: [ - { - resolve: `./packages/medusa-payment-stripe`, - options: { - api_key: "api_key", - webhook_secret: "api_key", - }, - }, - ], - projectConfig: { - redis_url: process.env.REDIS_URL, - database_url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME}`, - database_type: "postgres", - jwt_secret: "test", - cookie_secret: "test", - }, -} diff --git a/integration-tests/development/server.js b/integration-tests/development/server.js deleted file mode 100644 index 9c03ab8b8e..0000000000 --- a/integration-tests/development/server.js +++ /dev/null @@ -1,155 +0,0 @@ -const path = require("path") -const express = require("express") -const importFrom = require("import-from") -const chokidar = require("chokidar") -const { WorkflowManager } = require("@medusajs/orchestration") - -process.env.DEV_MODE = !!process[Symbol.for("ts-node.register.instance")] -process.env.NODE_ENV = process.env.DEV_MODE && "development" - -require("dotenv").config({ path: path.join(__dirname, ".env.development") }) - -require("./dev-require") - -const medusaCore = path - .resolve(path.join(__dirname, "../../packages")) - .replace(/\\/g, "/") - -let WATCHING = false -let IS_RELOADING = false - -function getParentModulesIds(element) { - if (!element) { - return [] - } - - const ids = [element.id] - let parent = element.parent - while (parent && parent.id.replace(/\\/g, "/").includes(medusaCore)) { - ids.push(parent.id) - parent = parent.parent - } - return ids -} - -const watchFiles = () => { - if (WATCHING) { - return - } - WATCHING = true - - const watcher = chokidar.watch(medusaCore, { - ignored: (rawPath) => { - const path = rawPath.replace(/\\/g, "/") - if ( - path.includes("/node_modules") || - path.includes("/dist") || - path.includes("/__") || - (/\..*/i.test(path) && - !( - path.endsWith(".js") || - path.endsWith(".ts") || - path.includes("/src") - )) - ) { - return true - } - - return false - }, - }) - - watcher.on("change", async function (rawFile) { - if (IS_RELOADING) { - return - } - - console.log("Reloading server...") - IS_RELOADING = true - const start = Date.now() - - const file = rawFile.replace(/\\/g, "/") - - if (file.includes("/models") || file.includes("/repositories")) { - Object.keys(require.cache).forEach(function (id) { - const name = require.cache[id].filename - if (!name.includes("typeorm")) { - return - } - - delete require.cache[id] - }) - } - - const allModules = Object.keys(module.constructor._cache) - const path = file.split("/") - const src = path.findIndex((folder) => folder === "src") - const next = path.slice(0, src + 2).join("/") - - for (const rawName of allModules) { - const name = rawName.replace(/\\/g, "/") - if (name.includes("typeorm")) { - delete module.constructor._cache[rawName] - } else if (name.includes(medusaCore)) { - if ( - name.includes("repositories") || - name.includes("loaders") || - next.endsWith(".js") || - next.endsWith(".ts") || - name.startsWith(next) - ) { - const cacheToClean = getParentModulesIds( - module.constructor._cache[rawName] - ) - for (const id of cacheToClean) { - delete module.constructor._cache[id] - } - } - } - } - - WorkflowManager.unregisterAll() - - await bootstrapApp() - IS_RELOADING = false - - console.log("Server reloaded in", Date.now() - start, "ms") - }) -} - -let server -const bootstrapApp = async () => { - if (server) { - server.close() - } - - const app = express() - app.use((req, res, next) => { - res.header("Access-Control-Allow-Origin", req.headers.origin) - res.header("Access-Control-Allow-Methods", "*") - res.header( - "Access-Control-Allow-Headers", - "Origin, X-Requested-With, Content-Type, Accept" - ) - next() - }) - - const dir = path.resolve( - path.join(__dirname, "../../packages/medusa/src/loaders") - ) - const loaders = importFrom(dir, ".").default - - const configDir = __dirname - const { dbConnection } = await loaders({ - directory: configDir, - expressApp: app, - }) - - const port = process.env.SERVER_PORT ?? 9000 - server = app.listen(port, (err) => { - watchFiles() - console.log(`Server Running at localhost:${port}`) - }) -} - -void bootstrapApp() diff --git a/integration-tests/development/src/services/local-file-service.js b/integration-tests/development/src/services/local-file-service.js deleted file mode 100644 index 1bc25a2013..0000000000 --- a/integration-tests/development/src/services/local-file-service.js +++ /dev/null @@ -1,96 +0,0 @@ -import { AbstractFileService } from "@medusajs/medusa" -import stream from "stream" -import { resolve } from "path" -import * as fs from "fs" -import mkdirp from "mkdirp" - -export default class LocalFileService extends AbstractFileService { - constructor({}, options) { - super({}, options) - this.upload_dir_ = - process.env.UPLOAD_DIR ?? options.upload_dir ?? "uploads/images" - - if (!fs.existsSync(this.upload_dir_)) { - fs.mkdirSync(this.upload_dir_) - } - } - - upload(file) { - return new Promise((resolvePromise, reject) => { - const path = resolve(this.upload_dir_, file.originalname) - - let content = "" - if (file.filename) { - content = fs.readFileSync( - resolve(process.cwd(), "uploads", file.filename) - ) - } - - const pathSegments = path.split("/") - pathSegments.splice(-1) - const dirname = pathSegments.join("/") - mkdirp.sync(dirname, { recursive: true }) - - fs.writeFile(path, content.toString(), (err) => { - if (err) { - reject(err) - } - - resolvePromise({ url: path }) - }) - }) - } - - delete({ fileKey }) { - return new Promise((resolvePromise, reject) => { - const path = resolve(this.upload_dir_, fileKey) - fs.unlink(path, (err) => { - if (err) { - reject(err) - } - - resolvePromise("file unlinked") - }) - }) - } - - async getUploadStreamDescriptor({ name, ext }) { - const fileKey = `${name}.${ext}` - const path = resolve(this.upload_dir_, fileKey) - - const isFileExists = fs.existsSync(path) - if (!isFileExists) { - await this.upload({ originalname: fileKey }) - } - - const pass = new stream.PassThrough() - pass.pipe(fs.createWriteStream(path)) - - return { - writeStream: pass, - promise: Promise.resolve(), - url: `${this.upload_dir_}/${fileKey}`, - fileKey, - } - } - - async getDownloadStream({ fileKey }) { - return new Promise((resolvePromise, reject) => { - try { - const path = resolve(this.upload_dir_, fileKey) - const data = fs.readFileSync(path) - const readable = stream.Readable() - readable._read = function () {} - readable.push(data.toString()) - readable.push(null) - resolvePromise(readable) - } catch (e) { - reject(e) - } - }) - } - - async getPresignedDownloadUrl({ fileKey }) { - return `${this.upload_dir_}/${fileKey}` - } -} diff --git a/integration-tests/development/src/services/test-ful.js b/integration-tests/development/src/services/test-ful.js deleted file mode 100644 index 4c2f4688ee..0000000000 --- a/integration-tests/development/src/services/test-ful.js +++ /dev/null @@ -1,53 +0,0 @@ -import { FulfillmentService } from "medusa-interfaces" - -class TestFulService extends FulfillmentService { - static identifier = "test-ful" - - constructor() { - super() - } - - getFulfillmentOptions() { - return [ - { - id: "manual-fulfillment", - }, - ] - } - - validateFulfillmentData(data, cart) { - return data - } - - validateOption(data) { - return true - } - - canCalculate() { - return true - } - - calculatePrice(data) { - return data.price - } - - createOrder() { - // No data is being sent anywhere - return Promise.resolve({}) - } - - createReturn() { - return Promise.resolve({}) - } - - createFulfillment() { - // No data is being sent anywhere - return Promise.resolve({}) - } - - cancelFulfillment() { - return Promise.resolve({}) - } -} - -export default TestFulService diff --git a/integration-tests/development/src/services/test-not.js b/integration-tests/development/src/services/test-not.js deleted file mode 100644 index 39c5ba665a..0000000000 --- a/integration-tests/development/src/services/test-not.js +++ /dev/null @@ -1,19 +0,0 @@ -import { NotificationService } from "medusa-interfaces" - -class TestNotiService extends NotificationService { - static identifier = "test-not" - - constructor() { - super() - } - - async sendNotification() { - return Promise.resolve() - } - - async resendNotification() { - return Promise.resolve() - } -} - -export default TestNotiService diff --git a/integration-tests/development/src/services/test-pay.js b/integration-tests/development/src/services/test-pay.js deleted file mode 100644 index e37f3e9dab..0000000000 --- a/integration-tests/development/src/services/test-pay.js +++ /dev/null @@ -1,87 +0,0 @@ -import { AbstractPaymentService } from "@medusajs/medusa" - -class TestPayService extends AbstractPaymentService { - static identifier = "test-pay" - - constructor(_) { - super(_) - } - - async getStatus(paymentData) { - return "authorized" - } - - async retrieveSavedMethods(customer) { - return [] - } - - async createPayment(cart) { - const fields = [ - "total", - "subtotal", - "tax_total", - "discount_total", - "shipping_total", - "gift_card_total", - ] - - const data = {} - for (const k of fields) { - data[k] = cart[k] - } - - return data - } - - async createPaymentNew(inputData) { - return inputData - } - - async retrievePayment(data) { - return {} - } - - async getPaymentData(sessionData) { - return {} - } - - async authorizePayment(sessionData, context = {}) { - if ( - sessionData.cart_id === "cart-id-tax-line-testing-for-pending-payment" - ) { - return { data: {}, status: "pending" } - } - - return { data: {}, status: "authorized" } - } - - async updatePaymentData(sessionData, update) { - return {} - } - - async updatePayment(sessionData, cart) { - return {} - } - - async updatePaymentNew(sessionData) { - return sessionData - } - - async deletePayment(payment) { - return {} - } - - async capturePayment(payment) { - return {} - } - - async refundPayment(payment, amountToRefund) { - return {} - } - - async cancelPayment(payment) { - return {} - } -} - -export default TestPayService diff --git a/integration-tests/development/use-db-development.js b/integration-tests/development/use-db-development.js deleted file mode 100644 index 8cc2634b6a..0000000000 --- a/integration-tests/development/use-db-development.js +++ /dev/null @@ -1,94 +0,0 @@ -const path = require("path") - -const { DataSource } = require("typeorm") -const { getConfigFile } = require("medusa-core-utils") - -const DB_HOST = process.env.DB_HOST -const DB_USERNAME = process.env.DB_USERNAME -const DB_PASSWORD = process.env.DB_PASSWORD -const DB_NAME = process.env.DB_NAME -const DB_URL = `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME}` - -process.env.NODE_ENV = "development" - -require("./dev-require") - -async function createDB() { - const connection = new DataSource({ - type: "postgres", - url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}`, - }) - - await connection.initialize() - - await connection.query(`DROP DATABASE IF EXISTS "${DB_NAME}";`) - await connection.query(`CREATE DATABASE "${DB_NAME}";`) - await connection.destroy() -} - -module.exports = { - initDb: async function () { - const cwd = path.resolve(path.join(__dirname, "../..")) - - const { configModule } = getConfigFile( - path.join(__dirname), - `medusa-config` - ) - - const { featureFlags } = configModule - - const basePath = path.join(cwd, "packages/medusa/src") - - const featureFlagsLoader = - require("@medusajs/medusa/dist/loaders/feature-flags").default - - const featureFlagsRouter = featureFlagsLoader({ featureFlags }) - - const modelsLoader = require("@medusajs/medusa/dist/loaders/models").default - - const { - getEnabledMigrations, - getModuleSharedResources, - runIsolatedModulesMigration, - } = require("@medusajs/medusa/dist/commands/utils/get-migrations") - - const entities = modelsLoader({}, { register: false }) - - // get migraitons with enabled featureflags - const migrationDir = path.resolve( - path.join(basePath, `migrations`, `*.{j,t}s`) - ) - - const isFlagEnabled = (flag) => featureFlagsRouter.isFeatureEnabled(flag) - - const { migrations: moduleMigrations, models: moduleModels } = - getModuleSharedResources(configModule, featureFlagsRouter) - - const enabledMigrations = getEnabledMigrations( - [migrationDir], - isFlagEnabled - ) - - const enabledEntities = entities.filter( - (e) => typeof e.isFeatureEnabled === "undefined" || e.isFeatureEnabled() - ) - - await createDB() - - const dbConnection = new DataSource({ - type: "postgres", - url: DB_URL, - entities: enabledEntities.concat(moduleModels), - migrations: enabledMigrations.concat(moduleMigrations), - // logging: true, - }) - - await dbConnection.initialize() - - await dbConnection.runMigrations() - - await runIsolatedModulesMigration(configModule) - - return dbConnection - }, -} diff --git a/integration-tests/factories/simple-discount-condition-factory.ts b/integration-tests/factories/simple-discount-condition-factory.ts deleted file mode 100644 index 0a4bfb7dcc..0000000000 --- a/integration-tests/factories/simple-discount-condition-factory.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { - DiscountCondition, - DiscountConditionOperator, - DiscountConditionType, -} from "@medusajs/medusa/dist/models/discount-condition" -import { DiscountConditionCustomerGroup } from "@medusajs/medusa/dist/models/discount-condition-customer-group" -import { DiscountConditionProduct } from "@medusajs/medusa/dist/models/discount-condition-product" -import { DiscountConditionProductCollection } from "@medusajs/medusa/dist/models/discount-condition-product-collection" -import { DiscountConditionProductTag } from "@medusajs/medusa/dist/models/discount-condition-product-tag" -import { DiscountConditionProductType } from "@medusajs/medusa/dist/models/discount-condition-product-type" -import { DiscountConditionJoinTableForeignKey } from "@medusajs/medusa/dist/repositories/discount-condition" -import faker from "faker" -import { DataSource } from "typeorm" - -export type DiscountConditionFactoryData = { - id?: string - rule_id: string - type: DiscountConditionType - operator: DiscountConditionOperator - products: string[] - product_collections: string[] - product_types: string[] - product_tags: string[] - customer_groups: string[] -} - -const getJoinTableResourceIdentifiers = (type: string) => { - let conditionTable: any - let resourceKey - - switch (type) { - case DiscountConditionType.PRODUCTS: { - resourceKey = DiscountConditionJoinTableForeignKey.PRODUCT_ID - conditionTable = DiscountConditionProduct - break - } - case DiscountConditionType.PRODUCT_TYPES: { - resourceKey = DiscountConditionJoinTableForeignKey.PRODUCT_TYPE_ID - conditionTable = DiscountConditionProductType - break - } - case DiscountConditionType.PRODUCT_COLLECTIONS: { - resourceKey = DiscountConditionJoinTableForeignKey.PRODUCT_COLLECTION_ID - conditionTable = DiscountConditionProductCollection - break - } - case DiscountConditionType.PRODUCT_TAGS: { - resourceKey = DiscountConditionJoinTableForeignKey.PRODUCT_TAG_ID - - conditionTable = DiscountConditionProductTag - break - } - case DiscountConditionType.CUSTOMER_GROUPS: { - resourceKey = DiscountConditionJoinTableForeignKey.CUSTOMER_GROUP_ID - conditionTable = DiscountConditionCustomerGroup - break - } - default: - break - } - - return { - resourceKey, - conditionTable, - } -} - -export const simpleDiscountConditionFactory = async ( - dataSource: DataSource, - data: DiscountConditionFactoryData, - seed?: number -): Promise => { - if (typeof seed !== "undefined") { - faker.seed(seed) - } - - const manager = dataSource.manager - - let resources = [] - - if (data.products) { - resources = data.products - } - if (data.product_collections) { - resources = data.product_collections - } - if (data.product_types) { - resources = data.product_types - } - if (data.product_tags) { - resources = data.product_tags - } - if (data.customer_groups) { - resources = data.customer_groups - } - - const toCreate = { - type: data.type, - operator: data.operator, - discount_rule_id: data.rule_id, - } - - if (data.id) { - toCreate["id"] = data.id - } - - const condToSave = manager.create(DiscountCondition, toCreate) - - const { conditionTable, resourceKey } = getJoinTableResourceIdentifiers( - data.type - ) - - const condition = await manager.save(condToSave) - - for (const resourceCond of resources) { - const toSave = manager.create(conditionTable, { - [resourceKey]: resourceCond, - condition_id: condition.id, - }) - - await manager.save(toSave) - } -} diff --git a/integration-tests/factories/simple-discount-factory.ts b/integration-tests/factories/simple-discount-factory.ts index 8495c3038b..01a58c5b06 100644 --- a/integration-tests/factories/simple-discount-factory.ts +++ b/integration-tests/factories/simple-discount-factory.ts @@ -6,16 +6,11 @@ import { } from "@medusajs/medusa" import faker from "faker" import { DataSource } from "typeorm" -import { - DiscountConditionFactoryData, - simpleDiscountConditionFactory, -} from "./simple-discount-condition-factory" export type DiscountRuleFactoryData = { type?: DiscountRuleType value?: number allocation?: AllocationType - conditions: DiscountConditionFactoryData[] } export type DiscountFactoryData = { @@ -48,16 +43,6 @@ export const simpleDiscountFactory = async ( const dRule = await manager.save(ruleToSave) - if (data?.rule?.conditions) { - for (const condition of data.rule.conditions) { - await simpleDiscountConditionFactory( - dataSource, - { ...condition, rule_id: dRule.id }, - 1 - ) - } - } - const toSave = manager.create(Discount, { id: data.id, is_dynamic: data.is_dynamic ?? false, diff --git a/integration-tests/helpers/admin-seeder.js b/integration-tests/helpers/admin-seeder.js index 25a49b64a7..d583fed89d 100644 --- a/integration-tests/helpers/admin-seeder.js +++ b/integration-tests/helpers/admin-seeder.js @@ -1,5 +1,4 @@ const Scrypt = require("scrypt-kdf") -const { User } = require("@medusajs/medusa/dist/models/user") module.exports = async (dataSource, data = {}) => { const manager = dataSource.manager @@ -7,7 +6,7 @@ module.exports = async (dataSource, data = {}) => { const buf = await Scrypt.kdf("secret_password", { logN: 15, r: 8, p: 1 }) const password_hash = buf.toString("base64") - const user = await manager.insert(User, { + const user = await manager.insert("user", { id: "admin_user", email: "admin@medusa.js", api_token: "test_token", diff --git a/integration-tests/modules/__tests__/link-modules/shipping-option-price-set.spec.ts b/integration-tests/modules/__tests__/link-modules/shipping-option-price-set.spec.ts index 383606f700..83b739083a 100644 --- a/integration-tests/modules/__tests__/link-modules/shipping-option-price-set.spec.ts +++ b/integration-tests/modules/__tests__/link-modules/shipping-option-price-set.spec.ts @@ -118,7 +118,7 @@ medusaIntegrationTestRunner({ price_set_id: priceSet.id, shipping_option_id: shippingOption.id, }), - prices: [ + prices: expect.arrayContaining([ expect.objectContaining({ amount: 5000, currency_code: "eur", @@ -127,7 +127,7 @@ medusaIntegrationTestRunner({ amount: 3000, currency_code: "usd", }), - ], + ]), calculated_price: expect.objectContaining({ calculated_amount: 5000, currency_code: "eur", diff --git a/integration-tests/modules/__tests__/price-lists/admin/price-lists.spec.ts b/integration-tests/modules/__tests__/price-lists/admin/price-lists.spec.ts index 33aef26893..b6eef241e2 100644 --- a/integration-tests/modules/__tests__/price-lists/admin/price-lists.spec.ts +++ b/integration-tests/modules/__tests__/price-lists/admin/price-lists.spec.ts @@ -548,7 +548,8 @@ medusaIntegrationTestRunner({ }) describe("POST /admin/price-lists/:id/prices/batch", () => { - it("should add, remove and delete price list prices in batch successfully", async () => { + // TODO: This is flaky, investigate why + it.skip("should add, remove and delete price list prices in batch successfully", async () => { const priceSet = await createVariantPriceSet({ container: appContainer, variantId: variant.id, diff --git a/integration-tests/modules/__tests__/product/admin/index.ts b/integration-tests/modules/__tests__/product/admin/index.ts index bf91a6257c..d033e24ec5 100644 --- a/integration-tests/modules/__tests__/product/admin/index.ts +++ b/integration-tests/modules/__tests__/product/admin/index.ts @@ -4,7 +4,6 @@ import { useApi } from "../../../../environment-helpers/use-api" import { initDb, useDb } from "../../../../environment-helpers/use-db" import adminSeeder from "../../../../helpers/admin-seeder" -import productSeeder from "../../../../helpers/product-seeder" import { Modules, ModulesDefinition } from "@medusajs/modules-sdk" import { MedusaV2Flag } from "@medusajs/utils" @@ -68,7 +67,6 @@ describe.skip("/admin/products", () => { describe("POST /admin/products", () => { beforeEach(async () => { - await productSeeder(dbConnection) await adminSeeder(dbConnection) await createDefaultRuleTypes(medusaContainer) diff --git a/integration-tests/modules/__tests__/workflow-engine/api.ts b/integration-tests/modules/__tests__/workflow-engine/api.ts deleted file mode 100644 index 7498e32e30..0000000000 --- a/integration-tests/modules/__tests__/workflow-engine/api.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { workflowEngineTestSuite } from "./tests" - -jest.setTimeout(5000000) - -const env = { - MEDUSA_FF_MEDUSA_V2: false, -} - -workflowEngineTestSuite(env, { force_modules_migration: true }) diff --git a/integration-tests/plugins/.babelrc.js b/integration-tests/plugins/.babelrc.js deleted file mode 100644 index bde709c495..0000000000 --- a/integration-tests/plugins/.babelrc.js +++ /dev/null @@ -1,13 +0,0 @@ -let ignore = [`**/dist`] - -// Jest needs to compile this code, but generally we don't want this copied -// to output folders -if (process.env.NODE_ENV !== `test`) { - ignore.push(`**/__tests__`) -} - -module.exports = { - sourceMaps: true, - presets: ["babel-preset-medusa-package"], - ignore, -} diff --git a/integration-tests/plugins/.gitignore b/integration-tests/plugins/.gitignore deleted file mode 100644 index a2c424c876..0000000000 --- a/integration-tests/plugins/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -dist/ -node_modules -*yarn-error.log - diff --git a/integration-tests/plugins/__tests__/cart/store/ff-medusa-v2.ts b/integration-tests/plugins/__tests__/cart/store/ff-medusa-v2.ts deleted file mode 100644 index 6bffbb66b0..0000000000 --- a/integration-tests/plugins/__tests__/cart/store/ff-medusa-v2.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { Region } from "@medusajs/medusa" -import path from "path" -import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" -import { useApi } from "../../../../environment-helpers/use-api" -import { initDb, useDb } from "../../../../environment-helpers/use-db" -import { - simpleProductFactory, - simpleSalesChannelFactory, -} from "../../../../factories" - -jest.setTimeout(30000) - -const env = { - MEDUSA_FF_MEDUSA_V2: true, -} - -describe.skip("/store/carts", () => { - let dbConnection - let shutdownServer - - const doAfterEach = async () => { - const db = useDb() - return await db.teardown() - } - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd, env } as any) - shutdownServer = await startBootstrapApp({ cwd, env }) - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - describe("POST /store/carts", () => { - let prod1 - let prodSale - - beforeEach(async () => { - const manager = dbConnection.manager - await manager.insert(Region, { - id: "region", - name: "Test Region", - currency_code: "usd", - tax_rate: 0, - }) - - await manager.query( - `UPDATE "country" - SET region_id='region' - WHERE iso_2 = 'us'` - ) - - prod1 = await simpleProductFactory(dbConnection, { - id: "test-product", - variants: [{ id: "test-variant_1" }], - }) - - prodSale = await simpleProductFactory(dbConnection, { - id: "test-product-sale", - variants: [ - { - id: "test-variant-sale", - prices: [{ amount: 1000, currency: "usd" }], - }, - ], - }) - - await simpleSalesChannelFactory(dbConnection, { - id: "amazon-sc", - name: "Amazon store", - }) - }) - - afterEach(async () => { - await doAfterEach() - }) - - it("should create a cart in a sales channel", async () => { - const api = useApi() - - const response = await api.post("/store/carts", { - sales_channel_id: "amazon-sc", - }) - - expect(response.status).toEqual(200) - - const getRes = await api.get(`/store/carts/${response.data.cart.id}`) - expect(getRes.status).toEqual(200) - expect(getRes.data.cart.sales_channel.id).toEqual("amazon-sc") - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/cart/store/index.ts b/integration-tests/plugins/__tests__/cart/store/index.ts deleted file mode 100644 index 0c892a959d..0000000000 --- a/integration-tests/plugins/__tests__/cart/store/index.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { - MoneyAmount, - PriceList, - ProductVariantMoneyAmount, - Region, -} from "@medusajs/medusa" -import path from "path" -import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" -import { useApi } from "../../../../environment-helpers/use-api" -import { initDb, useDb } from "../../../../environment-helpers/use-db" -import { simpleProductFactory } from "../../../../factories" - -jest.setTimeout(30000) - -describe("/store/carts", () => { - let dbConnection - let shutdownServer - - const doAfterEach = async () => { - const db = useDb() - return await db.teardown() - } - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd } as any) - shutdownServer = await startBootstrapApp({ cwd }) - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - describe("POST /store/carts", () => { - let prod1 - let prodSale - - beforeEach(async () => { - const manager = dbConnection.manager - await manager.insert(Region, { - id: "region", - name: "Test Region", - currency_code: "usd", - tax_rate: 0, - }) - - await manager.query( - `UPDATE "country" - SET region_id='region' - WHERE iso_2 = 'us'` - ) - - prod1 = await simpleProductFactory(dbConnection, { - id: "test-product", - variants: [{ id: "test-variant_1" }], - }) - - prodSale = await simpleProductFactory(dbConnection, { - id: "test-product-sale", - variants: [ - { - id: "test-variant-sale", - prices: [{ amount: 1000, currency: "usd" }], - }, - ], - }) - }) - - afterEach(async () => { - await doAfterEach() - }) - - it("should create a cart", async () => { - const api = useApi() - const response = await api.post("/store/carts") - - expect(response.status).toEqual(200) - - const getRes = await api.post(`/store/carts/${response.data.cart.id}`) - expect(getRes.status).toEqual(200) - }) - - it("should fail to create a cart when no region exist", async () => { - const api = useApi() - - await dbConnection.manager.query( - `UPDATE "country" - SET region_id=null - WHERE iso_2 = 'us'` - ) - - await dbConnection.manager.query(`DELETE from region`) - - try { - await api.post("/store/carts") - } catch (error) { - expect(error.response.status).toEqual(400) - expect(error.response.data.message).toEqual( - "A region is required to create a cart" - ) - } - }) - - it("should create a cart with items", async () => { - const yesterday = ((today) => - new Date(today.setDate(today.getDate() - 1)))(new Date()) - const tomorrow = ((today) => - new Date(today.setDate(today.getDate() + 1)))(new Date()) - - const priceList1 = await dbConnection.manager.create(PriceList, { - id: "pl_current", - name: "Past winter sale", - description: "Winter sale for key accounts.", - type: "sale", - status: "active", - starts_at: yesterday, - ends_at: tomorrow, - }) - - await dbConnection.manager.save(priceList1) - - const ma_sale_1 = dbConnection.manager.create(MoneyAmount, { - currency_code: "usd", - amount: 800, - price_list_id: "pl_current", - }) - - await dbConnection.manager.save(ma_sale_1) - - await dbConnection.manager.insert(ProductVariantMoneyAmount, { - id: "pvma-test", - variant_id: prodSale.variants[0].id, - money_amount_id: ma_sale_1.id, - }) - - const api = useApi() - - const response = await api - .post("/store/carts", { - items: [ - { - variant_id: prod1.variants[0].id, - quantity: 1, - }, - { - variant_id: prodSale.variants[0].id, - quantity: 2, - }, - ], - }) - .catch((err) => console.log(err)) - - response.data.cart.items.sort((a, b) => a.quantity - b.quantity) - - expect(response.status).toEqual(200) - expect(response.data.cart.items).toHaveLength(2) - expect(response.data.cart.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - variant_id: prod1.variants[0].id, - quantity: 1, - }), - expect.objectContaining({ - variant_id: prodSale.variants[0].id, - quantity: 2, - unit_price: 800, - }), - ]) - ) - - const getRes = await api.post(`/store/carts/${response.data.cart.id}`) - expect(getRes.status).toEqual(200) - }) - - it("should create a cart with country", async () => { - const api = useApi() - const response = await api.post("/store/carts", { - country_code: "us", - }) - - expect(response.status).toEqual(200) - expect(response.data.cart.shipping_address.country_code).toEqual("us") - - const getRes = await api.post(`/store/carts/${response.data.cart.id}`) - expect(getRes.status).toEqual(200) - }) - - it("should create a cart with context", async () => { - const api = useApi() - - const response = await api.post("/store/carts", { - context: { - test_id: "test", - }, - }) - - expect(response.status).toEqual(200) - - const getRes = await api.post(`/store/carts/${response.data.cart.id}`) - expect(getRes.status).toEqual(200) - - const cart = getRes.data.cart - expect(cart.context).toEqual({ - ip: expect.any(String), - user_agent: expect.stringContaining("axios/0.21."), - test_id: "test", - }) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/cart/cart.js b/integration-tests/plugins/__tests__/inventory/cart/cart.js deleted file mode 100644 index 3f5c08dd2a..0000000000 --- a/integration-tests/plugins/__tests__/inventory/cart/cart.js +++ /dev/null @@ -1,362 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") -const cartSeeder = require("../../../../helpers/cart-seeder") -const { simpleProductFactory } = require("../../../../factories") -const { simpleSalesChannelFactory } = require("../../../../factories") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") - -jest.setTimeout(60000) - -const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } - -describe("/store/carts", () => { - let shutdownServer - let appContainer - let dbConnection - - let variantId - let inventoryItemId - let locationId - - const doAfterEach = async () => { - const db = useDb() - return await db.teardown() - } - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - describe("POST /store/carts/:id", () => { - beforeEach(async () => { - await simpleSalesChannelFactory(dbConnection, { - id: "test-channel", - is_default: true, - }) - - await adminSeeder(dbConnection) - await cartSeeder(dbConnection, { sales_channel_id: "test-channel" }) - - await simpleProductFactory( - dbConnection, - { - id: "product1", - sales_channels: [{ id: "test-channel" }], - variants: [], - }, - 100 - ) - - const api = useApi() - - // Add payment provider - await api.post( - `/admin/regions/test-region/payment-providers`, - { - provider_id: "test-pay", - }, - adminHeaders - ) - - const prodVarInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - - const response = await api.post( - `/admin/products/product1/variants`, - { - title: "Test Variant w. inventory", - sku: "MY_SKU", - material: "material", - origin_country: "UK", - hs_code: "hs001", - mid_code: "mids", - weight: 300, - length: 100, - height: 200, - width: 150, - options: [ - { - option_id: "product1-option", - value: "SS", - }, - ], - manage_inventory: true, - prices: [{ currency_code: "usd", amount: 2300 }], - }, - adminHeaders - ) - - const variant = response.data.product.variants[0] - - variantId = variant.id - - const inventoryItems = - await prodVarInventoryService.listInventoryItemsByVariant(variantId) - - inventoryItemId = inventoryItems[0].id - - // Add Stock location - const stockRes = await api.post( - `/admin/stock-locations`, - { - name: "Fake Warehouse", - }, - adminHeaders - ) - locationId = stockRes.data.stock_location.id - - // Add stock level - await api.post( - `/admin/inventory-items/${inventoryItemId}/location-levels`, - { - location_id: locationId, - stocked_quantity: 5, - }, - adminHeaders - ) - - // Associate Stock Location with sales channel - await api.post( - `/admin/sales-channels/test-channel/stock-locations`, - { - location_id: locationId, - }, - adminHeaders - ) - }) - - afterEach(async () => { - await doAfterEach() - }) - - it("reserve quantity when completing the cart", async () => { - const api = useApi() - - const cartId = "test-cart" - - // Add standard line item to cart - await api.post( - `/store/carts/${cartId}/line-items`, - { - variant_id: variantId, - quantity: 3, - }, - { withCredentials: true } - ) - - await api.post(`/store/carts/${cartId}/payment-sessions`) - await api.post(`/store/carts/${cartId}/payment-session`, { - provider_id: "test-pay", - }) - - const getRes = await api.post(`/store/carts/${cartId}/complete`) - - expect(getRes.status).toEqual(200) - expect(getRes.data.type).toEqual("order") - - const inventoryService = appContainer.resolve("inventoryService") - const stockLevel = await inventoryService.retrieveInventoryLevel( - inventoryItemId, - locationId - ) - - expect(stockLevel.location_id).toEqual(locationId) - expect(stockLevel.inventory_item_id).toEqual(inventoryItemId) - expect(stockLevel.reserved_quantity).toEqual(3) - expect(stockLevel.stocked_quantity).toEqual(5) - }) - - it("removes reserved quantity when failing to complete the cart", async () => { - const api = useApi() - - const cartRes = await api.post( - `/store/carts`, - { - region_id: "test-region", - items: [ - { - variant_id: variantId, - quantity: 3, - }, - ], - }, - { withCredentials: true } - ) - - const cartId = cartRes.data.cart.id - - await api.post(`/store/carts/${cartId}/payment-sessions`) - await api.post(`/store/carts/${cartId}/payment-session`, { - provider_id: "test-pay", - }) - - const getRes = await api - .post(`/store/carts/${cartId}/complete`) - .catch((err) => err) - - expect(getRes.response.status).toEqual(400) - expect(getRes.response.data).toEqual({ - type: "invalid_data", - message: "Cannot create an order from the cart without a customer", - }) - - const inventoryService = appContainer.resolve("inventoryService") - const [, count] = await inventoryService.listReservationItems({ - line_item_id: cartRes.data.cart.items.map((i) => i.id), - }) - expect(count).toEqual(0) - }) - - it("should decorate line item variant inventory_quantity when creating a line-item", async () => { - const api = useApi() - - const cartId = "test-cart" - - // Add standard line item to cart - const addCart = await api - .post( - `/store/carts/${cartId}/line-items`, - { - variant_id: variantId, - quantity: 3, - }, - { withCredentials: true } - ) - .catch((e) => e) - - expect(addCart.status).toEqual(200) - expect(addCart.data.cart.items[0].variant.inventory_quantity).toEqual(5) - }) - - it("should decorate line item variant inventory_quantity when getting cart", async () => { - const api = useApi() - - const cartId = "test-cart" - - // Add standard line item to cart - await api - .post( - `/store/carts/${cartId}/line-items`, - { - variant_id: variantId, - quantity: 3, - }, - { withCredentials: true } - ) - .catch((e) => e) - - const cartResponse = await api - .get(`/store/carts/${cartId}`, { withCredentials: true }) - .catch((e) => e) - - expect(cartResponse.status).toEqual(200) - expect( - cartResponse.data.cart.items[0].variant.inventory_quantity - ).toEqual(5) - }) - - it("fails to add a item on the cart if the inventory isn't enough", async () => { - const api = useApi() - - const cartId = "test-cart" - - // Add standard line item to cart - const addCart = await api - .post( - `/store/carts/${cartId}/line-items`, - { - variant_id: variantId, - quantity: 6, - }, - { withCredentials: true } - ) - .catch((e) => e) - - expect(addCart.response.status).toEqual(400) - expect(addCart.response.data.code).toEqual("insufficient_inventory") - expect(addCart.response.data.message).toEqual( - `Variant with id: ${variantId} does not have the required inventory` - ) - }) - - it("fails to complete cart with items inventory not covered", async () => { - const api = useApi() - - const cartId = "test-cart" - - // Add standard line item to cart - await api.post( - `/store/carts/${cartId}/line-items`, - { - variant_id: variantId, - quantity: 5, - }, - { withCredentials: true } - ) - - await api.post(`/store/carts/${cartId}/payment-sessions`) - await api.post(`/store/carts/${cartId}/payment-session`, { - provider_id: "test-pay", - }) - - // Another proccess reserves items before the cart is completed - const inventoryService = appContainer.resolve("inventoryService") - inventoryService.createReservationItem({ - line_item_id: "line_item_123", - inventory_item_id: inventoryItemId, - location_id: locationId, - quantity: 2, - }) - - const completeCartRes = await api - .post(`/store/carts/${cartId}/complete`) - .catch((e) => e) - - expect(completeCartRes.response.status).toEqual(409) - expect(completeCartRes.response.data.errors[0].code).toEqual( - "insufficient_inventory" - ) - expect(completeCartRes.response.data.errors[0].message).toEqual( - `Variant with id: ${variantId} does not have the required inventory` - ) - - const stockLevel = await inventoryService.retrieveInventoryLevel( - inventoryItemId, - locationId - ) - - expect(stockLevel.location_id).toEqual(locationId) - expect(stockLevel.inventory_item_id).toEqual(inventoryItemId) - expect(stockLevel.reserved_quantity).toEqual(2) - expect(stockLevel.stocked_quantity).toEqual(5) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/inventory-items/ff-many-to-many.js b/integration-tests/plugins/__tests__/inventory/inventory-items/ff-many-to-many.js deleted file mode 100644 index 7e584d277f..0000000000 --- a/integration-tests/plugins/__tests__/inventory/inventory-items/ff-many-to-many.js +++ /dev/null @@ -1,86 +0,0 @@ -const path = require("path") -const { ProductVariantInventoryService } = require("@medusajs/medusa") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") - -jest.setTimeout(30000) - -const { - getContainer, -} = require("../../../../environment-helpers/use-container") -const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } - -describe("Inventory Items endpoints", () => { - let appContainer - let dbConnection - let shutdownServer - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - - // Set feature flag - const flagRouter = appContainer.resolve("featureFlagRouter") - flagRouter.setFlag("many_to_many_inventory", true) - }) - - afterAll(async () => { - const flagRouter = appContainer.resolve("featureFlagRouter") - flagRouter.setFlag("many_to_many_inventory", false) - - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - beforeEach(async () => { - await adminSeeder(dbConnection) - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - describe("Inventory Items", () => { - it("should create inventory item without variant id", async () => { - const api = useApi() - - await api.post( - `/admin/inventory-items`, - { - sku: "TABLE_LEG", - description: "Table Leg", - }, - adminHeaders - ) - - /** @type {ProductVariantInventoryService} */ - const productVariantInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - - const inventoryService = appContainer.resolve("inventoryService") - const inventoryItems = await inventoryService.list() - - expect(inventoryItems.length).toEqual(1) - - const variants = await productVariantInventoryService.listByItem([ - inventoryItems[0].id, - ]) - expect(variants.length).toEqual(0) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/inventory-items/index.js b/integration-tests/plugins/__tests__/inventory/inventory-items/index.js deleted file mode 100644 index 1494044f9e..0000000000 --- a/integration-tests/plugins/__tests__/inventory/inventory-items/index.js +++ /dev/null @@ -1,1083 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") - -jest.setTimeout(30000) - -const { - simpleProductFactory, - simpleOrderFactory, -} = require("../../../../factories") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") -const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } - -describe("Inventory Items endpoints", () => { - let appContainer - let dbConnection - let shutdownServer - - let variantId - let inventoryItems - let locationId - let location2Id - let location3Id - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - beforeEach(async () => { - // create inventory item - await adminSeeder(dbConnection) - - const api = useApi() - - await simpleProductFactory( - dbConnection, - { - id: "test-product", - variants: [], - }, - 100 - ) - - const prodVarInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - - const response = await api.post( - `/admin/products/test-product/variants`, - { - title: "Test Variant w. inventory", - sku: "MY_SKU", - material: "material", - origin_country: "UK", - hs_code: "hs001", - mid_code: "mids", - weight: 300, - length: 100, - height: 200, - width: 150, - manage_inventory: true, - options: [ - { - option_id: "test-product-option", - value: "SS", - }, - ], - prices: [{ currency_code: "usd", amount: 2300 }], - }, - adminHeaders - ) - - const variant = response.data.product.variants[0] - - variantId = variant.id - - inventoryItems = await prodVarInventoryService.listInventoryItemsByVariant( - variantId - ) - - const stockRes = await api.post( - `/admin/stock-locations`, - { - name: "Fake Warehouse", - }, - adminHeaders - ) - locationId = stockRes.data.stock_location.id - - const secondStockRes = await api.post( - `/admin/stock-locations`, - { - name: "Another random Warehouse", - }, - adminHeaders - ) - location2Id = secondStockRes.data.stock_location.id - - const thirdStockRes = await api.post( - `/admin/stock-locations`, - { - name: "Another random Warehouse", - }, - adminHeaders - ) - location3Id = thirdStockRes.data.stock_location.id - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - describe("Inventory Items", () => { - it("should create, update and delete the inventory location levels", async () => { - const api = useApi() - const inventoryItemId = inventoryItems[0].id - - await api.post( - `/admin/inventory-items/${inventoryItemId}/location-levels`, - { - location_id: locationId, - stocked_quantity: 17, - incoming_quantity: 2, - }, - adminHeaders - ) - - const inventoryService = appContainer.resolve("inventoryService") - const stockLevel = await inventoryService.retrieveInventoryLevel( - inventoryItemId, - locationId - ) - - expect(stockLevel.location_id).toEqual(locationId) - expect(stockLevel.inventory_item_id).toEqual(inventoryItemId) - expect(stockLevel.stocked_quantity).toEqual(17) - expect(stockLevel.incoming_quantity).toEqual(2) - - await api.post( - `/admin/inventory-items/${inventoryItemId}/location-levels/${locationId}`, - { - stocked_quantity: 21, - incoming_quantity: 0, - }, - adminHeaders - ) - - const newStockLevel = await inventoryService.retrieveInventoryLevel( - inventoryItemId, - locationId - ) - expect(newStockLevel.stocked_quantity).toEqual(21) - expect(newStockLevel.incoming_quantity).toEqual(0) - - await api.delete( - `/admin/inventory-items/${inventoryItemId}/location-levels/${locationId}`, - adminHeaders - ) - const invLevel = await inventoryService - .retrieveInventoryLevel(inventoryItemId, locationId) - .catch((e) => e) - - expect(invLevel.message).toEqual( - `Inventory level for item ${inventoryItemId} and location ${locationId} not found` - ) - }) - - it("should update the inventory item", async () => { - const api = useApi() - const inventoryItemId = inventoryItems[0].id - - const response = await api.post( - `/admin/inventory-items/${inventoryItemId}`, - { - mid_code: "updated mid_code", - weight: 120, - }, - adminHeaders - ) - - expect(response.data.inventory_item).toEqual( - expect.objectContaining({ - origin_country: "UK", - hs_code: "hs001", - mid_code: "updated mid_code", - weight: 120, - length: 100, - height: 200, - width: 150, - }) - ) - }) - - it("should fail to update the location level to negative quantity", async () => { - const api = useApi() - - const inventoryItemId = inventoryItems[0].id - - await api.post( - `/admin/inventory-items/${inventoryItemId}/location-levels`, - { - location_id: locationId, - stocked_quantity: 17, - incoming_quantity: 2, - }, - adminHeaders - ) - - const res = await api - .post( - `/admin/inventory-items/${inventoryItemId}/location-levels/${locationId}`, - { - incoming_quantity: -1, - stocked_quantity: -1, - }, - adminHeaders - ) - .catch((error) => error) - - expect(res.response.status).toEqual(400) - expect(res.response.data).toEqual({ - type: "invalid_data", - message: - "incoming_quantity must not be less than 0, stocked_quantity must not be less than 0", - }) - }) - - it("should retrieve the inventory item", async () => { - const api = useApi() - const inventoryItemId = inventoryItems[0].id - - await api.post( - `/admin/inventory-items/${inventoryItemId}/location-levels`, - { - location_id: locationId, - stocked_quantity: 15, - incoming_quantity: 5, - }, - adminHeaders - ) - - await api.post( - `/admin/inventory-items/${inventoryItemId}/location-levels`, - { - location_id: location2Id, - stocked_quantity: 7, - incoming_quantity: 0, - }, - adminHeaders - ) - - const response = await api.get( - `/admin/inventory-items/${inventoryItemId}`, - adminHeaders - ) - - expect(response.data).toEqual({ - inventory_item: expect.objectContaining({ - height: 200, - hs_code: "hs001", - id: inventoryItemId, - length: 100, - location_levels: [ - expect.objectContaining({ - available_quantity: 15, - deleted_at: null, - id: expect.any(String), - incoming_quantity: 5, - inventory_item_id: inventoryItemId, - location_id: locationId, - metadata: null, - reserved_quantity: 0, - stocked_quantity: 15, - }), - expect.objectContaining({ - available_quantity: 7, - deleted_at: null, - id: expect.any(String), - incoming_quantity: 0, - inventory_item_id: inventoryItemId, - location_id: location2Id, - metadata: null, - reserved_quantity: 0, - stocked_quantity: 7, - }), - ], - material: "material", - metadata: null, - mid_code: "mids", - origin_country: "UK", - requires_shipping: true, - sku: "MY_SKU", - weight: 300, - width: 150, - }), - }) - }) - - it("should create the inventory item using the api", async () => { - const product = await simpleProductFactory(dbConnection, {}) - - const api = useApi() - - const productRes = await api.get( - `/admin/products/${product.id}`, - adminHeaders - ) - - const variantId = productRes.data.product.variants[0].id - - let variantInventoryRes = await api.get( - `/admin/variants/${variantId}/inventory`, - adminHeaders - ) - - expect(variantInventoryRes.data).toEqual({ - variant: { - id: variantId, - inventory: [], - sales_channel_availability: [], - }, - }) - expect(variantInventoryRes.status).toEqual(200) - - const inventoryItemCreateRes = await api.post( - `/admin/inventory-items`, - { variant_id: variantId, sku: "attach_this_to_variant" }, - adminHeaders - ) - - variantInventoryRes = await api.get( - `/admin/variants/${variantId}/inventory`, - adminHeaders - ) - - expect(variantInventoryRes.data).toEqual({ - variant: expect.objectContaining({ - id: variantId, - inventory: [ - expect.objectContaining({ - ...inventoryItemCreateRes.data.inventory_item, - }), - ], - }), - }) - expect(variantInventoryRes.status).toEqual(200) - }) - - it("should list the location levels based on id param constraint", async () => { - const api = useApi() - const inventoryItemId = inventoryItems[0].id - - await api.post( - `/admin/inventory-items/${inventoryItemId}/location-levels`, - { - location_id: location2Id, - stocked_quantity: 10, - }, - adminHeaders - ) - - await api.post( - `/admin/inventory-items/${inventoryItemId}/location-levels`, - { - location_id: location3Id, - stocked_quantity: 5, - }, - adminHeaders - ) - - const result = await api.get( - `/admin/inventory-items/${inventoryItemId}/location-levels?location_id[]=${location2Id}`, - adminHeaders - ) - - expect(result.status).toEqual(200) - expect(result.data.inventory_item.location_levels).toHaveLength(1) - expect(result.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 10, - }) - ) - }) - - describe("List inventory items", () => { - it("should list inventory items with location", async () => { - const api = useApi() - - await api.post( - `/admin/products/test-product/variants`, - { - title: "Test Variant w. inventory 2", - sku: "MY_SKU1", - material: "material", - origin_country: "UK", - manage_inventory: true, - options: [ - { - option_id: "test-product-option", - value: "M", - }, - ], - prices: [{ currency_code: "usd", amount: 200 }], - }, - adminHeaders - ) - - const inventoryItemId = inventoryItems[0].id - - await api.post( - `/admin/inventory-items/${inventoryItemId}/location-levels`, - { - location_id: location3Id, - stocked_quantity: 5, - }, - adminHeaders - ) - - const unfilteredResponse = await api.get( - `/admin/inventory-items`, - adminHeaders - ) - expect(unfilteredResponse.data.inventory_items).toHaveLength(2) - - const response = await api.get( - `/admin/inventory-items?location_id=${location3Id}`, - adminHeaders - ) - - expect(response.data.inventory_items).toHaveLength(1) - expect(response.data.inventory_items[0]).toEqual( - expect.objectContaining({ - id: inventoryItemId, - sku: "MY_SKU", - }) - ) - }) - - it("should list the inventory items", async () => { - const api = useApi() - const inventoryItemId = inventoryItems[0].id - - await api.post( - `/admin/inventory-items/${inventoryItemId}/location-levels`, - { - location_id: location2Id, - stocked_quantity: 10, - }, - adminHeaders - ) - - await api.post( - `/admin/inventory-items/${inventoryItemId}/location-levels`, - { - location_id: location3Id, - stocked_quantity: 5, - }, - adminHeaders - ) - - const response = await api.get(`/admin/inventory-items`, adminHeaders) - - expect(response.data.inventory_items).toHaveLength(1) - expect(response.data.inventory_items[0]).toEqual( - expect.objectContaining({ - id: inventoryItemId, - sku: "MY_SKU", - origin_country: "UK", - hs_code: "hs001", - mid_code: "mids", - material: "material", - weight: 300, - length: 100, - height: 200, - width: 150, - requires_shipping: true, - metadata: null, - variants: expect.arrayContaining([ - expect.objectContaining({ - id: variantId, - title: "Test Variant w. inventory", - product_id: "test-product", - sku: "MY_SKU", - manage_inventory: true, - hs_code: "hs001", - origin_country: "UK", - mid_code: "mids", - material: "material", - weight: 300, - length: 100, - height: 200, - width: 150, - metadata: null, - product: expect.objectContaining({ - id: "test-product", - }), - }), - ]), - location_levels: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(String), - inventory_item_id: inventoryItemId, - location_id: location2Id, - stocked_quantity: 10, - reserved_quantity: 0, - incoming_quantity: 0, - metadata: null, - available_quantity: 10, - }), - expect.objectContaining({ - id: expect.any(String), - inventory_item_id: inventoryItemId, - location_id: location3Id, - stocked_quantity: 5, - reserved_quantity: 0, - incoming_quantity: 0, - metadata: null, - available_quantity: 5, - }), - ]), - reserved_quantity: 0, - stocked_quantity: 15, - }) - ) - }) - - it("should list the inventory items searching by title, description and sku", async () => { - const api = useApi() - - const inventoryService = appContainer.resolve("inventoryService") - - await inventoryService.createInventoryItems([ - { - title: "Test Item", - }, - { - description: "Test Desc", - }, - { - sku: "Test Sku", - }, - ]) - - const response = await api.get( - `/admin/inventory-items?q=test`, - adminHeaders - ) - - expect(response.data.inventory_items).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ - sku: "MY_SKU", - }), - ]) - ) - expect(response.data.inventory_items).toHaveLength(3) - expect(response.data.inventory_items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - sku: "Test Sku", - }), - expect.objectContaining({ - description: "Test Desc", - }), - expect.objectContaining({ - title: "Test Item", - }), - ]) - ) - }) - }) - - it("should remove associated levels and reservations when deleting an inventory item", async () => { - const api = useApi() - const inventoryService = appContainer.resolve("inventoryService") - - const invItem2 = await inventoryService.createInventoryItem({ - sku: "1234567", - }) - - const stockRes = await api.post( - `/admin/stock-locations`, - { - name: "Fake Warehouse 1", - }, - adminHeaders - ) - - locationId = stockRes.data.stock_location.id - - const level = await inventoryService.createInventoryLevel({ - inventory_item_id: invItem2.id, - location_id: locationId, - stocked_quantity: 10, - }) - - const reservation = await inventoryService.createReservationItem({ - inventory_item_id: invItem2.id, - location_id: locationId, - quantity: 5, - }) - - const [, reservationCount] = await inventoryService.listReservationItems({ - location_id: locationId, - }) - - expect(reservationCount).toEqual(1) - - const [, inventoryLevelCount] = - await inventoryService.listInventoryLevels({ - location_id: locationId, - }) - - expect(inventoryLevelCount).toEqual(1) - - const res = await api.delete( - `/admin/stock-locations/${locationId}`, - adminHeaders - ) - - expect(res.status).toEqual(200) - - const [, reservationCountPostDelete] = - await inventoryService.listReservationItems({ - location_id: locationId, - }) - - expect(reservationCountPostDelete).toEqual(0) - - const [, inventoryLevelCountPostDelete] = - await inventoryService.listInventoryLevels({ - location_id: locationId, - }) - - expect(inventoryLevelCountPostDelete).toEqual(0) - }) - - it("should remove the product variant associations when deleting an inventory item", async () => { - const api = useApi() - - await simpleProductFactory( - dbConnection, - { - id: "test-product-new", - variants: [], - }, - 5 - ) - - const response = await api.post( - `/admin/products/test-product-new/variants`, - { - title: "Test2", - sku: "MY_SKU2", - manage_inventory: true, - options: [ - { - option_id: "test-product-new-option", - value: "Blue", - }, - ], - prices: [{ currency_code: "usd", amount: 100 }], - }, - { headers: { "x-medusa-access-token": "test_token" } } - ) - - const secondVariantId = response.data.product.variants.find( - (v) => v.sku === "MY_SKU2" - ).id - - const inventoryService = appContainer.resolve("inventoryService") - const variantInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - - const invItem2 = await inventoryService.createInventoryItem({ - sku: "123456", - }) - - await variantInventoryService.attachInventoryItem( - variantId, - invItem2.id, - 2 - ) - await variantInventoryService.attachInventoryItem( - secondVariantId, - invItem2.id, - 2 - ) - - expect( - await variantInventoryService.listInventoryItemsByVariant(variantId) - ).toHaveLength(2) - - expect( - await variantInventoryService.listInventoryItemsByVariant( - secondVariantId - ) - ).toHaveLength(2) - - await api.delete(`/admin/inventory-items/${invItem2.id}`, { - headers: { "x-medusa-access-token": "test_token" }, - }) - - expect( - await variantInventoryService.listInventoryItemsByVariant(variantId) - ).toHaveLength(1) - - expect( - await variantInventoryService.listInventoryItemsByVariant( - secondVariantId - ) - ).toHaveLength(1) - }) - - describe("inventory service", () => { - let inventoryService - let productInventoryService - - beforeAll(() => { - inventoryService = appContainer.resolve("inventoryService") - productInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - }) - - it("should bulk remove the inventory items", async () => { - const [items] = await inventoryService.listInventoryItems() - - const ids = items.map((item) => item.id) - - expect(ids).not.toBeFalsy() - - await inventoryService.deleteInventoryItem(ids) - - const [emptyItems] = await inventoryService.listInventoryItems() - expect(emptyItems).toHaveLength(0) - }) - - it("should bulk create the inventory levels", async () => { - const [items] = await inventoryService.listInventoryItems() - - const itemId = items[0].id - - await inventoryService.createInventoryLevels([ - { - inventory_item_id: itemId, - location_id: locationId, - stocked_quantity: 10, - }, - { - inventory_item_id: itemId, - location_id: location2Id, - stocked_quantity: 10, - }, - ]) - - const [levels] = await inventoryService.listInventoryLevels({ - inventory_item_id: itemId, - }) - expect(levels).toHaveLength(2) - expect(levels).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - inventory_item_id: itemId, - location_id: locationId, - }), - expect.objectContaining({ - inventory_item_id: itemId, - location_id: location2Id, - }), - ]) - ) - }) - - it("should bulk create the inventory items", async () => { - const items = [ - { - sku: "sku-1", - }, - { - sku: "sku-2", - }, - ] - const createdItems = await inventoryService.createInventoryItems(items) - - expect(createdItems).toHaveLength(2) - expect(createdItems).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - sku: "sku-1", - }), - expect.objectContaining({ - sku: "sku-2", - }), - ]) - ) - }) - - it("should bulk delete the inventory levels by location id", async () => { - const [items] = await inventoryService.listInventoryItems() - - const itemId = items[0].id - - await inventoryService.createInventoryLevels([ - { - inventory_item_id: itemId, - location_id: locationId, - stocked_quantity: 10, - }, - { - inventory_item_id: itemId, - location_id: location2Id, - stocked_quantity: 10, - }, - ]) - - await inventoryService.deleteInventoryItemLevelByLocationId([ - locationId, - location2Id, - ]) - - const [levels] = await inventoryService.listInventoryLevels({ - inventory_item_id: itemId, - }) - expect(levels).toHaveLength(0) - }) - - it("should bulk delete the inventory levels by location id", async () => { - const [items] = await inventoryService.listInventoryItems() - - const itemId = items[0].id - - await inventoryService.createInventoryLevels([ - { - inventory_item_id: itemId, - location_id: locationId, - stocked_quantity: 10, - }, - { - inventory_item_id: itemId, - location_id: location2Id, - stocked_quantity: 10, - }, - ]) - - await inventoryService.deleteInventoryItemLevelByLocationId([ - locationId, - location2Id, - ]) - - const [levels] = await inventoryService.listInventoryLevels({ - inventory_item_id: itemId, - }) - expect(levels).toHaveLength(0) - }) - - it("should fail to create the reservations with invalid configuration", async () => { - const order = await simpleOrderFactory(dbConnection, { - line_items: [ - { id: "line-item-1", quantity: 1 }, - { id: "line-item-2", quantity: 1 }, - ], - }) - - const [items] = await inventoryService.listInventoryItems() - - const itemId = items[0].id - - const error = await inventoryService - .createReservationItems([ - { - inventory_item_id: itemId, - location_id: locationId, - line_item_id: "line-item-1", - quantity: 1, - }, - { - inventory_item_id: itemId, - location_id: locationId, - line_item_id: "line-item-2", - quantity: 1, - }, - ]) - .catch((err) => err) - - expect(error.message).toEqual( - `Item ${itemId} is not stocked at location ${locationId}, Item ${itemId} is not stocked at location ${locationId}` - ) - }) - - it("should bulk delete the reservations by their line item ids", async () => { - const order = await simpleOrderFactory(dbConnection, { - line_items: [ - { id: "line-item-1", quantity: 1 }, - { id: "line-item-2", quantity: 1 }, - ], - }) - - const [items] = await inventoryService.listInventoryItems() - - const itemId = items[0].id - - await inventoryService.createInventoryLevel({ - inventory_item_id: itemId, - location_id: locationId, - stocked_quantity: 10, - }) - - await inventoryService.createReservationItems([ - { - inventory_item_id: itemId, - location_id: locationId, - line_item_id: "line-item-1", - quantity: 1, - }, - { - inventory_item_id: itemId, - location_id: locationId, - line_item_id: "line-item-2", - quantity: 1, - }, - ]) - - const [reservations] = await inventoryService.listReservationItems({ - inventory_item_id: itemId, - }) - expect(reservations).toHaveLength(2) - - await inventoryService.deleteReservationItemsByLineItem([ - "line-item-1", - "line-item-2", - ]) - - const [deletedReservations] = - await inventoryService.listReservationItems({ - inventory_item_id: itemId, - }) - expect(deletedReservations).toHaveLength(0) - }) - - it("should bulk delete the reservations by their location id", async () => { - const order = await simpleOrderFactory(dbConnection, { - line_items: [ - { id: "line-item-1", quantity: 1 }, - { id: "line-item-2", quantity: 1 }, - ], - }) - - const [items] = await inventoryService.listInventoryItems() - - const itemId = items[0].id - - await inventoryService.createInventoryLevel({ - inventory_item_id: itemId, - location_id: locationId, - stocked_quantity: 10, - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: itemId, - location_id: location2Id, - stocked_quantity: 10, - }) - - await inventoryService.createReservationItems([ - { - inventory_item_id: itemId, - location_id: locationId, - line_item_id: "line-item-1", - quantity: 1, - }, - { - inventory_item_id: itemId, - location_id: location2Id, - line_item_id: "line-item-2", - quantity: 1, - }, - ]) - - const [reservations] = await inventoryService.listReservationItems({ - inventory_item_id: itemId, - }) - expect(reservations).toHaveLength(2) - - await inventoryService.deleteReservationItemByLocationId([ - location2Id, - locationId, - ]) - - const [deletedReservations] = - await inventoryService.listReservationItems({ - inventory_item_id: itemId, - }) - expect(deletedReservations).toHaveLength(0) - }) - - it("should bulk update the inventory levels", async () => { - const [items] = await inventoryService.listInventoryItems() - - const itemId = items[0].id - - await inventoryService.createInventoryLevel({ - inventory_item_id: itemId, - location_id: locationId, - stocked_quantity: 10, - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: itemId, - location_id: location2Id, - stocked_quantity: 10, - }) - - const levels = await inventoryService.listInventoryLevels({ - inventory_item_id: itemId, - }) - expect(levels).toHaveLength(2) - - await inventoryService.updateInventoryLevels([ - { - inventory_item_id: itemId, - location_id: locationId, - stocked_quantity: 20, - }, - { - inventory_item_id: itemId, - location_id: location2Id, - stocked_quantity: 25, - }, - ]) - - const [updatedLevels] = await inventoryService.listInventoryLevels({ - inventory_item_id: itemId, - }) - - expect(updatedLevels).toHaveLength(2) - expect(updatedLevels).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - inventory_item_id: itemId, - location_id: locationId, - stocked_quantity: 20, - }), - expect.objectContaining({ - inventory_item_id: itemId, - location_id: location2Id, - stocked_quantity: 25, - }), - ]) - ) - }) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/order/draft-order.js b/integration-tests/plugins/__tests__/inventory/order/draft-order.js deleted file mode 100644 index 3630b66672..0000000000 --- a/integration-tests/plugins/__tests__/inventory/order/draft-order.js +++ /dev/null @@ -1,180 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") -const { - simpleProductFactory, - simpleCustomerFactory, -} = require("../../../../factories") -const { - simpleRegionFactory, - simpleShippingOptionFactory, -} = require("../../../../factories") -const { - simpleAddressFactory, -} = require("../../../../factories/simple-address-factory") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") - -jest.setTimeout(30000) - -const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } - -describe("/store/carts", () => { - let shutdownServer - let appContainer - let dbConnection - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - beforeEach(async () => {}) - - describe("POST /store/carts", () => { - const variantId = "test-variant" - - let region - let invItemId - let prodVarInventoryService - let inventoryService - let lineItemService - let stockLocationService - let salesChannelLocationService - - let address - let shippingOption - let customer - - beforeEach(async () => { - await adminSeeder(dbConnection) - const api = useApi() - - prodVarInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - lineItemService = appContainer.resolve("lineItemService") - inventoryService = appContainer.resolve("inventoryService") - stockLocationService = appContainer.resolve("stockLocationService") - salesChannelLocationService = appContainer.resolve( - "salesChannelLocationService" - ) - - // create region - region = await simpleRegionFactory(dbConnection, {}) - - // create product - const product = await simpleProductFactory(dbConnection, { - variants: [{ id: variantId }], - }) - - const location = await stockLocationService.create({ - name: "test-location", - }) - - const invItem = await inventoryService.createInventoryItem({ - sku: "test-sku", - }) - invItemId = invItem.id - - await inventoryService.createInventoryLevel({ - inventory_item_id: invItem.id, - location_id: location.id, - stocked_quantity: 10, - }) - - await prodVarInventoryService.attachInventoryItem(variantId, invItem.id) - - // create customer - customer = await simpleCustomerFactory(dbConnection, {}) - - address = await simpleAddressFactory(dbConnection, {}) - - // create shipping option - shippingOption = await simpleShippingOptionFactory(dbConnection, { - region_id: region.id, - }) - }) - - it("should create the order from a draft order and shouldn't adjust reservations", async () => { - const api = useApi() - let inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels.length).toEqual( - 1 - ) - let locationLevel = inventoryItem.data.inventory_item.location_levels[0] - - expect(locationLevel.stocked_quantity).toEqual(10) - expect(locationLevel.reserved_quantity).toEqual(0) - - const payload = { - email: "test@test.dk", - shipping_address: address.id, - discounts: [], - items: [ - { - variant_id: variantId, - quantity: 2, - metadata: {}, - }, - ], - region_id: region.id, - customer_id: customer.id, - shipping_methods: [ - { - option_id: shippingOption.id, - }, - ], - } - - const createResponse = await api.post( - "/admin/draft-orders", - payload, - adminHeaders - ) - expect(createResponse.status).toEqual(200) - - const registerPaymentResponse = await api.post( - `/admin/draft-orders/${createResponse.data.draft_order.id}/pay`, - payload, - adminHeaders - ) - expect(registerPaymentResponse.status).toEqual(200) - - inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels.length).toEqual( - 1 - ) - locationLevel = inventoryItem.data.inventory_item.location_levels[0] - - expect(locationLevel.stocked_quantity).toEqual(10) - expect(locationLevel.reserved_quantity).toEqual(0) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/order/order.js b/integration-tests/plugins/__tests__/inventory/order/order.js deleted file mode 100644 index fa9419f331..0000000000 --- a/integration-tests/plugins/__tests__/inventory/order/order.js +++ /dev/null @@ -1,1131 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { useApi } = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") -const { - simpleLineItemFactory, - simpleSalesChannelFactory, - simpleProductFactory, - simpleCustomerFactory, - simpleOrderFactory, - simpleRegionFactory, - simpleCartFactory, - simpleShippingOptionFactory, -} = require("../../../../factories") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") - -jest.setTimeout(150000) - -const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } - -describe("/store/carts", () => { - let shutdownServer - let appContainer - let dbConnection - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - describe("POST /store/carts/:id", () => { - let order - let locationId - let invItemId - let variantId - let prodVarInventoryService - let inventoryService - let lineItemService - let stockLocationService - let salesChannelLocationService - let regionId - let orderId - - beforeEach(async () => { - const api = useApi() - - prodVarInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - lineItemService = appContainer.resolve("lineItemService") - inventoryService = appContainer.resolve("inventoryService") - stockLocationService = appContainer.resolve("stockLocationService") - salesChannelLocationService = appContainer.resolve( - "salesChannelLocationService" - ) - - const r = await simpleRegionFactory(dbConnection, {}) - regionId = r.id - await simpleSalesChannelFactory(dbConnection, { - id: "test-channel", - is_default: true, - }) - - await adminSeeder(dbConnection) - - const product = await simpleProductFactory(dbConnection, { - id: "product1", - sales_channels: [{ id: "test-channel" }], - }) - variantId = product.variants[0].id - - const sl = await stockLocationService.create({ name: "test-location" }) - - locationId = sl.id - - await salesChannelLocationService.associateLocation( - "test-channel", - locationId - ) - - const invItem = await inventoryService.createInventoryItem({ - sku: "test-sku", - }) - invItemId = invItem.id - - await prodVarInventoryService.attachInventoryItem(variantId, invItem.id) - - await inventoryService.createInventoryLevel({ - inventory_item_id: invItem.id, - location_id: locationId, - stocked_quantity: 100, - }) - - const { id: order_id } = await simpleOrderFactory(dbConnection, { - sales_channel: "test-channel", - line_items: [ - { - variant_id: variantId, - quantity: 2, - id: "line-item-id", - }, - ], - payment_status: "captured", - fulfillment_status: "fulfilled", - shipping_methods: [ - { - shipping_option: { - region_id: r.id, - }, - }, - ], - }) - - orderId = order_id - const orderRes = await api.get(`/admin/orders/${order_id}`, adminHeaders) - order = orderRes.data.order - - await simpleShippingOptionFactory(dbConnection, { - id: "test-return-option", - is_return: true, - region_id: regionId, - price: 0, - }) - - const inventoryItem = await api.get( - `/admin/inventory-items/${invItem.id}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 100, - reserved_quantity: 0, - available_quantity: 100, - }) - ) - }) - - describe("canceling an order", () => { - it("should cancel an order with many items", async () => { - const api = useApi() - - const stockLocation = await stockLocationService.create({ - name: "test-location", - }) - await salesChannelLocationService.associateLocation( - "test-channel", - stockLocation.id - ) - const inventoryItem = await inventoryService.createInventoryItem({ - sku: "cancel-me", - }) - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: stockLocation.id, - stocked_quantity: 100, - }) - - const customer = await simpleCustomerFactory(dbConnection, {}, 100) - const items = [] - const cart = await simpleCartFactory(dbConnection, { - email: "testme@email.com", - region: regionId, - line_items: items, - sales_channel_id: "test-channel", - shipping_address: {}, - shipping_methods: [ - { - shipping_option: { - region_id: regionId, - }, - }, - ], - }) - - for (let i = 0; i < 13; i++) { - const product = await simpleProductFactory(dbConnection, {}) - await prodVarInventoryService.attachInventoryItem( - product.variants[0].id, - inventoryItem.id - ) - const lineItem = await simpleLineItemFactory(dbConnection, { - cart_id: cart.id, - fulfilled_quantity: 0, - returned_quantity: 0, - title: "Line Item", - description: "Line Item Desc", - thumbnail: "https://test.js/1234", - unit_price: 8000, - quantity: 1, - variant_id: product.variants[0].id, - }) - items.push(lineItem) - } - - await appContainer - .resolve("cartService") - .update(cart.id, { customer_id: customer.id }) - - await api.post(`/store/carts/${cart.id}/payment-sessions`) - - const completeRes = await api.post(`/store/carts/${cart.id}/complete`) - - const orderId = completeRes.data.data.id - - const response = await api - .post(`/admin/orders/${orderId}/cancel`, {}, adminHeaders) - .catch((e) => { - console.log(e.response.data) - throw e - }) - - expect(response.status).toEqual(200) - }) - }) - - describe("swaps", () => { - it("adjusts reservations on successful swap", async () => { - const api = useApi() - - const response = await api.post( - `/admin/orders/${orderId}/swaps`, - { - return_items: [ - { - item_id: "line-item-id", - quantity: 1, - }, - ], - return_location_id: locationId, - }, - adminHeaders - ) - - expect(response.status).toEqual(200) - expect(response.data.order.swaps[0].return_order.location_id).toEqual( - locationId - ) - }) - }) - - describe("claims", () => { - it("adjusts reservations on successful swap", async () => { - const api = useApi() - - await lineItemService.update("line-item-id", { - fulfilled_quantity: 1, - }) - - const response = await api.post( - `/admin/orders/${orderId}/claims`, - { - type: "refund", - claim_items: [ - { - item_id: "line-item-id", - quantity: 1, - reason: "production_failure", - }, - ], - return_shipping: { option_id: "test-return-option", price: 0 }, - return_location_id: locationId, - }, - adminHeaders - ) - - expect(response.status).toEqual(200) - expect(response.data.order.claims[0].return_order.location_id).toEqual( - locationId - ) - }) - }) - - describe("Fulfillments", () => { - const lineItemId = "line-item-id" - - it("Adjusts reservations on successful fulfillment on updated reservation item", async () => { - const api = useApi() - - const lineItemId1 = "line-item-id-1" - - // create new location for the inventoryItem with a quantity - const loc = await stockLocationService.create({ name: "test-location" }) - - const customer = await simpleCustomerFactory(dbConnection, {}) - - const cart = await simpleCartFactory(dbConnection, { - email: "adrien@test.com", - region: regionId, - line_items: [ - { - id: lineItemId1, - variant_id: variantId, - quantity: 1, - unit_price: 1000, - }, - ], - sales_channel_id: "test-channel", - shipping_address: {}, - shipping_methods: [ - { - shipping_option: { - region_id: regionId, - }, - }, - ], - }) - - await appContainer - .resolve("cartService") - .update(cart.id, { customer_id: customer.id }) - - let inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 100, - reserved_quantity: 0, - available_quantity: 100, - }) - ) - - await api.post(`/store/carts/${cart.id}/payment-sessions`) - - const completeRes = await api.post(`/store/carts/${cart.id}/complete`) - - const orderId = completeRes.data.data.id - await salesChannelLocationService.associateLocation( - "test-channel", - locationId - ) - - await inventoryService.createInventoryLevel({ - inventory_item_id: invItemId, - location_id: loc.id, - stocked_quantity: 1, - }) - - inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - stocked_quantity: 100, - reserved_quantity: 1, - available_quantity: 99, - }), - expect.objectContaining({ - stocked_quantity: 1, - reserved_quantity: 0, - available_quantity: 1, - }), - ]) - ) - - // update reservation item - const reservationItems = await api.get( - `/admin/reservations?line_item_id[]=${lineItemId1}`, - adminHeaders - ) - - const reservationItem = reservationItems.data.reservations[0] - - const res = await api.post( - `/admin/reservations/${reservationItem.id}`, - { location_id: loc.id }, - adminHeaders - ) - - const fulfillmentRes = await api.post( - `/admin/orders/${orderId}/fulfillment`, - { - items: [{ item_id: lineItemId1, quantity: 1 }], - location_id: locationId, - }, - adminHeaders - ) - - expect(fulfillmentRes.status).toBe(200) - expect( - fulfillmentRes.data.order.fulfillments[0].location_id - ).toBeTruthy() - - inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - const reservations = await api.get( - `/admin/reservations?inventory_item_id[]=${invItemId}`, - adminHeaders - ) - - expect(reservations.data.reservations.length).toBe(0) - expect(inventoryItem.data.inventory_item.location_levels).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - location_id: locationId, - stocked_quantity: 99, - reserved_quantity: 0, - available_quantity: 99, - }), - expect.objectContaining({ - location_id: loc.id, - stocked_quantity: 1, - reserved_quantity: 0, - available_quantity: 1, - }), - ]) - ) - }) - - it("Adjusts reservations on several subsequent fulfillments (being cancelled in-between), with a total quantity greater that the line item quantity", async () => { - const api = useApi() - - const lineItemId1 = "line-item-id-1" - - const customer = await simpleCustomerFactory(dbConnection, {}) - - const cart = await simpleCartFactory(dbConnection, { - email: "adrien@test.com", - region: regionId, - line_items: [ - { - id: lineItemId1, - variant_id: variantId, - quantity: 3, - unit_price: 1000, - }, - ], - sales_channel_id: "test-channel", - shipping_address: {}, - shipping_methods: [ - { - shipping_option: { - region_id: regionId, - }, - }, - ], - }) - - await appContainer - .resolve("cartService") - .update(cart.id, { customer_id: customer.id }) - - let inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 100, - reserved_quantity: 0, - available_quantity: 100, - }) - ) - - await api.post(`/store/carts/${cart.id}/payment-sessions`) - - const completeRes = await api.post(`/store/carts/${cart.id}/complete`) - - const orderId = completeRes.data.data.id - - let fulfillmentRes = await api.post( - `/admin/orders/${orderId}/fulfillment`, - { - items: [{ item_id: lineItemId1, quantity: 2 }], - location_id: locationId, - }, - adminHeaders - ) - - expect(fulfillmentRes.status).toBe(200) - expect( - fulfillmentRes.data.order.fulfillments[0].location_id - ).toBeTruthy() - expect(fulfillmentRes.data.order.fulfillment_status).toEqual( - "partially_fulfilled" - ) - - await api.post( - `/admin/orders/${orderId}/fulfillments/${fulfillmentRes.data.order.fulfillments[0].id}/cancel`, - {}, - adminHeaders - ) - - fulfillmentRes = await api.post( - `/admin/orders/${orderId}/fulfillment`, - { - items: [{ item_id: lineItemId1, quantity: 2 }], - location_id: locationId, - }, - adminHeaders - ) - - expect(fulfillmentRes.status).toBe(200) - expect( - fulfillmentRes.data.order.fulfillments[1].location_id - ).toBeTruthy() - expect(fulfillmentRes.data.order.fulfillment_status).toEqual( - "partially_fulfilled" - ) - - inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - const reservations = await api.get( - `/admin/reservations?inventory_item_id[]=${invItemId}`, - adminHeaders - ) - - expect(reservations.data.reservations.length).toBe(0) - expect(inventoryItem.data.inventory_item.location_levels).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - location_id: locationId, - stocked_quantity: 98, - reserved_quantity: 0, - available_quantity: 98, - }), - ]) - ) - - const orderRes = await api.get(`/admin/orders/${orderId}`, adminHeaders) - expect(orderRes.data.order.items).toEqual([ - expect.objectContaining({ - id: lineItemId1, - fulfilled_quantity: 2, - quantity: 3, - }), - ]) - }) - - it("Adjusts reservation on successful fulfillment with reservation", async () => { - const api = useApi() - - await prodVarInventoryService.reserveQuantity(variantId, 1, { - locationId: locationId, - lineItemId: order.items[0].id, - }) - - let inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 100, - reserved_quantity: 1, - available_quantity: 99, - }) - ) - - const fulfillmentRes = await api.post( - `/admin/orders/${order.id}/fulfillment`, - { - items: [{ item_id: lineItemId, quantity: 1 }], - location_id: locationId, - }, - adminHeaders - ) - - expect(fulfillmentRes.status).toBe(200) - expect(fulfillmentRes.data.order.fulfillment_status).toBe( - "partially_fulfilled" - ) - - inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - const reservations = await api.get( - `/admin/reservations?inventory_item_id[]=${invItemId}`, - adminHeaders - ) - - expect(reservations.data.reservations.length).toBe(0) - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 99, - reserved_quantity: 0, - available_quantity: 99, - }) - ) - }) - - it("Deletes multiple reservations on successful fulfillment with reservation", async () => { - const api = useApi() - - await inventoryService.updateInventoryLevel(invItemId, locationId, { - stocked_quantity: 2, - }) - - await prodVarInventoryService.reserveQuantity(variantId, 1, { - locationId: locationId, - lineItemId: order.items[0].id, - }) - - await prodVarInventoryService.reserveQuantity(variantId, 1, { - locationId: locationId, - lineItemId: order.items[0].id, - }) - - let inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 2, - reserved_quantity: 2, - available_quantity: 0, - }) - ) - - const fulfillmentRes = await api.post( - `/admin/orders/${order.id}/fulfillment`, - { - items: [{ item_id: lineItemId, quantity: 2 }], - location_id: locationId, - }, - adminHeaders - ) - - expect(fulfillmentRes.status).toBe(200) - expect(fulfillmentRes.data.order.fulfillment_status).toBe("fulfilled") - - inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - const reservations = await api.get( - `/admin/reservations?inventory_item_id[]=${invItemId}`, - adminHeaders - ) - - expect(reservations.data.reservations.length).toBe(0) - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 0, - reserved_quantity: 0, - available_quantity: 0, - }) - ) - }) - - it("Deletes single reservation on successful fulfillment with partial reservation", async () => { - const api = useApi() - - await inventoryService.updateInventoryLevel(invItemId, locationId, { - stocked_quantity: 2, - }) - - await prodVarInventoryService.reserveQuantity(variantId, 1, { - locationId: locationId, - lineItemId: order.items[0].id, - }) - - let inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 2, - reserved_quantity: 1, - available_quantity: 1, - }) - ) - - const fulfillmentRes = await api.post( - `/admin/orders/${order.id}/fulfillment`, - { - items: [{ item_id: lineItemId, quantity: 2 }], - location_id: locationId, - }, - adminHeaders - ) - - expect(fulfillmentRes.status).toBe(200) - expect(fulfillmentRes.data.order.fulfillment_status).toBe("fulfilled") - - inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - const reservations = await api.get( - `/admin/reservations?inventory_item_id[]=${invItemId}`, - adminHeaders - ) - - expect(reservations.data.reservations.length).toBe(0) - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 0, - reserved_quantity: 0, - available_quantity: 0, - }) - ) - }) - - it("Adjusts single reservation on successful fulfillment with over-reserved line item", async () => { - const api = useApi() - - await inventoryService.updateInventoryLevel(invItemId, locationId, { - stocked_quantity: 3, - }) - - await prodVarInventoryService.reserveQuantity(variantId, 3, { - locationId: locationId, - lineItemId: order.items[0].id, - }) - - let inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 3, - reserved_quantity: 3, - available_quantity: 0, - }) - ) - - const fulfillmentRes = await api.post( - `/admin/orders/${order.id}/fulfillment`, - { - items: [{ item_id: lineItemId, quantity: 2 }], - location_id: locationId, - }, - adminHeaders - ) - - expect(fulfillmentRes.status).toBe(200) - expect(fulfillmentRes.data.order.fulfillment_status).toBe("fulfilled") - - inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - const reservations = await api.get( - `/admin/reservations?inventory_item_id[]=${invItemId}`, - adminHeaders - ) - - expect(reservations.data.reservations.length).toBe(1) - expect(reservations.data.reservations).toEqual([ - expect.objectContaining({ - quantity: 1, - }), - ]) - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 1, - reserved_quantity: 1, - available_quantity: 0, - }) - ) - }) - - it("Prioritizes adjusting reservations at the chosen location", async () => { - const api = useApi() - - const sl = await stockLocationService.create({ - name: "test-location 1", - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: invItemId, - location_id: sl.id, - stocked_quantity: 3, - }) - - await inventoryService.updateInventoryLevel(invItemId, locationId, { - stocked_quantity: 3, - }) - - await prodVarInventoryService.reserveQuantity(variantId, 1, { - locationId: locationId, - lineItemId: order.items[0].id, - }) - - await prodVarInventoryService.reserveQuantity(variantId, 2, { - locationId: sl.id, - lineItemId: order.items[0].id, - }) - - let inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - location_id: locationId, - stocked_quantity: 3, - reserved_quantity: 1, - available_quantity: 2, - }), - expect.objectContaining({ - location_id: sl.id, - stocked_quantity: 3, - reserved_quantity: 2, - available_quantity: 1, - }), - ]) - ) - - const fulfillmentRes = await api.post( - `/admin/orders/${order.id}/fulfillment`, - { - items: [{ item_id: lineItemId, quantity: 2 }], - location_id: locationId, - }, - adminHeaders - ) - - expect(fulfillmentRes.status).toBe(200) - expect(fulfillmentRes.data.order.fulfillment_status).toBe("fulfilled") - - inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - const reservations = await api.get( - `/admin/reservations?inventory_item_id[]=${invItemId}`, - adminHeaders - ) - - expect(reservations.data.reservations.length).toBe(1) - expect(reservations.data.reservations).toEqual([ - expect.objectContaining({ - quantity: 1, - location_id: sl.id, - }), - ]) - }) - - it("increases stocked quantity when return is received at location", async () => { - const api = useApi() - - const fulfillmentRes = await api.post( - `/admin/orders/${order.id}/fulfillment`, - { - items: [{ item_id: lineItemId, quantity: 1 }], - location_id: locationId, - }, - adminHeaders - ) - - const shipmentRes = await api.post( - `/admin/orders/${order.id}/shipment`, - { - fulfillment_id: fulfillmentRes.data.order.fulfillments[0].id, - }, - adminHeaders - ) - - expect(shipmentRes.status).toBe(200) - - let inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 99, - reserved_quantity: 0, - available_quantity: 99, - }) - ) - - const requestReturnRes = await api.post( - `/admin/orders/${order.id}/return`, - { - receive_now: true, - location_id: locationId, - items: [{ item_id: lineItemId, quantity: 1 }], - }, - adminHeaders - ) - - expect(requestReturnRes.status).toBe(200) - inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 100, - reserved_quantity: 0, - available_quantity: 100, - }) - ) - }) - - it("adjusts inventory levels on successful fulfillment without reservation", async () => { - const api = useApi() - - const fulfillmentRes = await api.post( - `/admin/orders/${order.id}/fulfillment`, - { - items: [{ item_id: lineItemId, quantity: 1 }], - location_id: locationId, - }, - adminHeaders - ) - expect(fulfillmentRes.status).toBe(200) - expect(fulfillmentRes.data.order.fulfillment_status).toBe( - "partially_fulfilled" - ) - - const inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 99, - reserved_quantity: 0, - available_quantity: 99, - }) - ) - }) - - it("Fails to create fulfillment if there is not enough inventory at the fulfillment location", async () => { - const api = useApi() - - const updateRes = await api.post( - `/admin/inventory-items/${invItemId}/location-levels/${locationId}`, - { - stocked_quantity: 1, - }, - adminHeaders - ) - - expect(updateRes.status).toBe(200) - - const locationLevels = await api.get( - `/admin/variants/${variantId}/inventory`, - adminHeaders - ) - - expect( - locationLevels.data.variant.inventory[0].location_levels[0] - ).toEqual( - expect.objectContaining({ - stocked_quantity: 1, - reserved_quantity: 0, - available_quantity: 1, - }) - ) - - const err = await api - .post( - `/admin/orders/${order.id}/fulfillment`, - { - items: [{ item_id: lineItemId, quantity: 2 }], - location_id: locationId, - }, - adminHeaders - ) - .catch((e) => e) - - expect(err.response.status).toBe(400) - expect(err.response.data).toEqual({ - type: "not_allowed", - message: `Insufficient stock for item: ${order.items[0].title}`, - }) - - const inventoryItem = await api.get( - `/admin/inventory-items/${invItemId}`, - adminHeaders - ) - - expect(inventoryItem.data.inventory_item.location_levels[0]).toEqual( - expect.objectContaining({ - stocked_quantity: 1, - reserved_quantity: 0, - available_quantity: 1, - }) - ) - }) - }) - - describe("POST /admin/order-edits", () => { - let order - - beforeEach(async () => { - const api = useApi() - - const cart = await simpleCartFactory(dbConnection, { - id: "test-cart", - sales_channel_id: "test-channel", - }) - - const cartId = cart.id - - await api.post( - `/store/carts/${cartId}/line-items`, - { - variant_id: variantId, - quantity: 3, - }, - { withCredentials: true } - ) - - await api.post( - `/store/carts/${cartId}`, - { - email: "test@test.com", - }, - { withCredentials: true } - ) - - await api.post(`/store/carts/${cartId}/payment-sessions`) - await api.post(`/store/carts/${cartId}/payment-session`, { - provider_id: "test-pay", - }) - const completeRes = await api.post(`/store/carts/${cartId}/complete`) - - expect(completeRes.status).toEqual(200) - expect(completeRes.data.type).toEqual("order") - - order = completeRes.data.data - }) - - it("deletes reservations when an order edit is confirmed", async () => { - const api = useApi() - - const lineItemIds = order.items.map((item) => item.id) - - const inventoryService = appContainer.resolve("inventoryService") - - const [, count] = await inventoryService.listReservationItems({ - line_item_id: lineItemIds, - }) - - expect(count).toEqual(1) - - let response = await api.post( - `/admin/order-edits/`, - { - order_id: order.id, - internal_note: "This is an internal note", - }, - adminHeaders - ) - - const orderEditId = response.data.order_edit.id - - const itemToUpdate = response.data.order_edit.items.find( - (item) => item.original_item_id === order.items[0].id - ) - - response = await api.post( - `/admin/order-edits/${orderEditId}/items/${itemToUpdate.id}`, - { quantity: 2 }, - adminHeaders - ) - - response = await api.post( - `/admin/order-edits/${orderEditId}/confirm`, - {}, - adminHeaders - ) - - expect(response.status).toEqual(200) - expect(response.data.order_edit).toEqual( - expect.objectContaining({ - id: orderEditId, - created_by: "admin_user", - confirmed_by: "admin_user", - confirmed_at: expect.any(String), - status: "confirmed", - }) - ) - - const [, countAfterConfirm] = - await inventoryService.listReservationItems({ - line_item_id: lineItemIds, - }) - - expect(countAfterConfirm).toEqual(0) - }) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/products/create-variant.js b/integration-tests/plugins/__tests__/inventory/products/create-variant.js deleted file mode 100644 index 44706b332e..0000000000 --- a/integration-tests/plugins/__tests__/inventory/products/create-variant.js +++ /dev/null @@ -1,176 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const { - ProductVariantInventoryService, - ProductVariantService, -} = require("@medusajs/medusa") - -const adminSeeder = require("../../../../helpers/admin-seeder") - -jest.setTimeout(30000) - -const { simpleProductFactory } = require("../../../../factories") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") - -describe("Create Variant", () => { - let appContainer - let dbConnection - let shutdownServer - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - describe("Inventory Items", () => { - it("When creating a new product variant it should create an Inventory Item", async () => { - await adminSeeder(dbConnection) - - const api = useApi() - - await simpleProductFactory( - dbConnection, - { - id: "test-product", - variants: [{ id: "test-variant" }], - }, - 100 - ) - - const response = await api.post( - `/admin/products/test-product/variants`, - { - title: "Test Variant w. inventory", - sku: "MY_SKU", - material: "material", - origin_country: "UK", - hs_code: "hs001", - mid_code: "mids", - weight: 300, - length: 100, - height: 200, - width: 150, - manage_inventory: true, - options: [ - { - option_id: "test-product-option", - value: "SS", - }, - ], - prices: [{ currency_code: "usd", amount: 2300 }], - }, - { headers: { "x-medusa-access-token": "test_token" } } - ) - - expect(response.status).toEqual(200) - - const variantId = response.data.product.variants.find( - (v) => v.id !== "test-variant" - ).id - - const variantInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - const inventory = - await variantInventoryService.listInventoryItemsByVariant(variantId) - - expect(inventory).toHaveLength(1) - expect(inventory).toEqual([ - expect.objectContaining({ - origin_country: "UK", - hs_code: "hs001", - mid_code: "mids", - weight: 300, - length: 100, - height: 200, - width: 150, - }), - ]) - }) - - it("When creating a new variant fails, it should revert all the transaction", async () => { - await adminSeeder(dbConnection) - - const api = useApi() - - await simpleProductFactory( - dbConnection, - { - id: "test-product", - variants: [{ id: "test-variant" }], - }, - 100 - ) - - jest - .spyOn(ProductVariantInventoryService.prototype, "attachInventoryItem") - .mockImplementation(() => { - throw new Error("Failure while attaching inventory item") - }) - - const prodVariantDeleteMock = jest.spyOn( - ProductVariantService.prototype, - "delete" - ) - - const error = await api - .post( - `/admin/products/test-product/variants`, - { - title: "Test Variant w. inventory", - sku: "MY_SKU", - material: "material", - origin_country: "UK", - hs_code: "hs001", - mid_code: "mids", - weight: 300, - length: 100, - height: 200, - width: 150, - manage_inventory: true, - options: [ - { - option_id: "test-product-option", - value: "SS", - }, - ], - prices: [{ currency_code: "usd", amount: 2300 }], - }, - { headers: { "x-medusa-access-token": "test_token" } } - ) - .catch((e) => e) - - expect(error.response.status).toEqual(400) - expect(error.response.data.message).toEqual( - "Failure while attaching inventory item" - ) - - expect(prodVariantDeleteMock).toHaveBeenCalledTimes(1) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/products/delete-variant.js b/integration-tests/plugins/__tests__/inventory/products/delete-variant.js deleted file mode 100644 index 2c2abc42d6..0000000000 --- a/integration-tests/plugins/__tests__/inventory/products/delete-variant.js +++ /dev/null @@ -1,114 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") - -jest.setTimeout(30000) - -const { simpleProductFactory } = require("../../../../factories") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") - -describe("Delete Variant", () => { - let appContainer - let dbConnection - let shutdownServer - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - describe("Inventory Items", () => { - it("When deleting a product variant it removes the inventory items associated to it", async () => { - await adminSeeder(dbConnection) - - const api = useApi() - - await simpleProductFactory( - dbConnection, - { - id: "test-product", - variants: [{ id: "test-variant" }], - }, - 100 - ) - - const response = await api.post( - `/admin/products/test-product/variants`, - { - title: "Test Variant w. inventory", - sku: "MY_SKU", - manage_inventory: true, - options: [ - { - option_id: "test-product-option", - value: "SS", - }, - ], - prices: [{ currency_code: "usd", amount: 2300 }], - }, - { headers: { "x-medusa-access-token": "test_token" } } - ) - - const variantId = response.data.product.variants.find( - (v) => v.sku === "MY_SKU" - ).id - - const inventoryService = appContainer.resolve("inventoryService") - const variantInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - const variantService = appContainer.resolve("productVariantService") - - const invItem2 = await inventoryService.createInventoryItem({ - sku: "123456", - }) - - await variantInventoryService.attachInventoryItem( - variantId, - invItem2.id, - 2 - ) - - expect( - await variantInventoryService.listInventoryItemsByVariant(variantId) - ).toHaveLength(2) - - await api.delete(`/admin/products/test-product/variants/${variantId}`, { - headers: { "x-medusa-access-token": "test_token" }, - }) - - await expect(variantService.retrieve(variantId)).rejects.toThrow( - `Variant with id: ${variantId} was not found` - ) - - expect( - await variantInventoryService.listInventoryItemsByVariant(variantId) - ).toHaveLength(0) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/products/get-product.js b/integration-tests/plugins/__tests__/inventory/products/get-product.js deleted file mode 100644 index 4bce1cb1ab..0000000000 --- a/integration-tests/plugins/__tests__/inventory/products/get-product.js +++ /dev/null @@ -1,151 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") - -jest.setTimeout(30000) - -const { - simpleProductFactory, - simpleSalesChannelFactory, -} = require("../../../../factories") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") - -const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } - -describe("Get products", () => { - let appContainer - let dbConnection - let shutdownServer - const productId = "test-product" - const variantId = "test-variant" - let invItem - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - beforeEach(async () => { - await adminSeeder(dbConnection) - - const productVariantInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - const inventoryService = appContainer.resolve("inventoryService") - const locationService = appContainer.resolve("stockLocationService") - const salesChannelService = appContainer.resolve("salesChannelService") - const salesChannelLocationService = appContainer.resolve( - "salesChannelLocationService" - ) - - const salesChannel = await simpleSalesChannelFactory(dbConnection, { - is_default: true, - }) - - const location = await locationService.create({ name: "test-location" }) - await simpleProductFactory( - dbConnection, - { - id: productId, - status: "published", - variants: [{ id: variantId }], - }, - 100 - ) - await salesChannelService.addProducts(salesChannel.id, [productId]) - await salesChannelLocationService.associateLocation( - salesChannel.id, - location.id - ) - invItem = await inventoryService.createInventoryItem({ - sku: "test-sku", - }) - - await productVariantInventoryService.attachInventoryItem( - variantId, - invItem.id - ) - - await inventoryService.createInventoryLevel({ - inventory_item_id: invItem.id, - location_id: location.id, - stocked_quantity: 100, - }) - }) - - describe("/store/products/:id", () => { - it("Expands inventory items when getting product with expand parameters", async () => { - const api = useApi() - - const res = await api.get( - `/store/products/${productId}?expand=variants,variants.inventory_items` - ) - - expect(res.status).toEqual(200) - expect(res.data.product).toEqual( - expect.objectContaining({ - id: productId, - variants: [ - expect.objectContaining({ - id: variantId, - inventory_items: [ - expect.objectContaining({ - inventory_item_id: invItem.id, - variant_id: variantId, - }), - ], - }), - ], - }), - expect.objectContaining({}) - ) - }) - }) - - describe("/admin/products/:id", () => { - it("should get inventory quantity for products fetched through the admin api", async () => { - const api = useApi() - - const res = await api.get(`/admin/products/${productId}`, adminHeaders) - - expect(res.status).toEqual(200) - expect(res.data.product).toEqual( - expect.objectContaining({ - id: productId, - variants: [ - expect.objectContaining({ - id: variantId, - inventory_quantity: 100, - }), - ], - }), - expect.objectContaining({}) - ) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/products/get-variant.js b/integration-tests/plugins/__tests__/inventory/products/get-variant.js deleted file mode 100644 index 1c2d9a5d27..0000000000 --- a/integration-tests/plugins/__tests__/inventory/products/get-variant.js +++ /dev/null @@ -1,144 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") - -jest.setTimeout(30000) - -const { - simpleProductFactory, - simpleSalesChannelFactory, -} = require("../../../../factories") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") - -const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } - -describe("Get variant", () => { - let appContainer - let dbConnection - let shutdownServer - const productId = "test-product" - const variantId = "test-variant" - let invItem - let salesChannelService - let salesChannelLocationService - let location - let inventoryService - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - beforeEach(async () => { - await adminSeeder(dbConnection) - - const productVariantInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - inventoryService = appContainer.resolve("inventoryService") - salesChannelService = appContainer.resolve("salesChannelService") - salesChannelLocationService = appContainer.resolve( - "salesChannelLocationService" - ) - const stockLocationService = appContainer.resolve("stockLocationService") - - location = await stockLocationService.create({ - name: "test-location", - }) - await simpleProductFactory( - dbConnection, - { - id: productId, - status: "published", - variants: [{ id: variantId }], - }, - 100 - ) - - invItem = await inventoryService.createInventoryItem({ - sku: "test-sku", - }) - - await productVariantInventoryService.attachInventoryItem( - variantId, - invItem.id - ) - }) - - it("Expands inventory items when getting variant with expand parameters", async () => { - const api = useApi() - - const res = await api.get( - `/store/variants/${variantId}?expand=inventory_items`, - adminHeaders - ) - - expect(res.status).toEqual(200) - expect(res.data.variant).toEqual( - expect.objectContaining({ - id: variantId, - inventory_items: [ - expect.objectContaining({ - inventory_item_id: invItem.id, - variant_id: variantId, - }), - ], - }) - ) - }) - - it("sets availability correctly", async () => { - const salesChannel = await simpleSalesChannelFactory(dbConnection, { - is_default: true, - }) - - await salesChannelService.addProducts(salesChannel.id, [productId]) - - await salesChannelLocationService.associateLocation( - salesChannel.id, - location.id - ) - - await inventoryService.createInventoryLevel({ - inventory_item_id: invItem.id, - location_id: location.id, - stocked_quantity: 10, - }) - - const api = useApi() - - const response = await api.get(`/store/variants/${variantId}`) - - expect(response.data).toEqual({ - variant: expect.objectContaining({ - purchasable: true, - inventory_quantity: 10, - }), - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/products/list-products.js b/integration-tests/plugins/__tests__/inventory/products/list-products.js deleted file mode 100644 index ea72b61ba7..0000000000 --- a/integration-tests/plugins/__tests__/inventory/products/list-products.js +++ /dev/null @@ -1,348 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") - -jest.setTimeout(30000) - -const { simpleProductFactory } = require("../../../../factories") -const { simpleSalesChannelFactory } = require("../../../../factories") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") - -const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } - -describe("Create Variant", () => { - let appContainer - let dbConnection - let shutdownServer - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - describe("list-products", () => { - const productId = "test-product" - const variantId = "test-variant" - let sc2 - beforeEach(async () => { - await adminSeeder(dbConnection) - - const stockLocationService = appContainer.resolve("stockLocationService") - const productVariantInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - const inventoryService = appContainer.resolve("inventoryService") - const salesChannelLocationService = appContainer.resolve( - "salesChannelLocationService" - ) - - await simpleProductFactory( - dbConnection, - { - id: productId, - status: "published", - sales_channels: [], - variants: [{ id: variantId }], - }, - 100 - ) - - const sc1 = await simpleSalesChannelFactory(dbConnection, {}) - sc2 = await simpleSalesChannelFactory(dbConnection, {}) - const sc3 = await simpleSalesChannelFactory(dbConnection, {}) - - const sl1 = await stockLocationService.create({ name: "sl1" }) - const sl2 = await stockLocationService.create({ name: "sl2" }) - - await salesChannelLocationService.associateLocation(sc1.id, sl1.id) - await salesChannelLocationService.associateLocation(sc2.id, sl1.id) - await salesChannelLocationService.associateLocation(sc2.id, sl2.id) - - const invItem = await inventoryService.createInventoryItem({ - sku: "test-sku", - }) - await productVariantInventoryService.attachInventoryItem( - variantId, - invItem.id - ) - - await inventoryService.createInventoryLevel({ - inventory_item_id: invItem.id, - location_id: sl1.id, - stocked_quantity: 3, - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: invItem.id, - location_id: sl2.id, - stocked_quantity: 1, - }) - }) - - it("lists location availability correctly", async () => { - const api = useApi() - - const res = await api.get(`/admin/products`, adminHeaders) - - expect(res.status).toEqual(200) - expect(res.data.products).toEqual([ - expect.objectContaining({ - id: productId, - variants: [ - expect.objectContaining({ - inventory_quantity: 4, - }), - ], - }), - ]) - }) - - describe("/store/products", () => { - beforeEach(async () => { - const inventoryService = appContainer.resolve("inventoryService") - const productVariantInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - - await simpleProductFactory( - dbConnection, - { - id: `${productId}-1`, - status: "published", - sales_channels: [], - variants: [ - { - id: `${variantId}-1`, - manage_inventory: false, - }, - ], - }, - 101 - ) - await simpleProductFactory( - dbConnection, - { - id: `${productId}-2`, - status: "published", - variants: [{ id: `${variantId}-2`, manage_inventory: true }], - sales_channels: [], - }, - 102 - ) - await simpleProductFactory( - dbConnection, - { - id: `${productId}-3`, - status: "published", - sales_channels: [], - variants: [ - { - id: `${variantId}-3`, - manage_inventory: true, - allow_backorder: true, - }, - ], - }, - 103 - ) - const invItem = await inventoryService.createInventoryItem({ - sku: "test-sku-1", - }) - await productVariantInventoryService.attachInventoryItem( - `${variantId}-3`, - invItem.id - ) - await simpleProductFactory( - dbConnection, - { - id: `${productId}-4`, - status: "published", - sales_channels: [], - variants: [ - { - id: `${variantId}-4`, - manage_inventory: true, - allow_backorder: false, - }, - ], - }, - 104 - ) - const invItem1 = await inventoryService.createInventoryItem({ - sku: "test-sku-2", - }) - await productVariantInventoryService.attachInventoryItem( - `${variantId}-4`, - invItem1.id - ) - }) - - it("includes inventory items when property is expanded", async () => { - const api = useApi() - - const result = await api.get( - `/store/products?expand=variants,variants.inventory_items` - ) - - expect(result.status).toEqual(200) - expect(result.data.products).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - variants: expect.arrayContaining([ - expect.objectContaining({ - inventory_items: [expect.any(Object)], - }), - ]), - }), - ]) - ) - }) - - it("lists location availability correctly for store", async () => { - const api = useApi() - - const res = await api.get(`/store/products`) - - expect(res.status).toEqual(200) - expect(res.data.products).toEqual([ - expect.objectContaining({ - id: `${productId}-4`, - variants: [ - expect.objectContaining({ - purchasable: false, - }), - ], - }), - expect.objectContaining({ - id: `${productId}-3`, - variants: [ - expect.objectContaining({ - purchasable: false, - }), - ], - }), - expect.objectContaining({ - id: `${productId}-2`, - variants: [ - expect.objectContaining({ - purchasable: true, - }), - ], - }), - expect.objectContaining({ - id: `${productId}-1`, - variants: [ - expect.objectContaining({ - inventory_quantity: 10, - purchasable: true, - }), - ], - }), - expect.objectContaining({ - id: productId, - variants: [ - expect.objectContaining({ - purchasable: false, - }), - ], - }), - ]) - }) - - it("lists location availability correctly for store with sales channel id", async () => { - const api = useApi() - - const productService = appContainer.resolve("productService") - - const ids = [ - `${productId}`, - `${productId}-1`, - `${productId}-2`, - `${productId}-3`, - `${productId}-4`, - ] - - for (const id of ids) { - await productService.update(id, { - sales_channels: [{ id: sc2.id }], - }) - } - - const res = await api.get( - `/store/products?sales_channel_id[]=${sc2.id}` - ) - - expect(res.status).toEqual(200) - expect(res.data.products).toEqual([ - expect.objectContaining({ - id: `${productId}-4`, - variants: [ - expect.objectContaining({ - purchasable: false, - }), - ], - }), - expect.objectContaining({ - id: `${productId}-3`, - variants: [ - expect.objectContaining({ - purchasable: true, - }), - ], - }), - expect.objectContaining({ - id: `${productId}-2`, - variants: [ - expect.objectContaining({ - purchasable: true, - }), - ], - }), - expect.objectContaining({ - id: `${productId}-1`, - variants: [ - expect.objectContaining({ - inventory_quantity: 10, - purchasable: true, - }), - ], - }), - expect.objectContaining({ - id: productId, - variants: [ - expect.objectContaining({ - purchasable: true, - inventory_quantity: 4, - }), - ], - }), - ]) - }) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/products/list-variants.js b/integration-tests/plugins/__tests__/inventory/products/list-variants.js deleted file mode 100644 index cc099e8c08..0000000000 --- a/integration-tests/plugins/__tests__/inventory/products/list-variants.js +++ /dev/null @@ -1,147 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") - -jest.setTimeout(30000) - -const { simpleProductFactory } = require("../../../../factories") -const { simpleSalesChannelFactory } = require("../../../../factories") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") -const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } - -describe("List Variants", () => { - let appContainer - let dbConnection - let shutdownServer - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - describe("Inventory Items", () => { - const variantId = "test-variant" - let invItem - - beforeEach(async () => { - await adminSeeder(dbConnection) - - const salesChannelLocationService = appContainer.resolve( - "salesChannelLocationService" - ) - const salesChannelService = appContainer.resolve("salesChannelService") - const inventoryService = appContainer.resolve("inventoryService") - const stockLocationService = appContainer.resolve("stockLocationService") - const prodVarInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - - const location = await stockLocationService.create({ - name: "test-location", - }) - - const salesChannel = await simpleSalesChannelFactory(dbConnection, { - is_default: true, - }) - - const product = await simpleProductFactory(dbConnection, { - variants: [{ id: variantId }], - }) - - await salesChannelService.addProducts(salesChannel.id, [product.id]) - await salesChannelLocationService.associateLocation( - salesChannel.id, - location.id - ) - - invItem = await inventoryService.createInventoryItem({ - sku: "test-sku", - }) - - const invItemId = invItem.id - - await prodVarInventoryService.attachInventoryItem(variantId, invItem.id) - - await inventoryService.createInventoryLevel({ - inventory_item_id: invItem.id, - location_id: location.id, - stocked_quantity: 10, - }) - }) - - it("Decorates inventory quantities when listing variants", async () => { - const api = useApi() - - const listVariantsRes = await api.get(`/admin/variants`, adminHeaders) - - expect(listVariantsRes.status).toEqual(200) - expect(listVariantsRes.data.variants.length).toEqual(1) - expect(listVariantsRes.data.variants[0]).toEqual( - expect.objectContaining({ id: variantId, inventory_quantity: 10 }) - ) - }) - - it("expands inventory_items when querying with expand parameter", async () => { - const api = useApi() - - const listVariantsRes = await api.get( - `/admin/variants?expand=inventory_items`, - adminHeaders - ) - - expect(listVariantsRes.status).toEqual(200) - expect(listVariantsRes.data.variants.length).toEqual(1) - expect(listVariantsRes.data.variants[0]).toEqual( - expect.objectContaining({ - id: variantId, - inventory_items: [ - expect.objectContaining({ - inventory_item_id: invItem.id, - variant_id: variantId, - }), - ], - }) - ) - }) - - it("sets availability correctly", async () => { - const api = useApi() - - const response = await api.get(`/store/variants?ids=${variantId}`) - - expect(response.data).toEqual({ - variants: [ - expect.objectContaining({ - purchasable: true, - inventory_quantity: 10, - }), - ], - }) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/reservation-items/index.js b/integration-tests/plugins/__tests__/inventory/reservation-items/index.js deleted file mode 100644 index d873405d60..0000000000 --- a/integration-tests/plugins/__tests__/inventory/reservation-items/index.js +++ /dev/null @@ -1,459 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") - -jest.setTimeout(30000) - -const { - simpleProductFactory, - simpleOrderFactory, - simpleRegionFactory, -} = require("../../../../factories") -const { simpleSalesChannelFactory } = require("../../../../factories") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") -const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } - -describe("Inventory Items endpoints", () => { - let appContainer - let dbConnection - let shutdownServer - - let inventoryItem - let locationId - - let prodVarInventoryService - let inventoryService - let stockLocationService - let salesChannelLocationService - - let reg - let regionId - let order - let variantId - let reservationItem - let lineItemId - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - beforeEach(async () => { - const api = useApi() - - await adminSeeder(dbConnection) - - prodVarInventoryService = appContainer.resolve( - "productVariantInventoryService" - ) - inventoryService = appContainer.resolve("inventoryService") - stockLocationService = appContainer.resolve("stockLocationService") - salesChannelLocationService = appContainer.resolve( - "salesChannelLocationService" - ) - - const r = await simpleRegionFactory(dbConnection, {}) - regionId = r.id - await simpleSalesChannelFactory(dbConnection, { - id: "test-channel", - is_default: true, - }) - - await simpleProductFactory(dbConnection, { - id: "product1", - sales_channels: [{ id: "test-channel" }], - }) - - const productRes = await api.get(`/admin/products/product1`, adminHeaders) - - variantId = productRes.data.product.variants[0].id - - const stockRes = await api.post( - `/admin/stock-locations`, - { - name: "Fake Warehouse", - }, - adminHeaders - ) - locationId = stockRes.data.stock_location.id - - await salesChannelLocationService.associateLocation( - "test-channel", - locationId - ) - - inventoryItem = await inventoryService.createInventoryItem({ - sku: "1234", - }) - - await prodVarInventoryService.attachInventoryItem( - variantId, - inventoryItem.id - ) - - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: locationId, - stocked_quantity: 100, - }) - - order = await simpleOrderFactory(dbConnection, { - sales_channel: "test-channel", - line_items: [ - { - variant_id: variantId, - quantity: 2, - id: "line-item-id", - }, - ], - shipping_methods: [ - { - shipping_option: { - region_id: r.id, - }, - }, - ], - }) - const orderRes = await api.get(`/admin/orders/${order.id}`, adminHeaders) - - lineItemId = orderRes.data.order.items[0].id - - reservationItem = await inventoryService.createReservationItem({ - line_item_id: lineItemId, - inventory_item_id: inventoryItem.id, - location_id: locationId, - quantity: 2, - }) - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - describe("Reservation items", () => { - it("Create reservation item throws if available item quantity is less than reservation quantity", async () => { - const api = useApi() - - const orderRes = await api.get(`/admin/orders/${order.id}`, adminHeaders) - - expect(orderRes.data.order.items[0].quantity).toBe(2) - expect(orderRes.data.order.items[0].fulfilled_quantity).toBeFalsy() - - const payload = { - quantity: 1, - inventory_item_id: inventoryItem.id, - line_item_id: lineItemId, - location_id: locationId, - } - - const res = await api - .post(`/admin/reservations`, payload, adminHeaders) - .catch((err) => err) - - expect(res.response.status).toBe(400) - expect(res.response.data).toEqual({ - type: "invalid_data", - message: - "The reservation quantity cannot be greater than the unfulfilled line item quantity", - }) - }) - - it("Update reservation item throws if available item quantity is less than reservation quantity", async () => { - const api = useApi() - - const orderRes = await api.get(`/admin/orders/${order.id}`, adminHeaders) - - expect(orderRes.data.order.items[0].quantity).toBe(2) - expect(orderRes.data.order.items[0].fulfilled_quantity).toBeFalsy() - - const payload = { - quantity: 3, - } - - const res = await api - .post( - `/admin/reservations/${reservationItem.id}`, - payload, - adminHeaders - ) - .catch((err) => err) - - expect(res.response.status).toBe(400) - expect(res.response.data).toEqual({ - type: "invalid_data", - message: - "The reservation quantity cannot be greater than the unfulfilled line item quantity", - }) - }) - - describe("List reservation items", () => { - let item2 - let location2 - let reservation2 - - beforeEach(async () => { - const api = useApi() - const stockRes = await api.post( - `/admin/stock-locations`, - { - name: "Fake Warehouse 1", - }, - adminHeaders - ) - - location2 = stockRes.data.stock_location.id - - await salesChannelLocationService.associateLocation( - "test-channel", - location2 - ) - - const inventoryItem1 = await inventoryService.createInventoryItem({ - sku: "12345", - }) - item2 = inventoryItem1.id - - await inventoryService.createInventoryLevel({ - inventory_item_id: item2, - location_id: location2, - stocked_quantity: 100, - }) - - order = await simpleOrderFactory(dbConnection, { - sales_channel: "test-channel", - line_items: [ - { - variant_id: variantId, - quantity: 2, - id: "line-item-id-2", - }, - ], - shipping_methods: [ - { - shipping_option: { - region_id: regionId, - }, - }, - ], - }) - - const orderRes = await api.get( - `/admin/orders/${order.id}`, - adminHeaders - ) - - reservation2 = await inventoryService.createReservationItem({ - line_item_id: "line-item-id-2", - inventory_item_id: item2, - location_id: location2, - description: "test description", - quantity: 1, - }) - }) - - it("lists reservation items", async () => { - const api = useApi() - - const reservationsRes = await api.get( - `/admin/reservations`, - adminHeaders - ) - expect(reservationsRes.data.reservations.length).toBe(2) - expect(reservationsRes.data.reservations).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: reservationItem.id, - }), - expect.objectContaining({ - id: reservation2.id, - }), - ]) - ) - }) - - describe("Filters reservation items", () => { - it("filters by location", async () => { - const api = useApi() - - const reservationsRes = await api.get( - `/admin/reservations?location_id[]=${locationId}`, - adminHeaders - ) - expect(reservationsRes.data.reservations.length).toBe(1) - expect(reservationsRes.data.reservations[0].location_id).toBe( - locationId - ) - }) - - it("filters by itemID", async () => { - const api = useApi() - - const reservationsRes = await api.get( - `/admin/reservations?inventory_item_id[]=${item2}`, - adminHeaders - ) - expect(reservationsRes.data.reservations.length).toBe(1) - expect(reservationsRes.data.reservations[0].inventory_item_id).toBe( - item2 - ) - }) - - it("filters by quantity", async () => { - const api = useApi() - - const reservationsRes = await api.get( - `/admin/reservations?quantity[gt]=1`, - adminHeaders - ) - - expect(reservationsRes.data.reservations.length).toBe(1) - expect(reservationsRes.data.reservations[0].id).toBe( - reservationItem.id - ) - }) - - it("filters by date", async () => { - const api = useApi() - - const reservationsRes = await api.get( - `/admin/reservations?created_at[gte]=${new Date( - reservation2.created_at - ).toISOString()}`, - adminHeaders - ) - - expect(reservationsRes.data.reservations.length).toBe(1) - expect(reservationsRes.data.reservations[0].id).toBe(reservation2.id) - }) - - it("filters by description using equals", async () => { - const api = useApi() - - const reservationsRes = await api - .get( - `/admin/reservations?description=test%20description`, - adminHeaders - ) - .catch(console.log) - - expect(reservationsRes.data.reservations.length).toBe(1) - expect(reservationsRes.data.reservations[0].id).toBe(reservation2.id) - }) - - it("filters by description using equals removes results", async () => { - const api = useApi() - - const reservationsRes = await api.get( - `/admin/reservations?description=description`, - adminHeaders - ) - - expect(reservationsRes.data.reservations.length).toBe(0) - }) - - it("filters by description using contains", async () => { - const api = useApi() - - const reservationsRes = await api.get( - `/admin/reservations?description[contains]=descri`, - adminHeaders - ) - - expect(reservationsRes.data.reservations.length).toBe(1) - expect(reservationsRes.data.reservations[0].id).toBe(reservation2.id) - }) - - it("filters by description using starts_with", async () => { - const api = useApi() - - const reservationsRes = await api - .get( - `/admin/reservations?description[starts_with]=test`, - adminHeaders - ) - .catch(console.log) - - expect(reservationsRes.data.reservations.length).toBe(1) - expect(reservationsRes.data.reservations[0].id).toBe(reservation2.id) - }) - - it("filters by description using starts_with removes results", async () => { - const api = useApi() - - const reservationsRes = await api.get( - `/admin/reservations?description[starts_with]=description`, - adminHeaders - ) - - expect(reservationsRes.data.reservations.length).toBe(0) - }) - - it("filters by description using ends_with", async () => { - const api = useApi() - - const reservationsRes = await api.get( - `/admin/reservations?description[ends_with]=test`, - adminHeaders - ) - - expect(reservationsRes.data.reservations.length).toBe(0) - }) - - it("filters by description using ends_with removes results", async () => { - const api = useApi() - - const reservationsRes = await api.get( - `/admin/reservations?description[ends_with]=description`, - adminHeaders - ) - - expect(reservationsRes.data.reservations.length).toBe(1) - expect(reservationsRes.data.reservations[0].id).toBe(reservation2.id) - }) - }) - }) - - it("lists reservations with inventory_items and line items", async () => { - const api = useApi() - - const res = await api.get( - `/admin/reservations?expand=line_item,inventory_item`, - adminHeaders - ) - - expect(res.status).toEqual(200) - expect(res.data.reservations.length).toEqual(1) - expect(res.data.reservations).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - inventory_item: expect.objectContaining({}), - line_item: expect.objectContaining({ - order: expect.objectContaining({}), - }), - }), - ]) - ) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/service.js b/integration-tests/plugins/__tests__/inventory/service.js deleted file mode 100644 index cffee069f6..0000000000 --- a/integration-tests/plugins/__tests__/inventory/service.js +++ /dev/null @@ -1,815 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../environment-helpers/use-db") -const { getContainer } = require("../../../environment-helpers/use-container") -const { useExpressServer } = require("../../../environment-helpers/use-api") - -jest.setTimeout(50000) - -describe("Inventory Module", () => { - let shutdownServer - let appContainer - let dbConnection - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - const db = useDb() - return await db.teardown() - }) - - describe("Inventory Module Interface", () => { - it("createInventoryItem", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const inventoryItem = await inventoryService.createInventoryItem({ - sku: "sku_1", - origin_country: "CH", - mid_code: "mid code", - material: "lycra", - weight: 100, - length: 200, - height: 50, - width: 50, - metadata: { - abc: 123, - }, - hs_code: "hs_code 123", - requires_shipping: true, - }) - - expect(inventoryItem).toEqual( - expect.objectContaining({ - id: expect.any(String), - sku: "sku_1", - origin_country: "CH", - hs_code: "hs_code 123", - mid_code: "mid code", - material: "lycra", - weight: 100, - length: 200, - height: 50, - width: 50, - requires_shipping: true, - metadata: { abc: 123 }, - deleted_at: null, - created_at: expect.any(Date), - updated_at: expect.any(Date), - }) - ) - }) - - it("updateInventoryItem", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const item = await inventoryService.createInventoryItem({ - sku: "sku_1", - origin_country: "CH", - mid_code: "mid code", - material: "lycra", - weight: 100, - length: 200, - height: 50, - width: 50, - metadata: { - abc: 123, - }, - hs_code: "hs_code 123", - requires_shipping: true, - }) - - const updatedInventoryItem = await inventoryService.updateInventoryItem( - item.id, - { - origin_country: "CZ", - mid_code: "mid code 345", - material: "lycra and polyester", - weight: 500, - metadata: { - dce: 456, - }, - } - ) - - expect(updatedInventoryItem).toEqual( - expect.objectContaining({ - id: item.id, - sku: item.sku, - origin_country: "CZ", - hs_code: item.hs_code, - mid_code: "mid code 345", - material: "lycra and polyester", - weight: 500, - length: item.length, - height: item.height, - width: item.width, - requires_shipping: true, - metadata: { dce: 456 }, - deleted_at: null, - created_at: expect.any(Date), - updated_at: expect.any(Date), - }) - ) - }) - - it("deleteInventoryItem and retrieveInventoryItem", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const item = await inventoryService.createInventoryItem({ - sku: "sku_1", - origin_country: "CH", - mid_code: "mid code", - material: "lycra", - weight: 100, - length: 200, - height: 50, - width: 50, - metadata: { - abc: 123, - }, - hs_code: "hs_code 123", - requires_shipping: true, - }) - - await inventoryService.deleteInventoryItem(item.id) - - const deletedItem = inventoryService.retrieveInventoryItem(item.id) - - await expect(deletedItem).rejects.toThrow( - `InventoryItem with id ${item.id} was not found` - ) - }) - - it("createInventoryLevel", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const inventoryItem = await inventoryService.createInventoryItem({ - sku: "sku_1", - origin_country: "CH", - mid_code: "mid code", - material: "lycra", - weight: 100, - length: 200, - height: 50, - width: 50, - metadata: { - abc: 123, - }, - hs_code: "hs_code 123", - requires_shipping: true, - }) - - const inventoryLevel = await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: "location_123", - stocked_quantity: 50, - reserved_quantity: 15, - incoming_quantity: 4, - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: "second_location", - stocked_quantity: 10, - reserved_quantity: 1, - }) - - expect(inventoryLevel).toEqual( - expect.objectContaining({ - id: expect.any(String), - incoming_quantity: 4, - inventory_item_id: inventoryItem.id, - location_id: "location_123", - metadata: null, - reserved_quantity: 15, - stocked_quantity: 50, - deleted_at: null, - created_at: expect.any(Date), - updated_at: expect.any(Date), - }) - ) - - expect( - await inventoryService.retrieveStockedQuantity(inventoryItem.id, [ - "location_123", - ]) - ).toEqual(50) - - expect( - await inventoryService.retrieveAvailableQuantity(inventoryItem.id, [ - "location_123", - ]) - ).toEqual(35) - - expect( - await inventoryService.retrieveReservedQuantity(inventoryItem.id, [ - "location_123", - ]) - ).toEqual(15) - - expect( - await inventoryService.retrieveStockedQuantity(inventoryItem.id, [ - "location_123", - "second_location", - ]) - ).toEqual(60) - - expect( - await inventoryService.retrieveAvailableQuantity(inventoryItem.id, [ - "location_123", - "second_location", - ]) - ).toEqual(44) - - expect( - await inventoryService.retrieveReservedQuantity(inventoryItem.id, [ - "location_123", - "second_location", - ]) - ).toEqual(16) - }) - - it("updateInventoryLevel", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const inventoryItem = await inventoryService.createInventoryItem({ - sku: "sku_1", - origin_country: "CH", - mid_code: "mid code", - material: "lycra", - weight: 100, - length: 200, - height: 50, - width: 50, - metadata: { - abc: 123, - }, - hs_code: "hs_code 123", - requires_shipping: true, - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: "location_123", - stocked_quantity: 50, - reserved_quantity: 0, - incoming_quantity: 0, - }) - - const updatedLevel = await inventoryService.updateInventoryLevel( - inventoryItem.id, - "location_123", - { - stocked_quantity: 25, - reserved_quantity: 4, - incoming_quantity: 10, - } - ) - - expect(updatedLevel).toEqual( - expect.objectContaining({ - id: expect.any(String), - incoming_quantity: 10, - inventory_item_id: inventoryItem.id, - location_id: "location_123", - metadata: null, - reserved_quantity: 4, - stocked_quantity: 25, - deleted_at: null, - created_at: expect.any(Date), - updated_at: expect.any(Date), - }) - ) - }) - - describe("updateInventoryLevel", () => { - it("should pass along the correct context when doing a bulk update", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const inventoryItem = await inventoryService.createInventoryItem({ - sku: "sku_1", - origin_country: "CH", - mid_code: "mid code", - material: "lycra", - weight: 100, - length: 200, - height: 50, - width: 50, - metadata: { - abc: 123, - }, - hs_code: "hs_code 123", - requires_shipping: true, - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: "location_123", - stocked_quantity: 50, - reserved_quantity: 0, - incoming_quantity: 0, - }) - - let error - try { - await inventoryService.updateInventoryLevels( - [ - { - inventory_item_id: inventoryItem.id, - location_id: "location_123", - stocked_quantity: 25, - reserved_quantity: 4, - incoming_quantity: 10, - }, - ], - { - transactionManager: {}, - } - ) - } catch (e) { - error = e - } - expect(error.message).toEqual("manager.getRepository is not a function") - }) - - it("should pass along the correct context when doing a single update", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const inventoryItem = await inventoryService.createInventoryItem({ - sku: "sku_1", - origin_country: "CH", - mid_code: "mid code", - material: "lycra", - weight: 100, - length: 200, - height: 50, - width: 50, - metadata: { - abc: 123, - }, - hs_code: "hs_code 123", - requires_shipping: true, - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: "location_123", - stocked_quantity: 50, - reserved_quantity: 0, - incoming_quantity: 0, - }) - - let error - try { - await inventoryService.updateInventoryLevel( - inventoryItem.id, - "location_123", - { - stocked_quantity: 25, - reserved_quantity: 4, - incoming_quantity: 10, - }, - { - transactionManager: {}, - } - ) - } catch (e) { - error = e - } - expect(error.message).toEqual("manager.getRepository is not a function") - }) - }) - - it("deleteInventoryLevel", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const inventoryItem = await inventoryService.createInventoryItem({ - sku: "sku_1", - origin_country: "CH", - mid_code: "mid code", - material: "lycra", - weight: 100, - length: 200, - height: 50, - width: 50, - metadata: { - abc: 123, - }, - hs_code: "hs_code 123", - requires_shipping: true, - }) - - const inventoryLevel = await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: "location_123", - stocked_quantity: 50, - reserved_quantity: 0, - incoming_quantity: 0, - }) - - await inventoryService.deleteInventoryLevel( - inventoryItem.id, - "location_123" - ) - - const deletedLevel = inventoryService.retrieveInventoryLevel( - inventoryItem.id, - "location_123" - ) - - await expect(deletedLevel).rejects.toThrow( - `Inventory level for item ${inventoryItem.id} and location location_123 not found` - ) - }) - - it("createReservationItem", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const locationId = "location_123" - const inventoryItem = await inventoryService.createInventoryItem({ - sku: "sku_1", - }) - - const tryReserve = inventoryService.createReservationItem({ - line_item_id: "line_item_123", - inventory_item_id: inventoryItem.id, - location_id: locationId, - quantity: 10, - metadata: { - abc: 123, - }, - }) - - await expect(tryReserve).rejects.toThrow( - `Item ${inventoryItem.id} is not stocked at location ${locationId}` - ) - - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: locationId, - stocked_quantity: 50, - reserved_quantity: 0, - incoming_quantity: 0, - }) - - const inventoryReservation = await inventoryService.createReservationItem( - { - line_item_id: "line_item_123", - inventory_item_id: inventoryItem.id, - location_id: locationId, - quantity: 10, - metadata: { - abc: 123, - }, - } - ) - - expect(inventoryReservation).toEqual( - expect.objectContaining({ - id: expect.any(String), - line_item_id: "line_item_123", - inventory_item_id: inventoryItem.id, - location_id: locationId, - quantity: 10, - metadata: { abc: 123 }, - deleted_at: null, - created_at: expect.any(Date), - updated_at: expect.any(Date), - }) - ) - - const [available, reserved] = await Promise.all([ - inventoryService.retrieveAvailableQuantity(inventoryItem.id, [ - locationId, - ]), - inventoryService.retrieveReservedQuantity(inventoryItem.id, locationId), - ]) - - expect(available).toEqual(40) - expect(reserved).toEqual(10) - }) - - it("updateReservationItem", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const locationId = "location_123" - const newLocationId = "location_new" - - const inventoryItem = await inventoryService.createInventoryItem({ - sku: "sku_1", - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: locationId, - stocked_quantity: 50, - reserved_quantity: 0, - incoming_quantity: 0, - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: newLocationId, - stocked_quantity: 20, - reserved_quantity: 5, - incoming_quantity: 0, - }) - - const inventoryReservation = await inventoryService.createReservationItem( - { - line_item_id: "line_item_123", - inventory_item_id: inventoryItem.id, - location_id: locationId, - quantity: 15, - metadata: { - abc: 123, - }, - } - ) - - const [available, reserved] = await Promise.all([ - inventoryService.retrieveAvailableQuantity( - inventoryItem.id, - locationId - ), - inventoryService.retrieveReservedQuantity(inventoryItem.id, locationId), - ]) - - expect(available).toEqual(35) - expect(reserved).toEqual(15) - - const updatedReservation = await inventoryService.updateReservationItem( - inventoryReservation.id, - { - quantity: 5, - } - ) - - expect(updatedReservation).toEqual( - expect.objectContaining({ - id: expect.any(String), - line_item_id: "line_item_123", - inventory_item_id: inventoryItem.id, - location_id: locationId, - quantity: 5, - metadata: { abc: 123 }, - }) - ) - - const [newAvailable, newReserved] = await Promise.all([ - inventoryService.retrieveAvailableQuantity( - inventoryItem.id, - locationId - ), - inventoryService.retrieveReservedQuantity(inventoryItem.id, locationId), - ]) - - expect(newAvailable).toEqual(45) - expect(newReserved).toEqual(5) - - const updatedReservationLocation = - await inventoryService.updateReservationItem(inventoryReservation.id, { - quantity: 12, - location_id: newLocationId, - }) - - expect(updatedReservationLocation).toEqual( - expect.objectContaining({ - id: expect.any(String), - line_item_id: "line_item_123", - inventory_item_id: inventoryItem.id, - location_id: newLocationId, - quantity: 12, - metadata: { abc: 123 }, - }) - ) - - const [ - oldLocationAvailable, - oldLocationReserved, - newLocationAvailable, - newLocationReserved, - ] = await Promise.all([ - inventoryService.retrieveAvailableQuantity( - inventoryItem.id, - locationId - ), - inventoryService.retrieveReservedQuantity(inventoryItem.id, locationId), - inventoryService.retrieveAvailableQuantity( - inventoryItem.id, - newLocationId - ), - inventoryService.retrieveReservedQuantity( - inventoryItem.id, - newLocationId - ), - ]) - - expect(oldLocationAvailable).toEqual(50) - expect(oldLocationReserved).toEqual(0) - expect(newLocationAvailable).toEqual(3) - expect(newLocationReserved).toEqual(17) - }) - - it("deleteReservationItem and deleteReservationItemsByLineItem", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const locationId = "location_123" - - const inventoryItem = await inventoryService.createInventoryItem({ - sku: "sku_1", - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: locationId, - stocked_quantity: 10, - }) - - const inventoryReservation = await inventoryService.createReservationItem( - { - line_item_id: "line_item_123", - inventory_item_id: inventoryItem.id, - location_id: locationId, - quantity: 1, - } - ) - - for (let quant = 1; quant <= 3; quant++) { - await inventoryService.createReservationItem({ - line_item_id: "line_item_444", - inventory_item_id: inventoryItem.id, - location_id: locationId, - quantity: 1, - }) - } - - const [available, reserved] = await Promise.all([ - inventoryService.retrieveAvailableQuantity( - inventoryItem.id, - locationId - ), - inventoryService.retrieveReservedQuantity(inventoryItem.id, locationId), - ]) - - expect(available).toEqual(6) - expect(reserved).toEqual(4) - - await inventoryService.deleteReservationItemsByLineItem("line_item_444") - const [afterDeleteLineitemAvailable, afterDeleteLineitemReserved] = - await Promise.all([ - inventoryService.retrieveAvailableQuantity( - inventoryItem.id, - locationId - ), - inventoryService.retrieveReservedQuantity( - inventoryItem.id, - locationId - ), - ]) - - expect(afterDeleteLineitemAvailable).toEqual(9) - expect(afterDeleteLineitemReserved).toEqual(1) - - await inventoryService.deleteReservationItem(inventoryReservation.id) - const [afterDeleteReservationAvailable, afterDeleteReservationReserved] = - await Promise.all([ - inventoryService.retrieveAvailableQuantity( - inventoryItem.id, - locationId - ), - inventoryService.retrieveReservedQuantity( - inventoryItem.id, - locationId - ), - ]) - - expect(afterDeleteReservationAvailable).toEqual(10) - expect(afterDeleteReservationReserved).toEqual(0) - }) - - it("confirmInventory", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const locationId = "location_123" - const secondLocationId = "location_551" - - const inventoryItem = await inventoryService.createInventoryItem({ - sku: "sku_1", - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: locationId, - stocked_quantity: 10, - reserved_quantity: 5, - }) - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: secondLocationId, - stocked_quantity: 6, - reserved_quantity: 1, - }) - - expect( - await inventoryService.confirmInventory(inventoryItem.id, locationId, 5) - ).toBeTruthy() - - expect( - await inventoryService.confirmInventory( - inventoryItem.id, - [locationId, secondLocationId], - 10 - ) - ).toBeTruthy() - - expect( - await inventoryService.confirmInventory(inventoryItem.id, locationId, 6) - ).toBeFalsy() - - expect( - await inventoryService.confirmInventory( - inventoryItem.id, - [locationId, secondLocationId], - 11 - ) - ).toBeFalsy() - }) - - it("adjustInventory", async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const locationId = "location_123" - const secondLocationId = "location_551" - - const inventoryItem = await inventoryService.createInventoryItem({ - sku: "sku_1", - }) - - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: locationId, - stocked_quantity: 10, - reserved_quantity: 5, - }) - await inventoryService.createInventoryLevel({ - inventory_item_id: inventoryItem.id, - location_id: secondLocationId, - stocked_quantity: 6, - reserved_quantity: 1, - }) - - expect( - await inventoryService.adjustInventory(inventoryItem.id, locationId, -5) - ).toEqual( - expect.objectContaining({ - id: expect.any(String), - inventory_item_id: inventoryItem.id, - location_id: locationId, - stocked_quantity: 5, - reserved_quantity: 5, - incoming_quantity: 0, - metadata: null, - deleted_at: null, - created_at: expect.any(Date), - updated_at: expect.any(Date), - }) - ) - - expect( - await inventoryService.adjustInventory( - inventoryItem.id, - secondLocationId, - -10 - ) - ).toEqual( - expect.objectContaining({ - id: expect.any(String), - inventory_item_id: inventoryItem.id, - location_id: secondLocationId, - stocked_quantity: -4, - reserved_quantity: 1, - incoming_quantity: 0, - metadata: null, - deleted_at: null, - created_at: expect.any(Date), - updated_at: expect.any(Date), - }) - ) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/inventory/variant-inventory-service.js b/integration-tests/plugins/__tests__/inventory/variant-inventory-service.js deleted file mode 100644 index 5bf7ace382..0000000000 --- a/integration-tests/plugins/__tests__/inventory/variant-inventory-service.js +++ /dev/null @@ -1,286 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../environment-helpers/use-db") -const { simpleProductFactory } = require("../../../factories") -const { getContainer } = require("../../../environment-helpers/use-container") -const { useExpressServer } = require("../../../environment-helpers/use-api") - -jest.setTimeout(50000) - -describe("Inventory Module", () => { - let appContainer - let dbConnection - let shutdownServer - - let invItem1 - let invItem2 - let variant1 - let variant2 - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - describe("ProductVariantInventoryService", () => { - describe("attachInventoryItem", () => { - afterEach(async () => { - const db = useDb() - return await db.teardown() - }) - - beforeEach(async () => { - const inventoryService = appContainer.resolve("inventoryService") - - const { variants } = await simpleProductFactory(dbConnection, { - variants: [{}, {}], - }) - - variant1 = variants[0] - variant2 = variants[1] - - invItem1 = await inventoryService.createInventoryItem({ - sku: "test-sku-1", - }) - - invItem2 = await inventoryService.createInventoryItem({ - sku: "test-sku-2", - }) - }) - - it("should attach the single item with spread params", async () => { - const pviService = appContainer.resolve( - "productVariantInventoryService" - ) - await pviService.attachInventoryItem(variant1.id, invItem1.id) - - const variantItems = await pviService.listByVariant(variant1.id) - expect(variantItems.length).toEqual(1) - expect(variantItems[0]).toEqual( - expect.objectContaining({ - inventory_item_id: invItem1.id, - variant_id: variant1.id, - }) - ) - }) - - it("should attach multiple inventory items and variants at once", async () => { - const pviService = appContainer.resolve( - "productVariantInventoryService" - ) - await pviService.attachInventoryItem([ - { - variantId: variant1.id, - inventoryItemId: invItem1.id, - }, - { - variantId: variant2.id, - inventoryItemId: invItem2.id, - }, - ]) - - const variantItems = await pviService.listByVariant([ - variant1.id, - variant2.id, - ]) - expect(variantItems.length).toEqual(2) - expect(variantItems).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - inventory_item_id: invItem1.id, - variant_id: variant1.id, - }), - expect.objectContaining({ - variant_id: variant2.id, - inventory_item_id: invItem2.id, - }), - ]) - ) - }) - - it("should skip existing attachments when attaching a singular inventory item", async () => { - const pviService = appContainer.resolve( - "productVariantInventoryService" - ) - await pviService.attachInventoryItem(variant1.id, invItem1.id) - await pviService.attachInventoryItem(variant1.id, invItem1.id) - - const variantItems = await pviService.listByVariant(variant1.id) - expect(variantItems.length).toEqual(1) - expect(variantItems[0]).toEqual( - expect.objectContaining({ - inventory_item_id: invItem1.id, - variant_id: variant1.id, - }) - ) - }) - - it("should skip existing attachments when attaching multiple inventory items in bulk", async () => { - const pviService = appContainer.resolve( - "productVariantInventoryService" - ) - await pviService.attachInventoryItem(variant1.id, invItem1.id) - - await pviService.attachInventoryItem([ - { - variantId: variant1.id, - inventoryItemId: invItem1.id, - }, - { - variantId: variant2.id, - inventoryItemId: invItem2.id, - }, - ]) - - const variantItems = await pviService.listByVariant([ - variant1.id, - variant2.id, - ]) - expect(variantItems.length).toEqual(2) - expect(variantItems).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - inventory_item_id: invItem1.id, - variant_id: variant1.id, - }), - expect.objectContaining({ - variant_id: variant2.id, - inventory_item_id: invItem2.id, - }), - ]) - ) - }) - - it("should fail to attach items when a single item has a required_quantity below 1", async () => { - const pviService = appContainer.resolve( - "productVariantInventoryService" - ) - - let e - try { - await pviService.attachInventoryItem(variant1.id, invItem1.id, 0) - } catch (err) { - e = err - } - - expect(e.message).toEqual( - `"requiredQuantity" must be greater than 0, the following entries are invalid: ${JSON.stringify( - { - variantId: variant1.id, - inventoryItemId: invItem1.id, - requiredQuantity: 0, - } - )}` - ) - - try { - await pviService.attachInventoryItem([ - { - variantId: variant1.id, - inventoryItemId: invItem1.id, - }, - { - variantId: variant2.id, - inventoryItemId: invItem2.id, - requiredQuantity: 0, - }, - ]) - } catch (err) { - e = err - } - - expect(e.message).toEqual( - `"requiredQuantity" must be greater than 0, the following entries are invalid: ${JSON.stringify( - { - variantId: variant2.id, - inventoryItemId: invItem2.id, - requiredQuantity: 0, - } - )}` - ) - }) - - it("should fail to attach items when attaching to a non-existing variant", async () => { - const pviService = appContainer.resolve( - "productVariantInventoryService" - ) - - let e - try { - await pviService.attachInventoryItem("variant1.id", invItem1.id) - } catch (err) { - e = err - } - - expect(e.message).toEqual( - `Variants not found for the following ids: variant1.id` - ) - - try { - await pviService.attachInventoryItem([ - { - variantId: "variant1.id", - inventoryItemId: invItem1.id, - }, - { - variantId: variant2.id, - inventoryItemId: invItem2.id, - }, - ]) - } catch (err) { - e = err - } - - expect(e.message).toEqual( - `Variants not found for the following ids: variant1.id` - ) - }) - it("should fail to attach items when attaching to a non-existing inventory item", async () => { - const pviService = appContainer.resolve( - "productVariantInventoryService" - ) - - let e - try { - await pviService.attachInventoryItem(variant1.id, "invItem1.id") - } catch (err) { - e = err - } - - expect(e.message).toEqual( - `Inventory items not found for the following ids: invItem1.id` - ) - - try { - await pviService.attachInventoryItem([ - { - variantId: variant1.id, - inventoryItemId: invItem1.id, - }, - { - variantId: variant2.id, - inventoryItemId: "invItem2.id", - }, - ]) - } catch (err) { - e = err - } - - expect(e.message).toEqual( - `Inventory items not found for the following ids: invItem2.id` - ) - }) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/stock-location/list-stock-locations.spec.ts b/integration-tests/plugins/__tests__/stock-location/list-stock-locations.spec.ts deleted file mode 100644 index 68ff3e4212..0000000000 --- a/integration-tests/plugins/__tests__/stock-location/list-stock-locations.spec.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { useApi } from "../../../environment-helpers/use-api" -import { AxiosInstance } from "axios" -import adminSeeder from "../../../helpers/admin-seeder" - -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../environment-helpers/use-db") -const { getContainer } = require("../../../environment-helpers/use-container") -const { useExpressServer } = require("../../../environment-helpers/use-api") - -const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } - -jest.setTimeout(50000) - -describe("List stock locations", () => { - let shutdownServer - let appContainer - let dbConnection - let addressId - let scId - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - const db = useDb() - return await db.teardown() - }) - - beforeEach(async () => { - await adminSeeder(dbConnection) - - const stockLocationModule = appContainer.resolve( - ModuleRegistrationName.STOCK_LOCATION - ) - - const salesChannelService = appContainer.resolve("salesChannelService") - const salesChannelLocationService = appContainer.resolve( - "salesChannelLocationService" - ) - const { id: sc_id } = await salesChannelService.create({ name: "test" }) - scId = sc_id - - const [{ address_id }, { id }] = await Promise.all([ - stockLocationModule.create({ - name: "Copenhagen", - address: { - address_1: "test street 1", - country_code: "DK", - }, - }), - stockLocationModule.create({ - name: "Berlin", - }), - stockLocationModule.create({ - name: "Paris", - }), - ]) - - await salesChannelLocationService.associateLocation(sc_id, id) - - addressId = address_id - }) - - describe("GET /stock-location", () => { - it("should list all stock locations", async () => { - const api = useApi()! as AxiosInstance - - const result = await api.get("/admin/stock-locations", adminHeaders) - - expect(result.status).toEqual(200) - expect(result.data.stock_locations).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - name: "Copenhagen", - }), - expect.objectContaining({ - name: "Berlin", - }), - expect.objectContaining({ - name: "Paris", - }), - ]) - ) - }) - - it("should list stock locations filtered by q parameter", async () => { - const api = useApi()! as AxiosInstance - - const result = await api.get( - "/admin/stock-locations?q=open", - adminHeaders - ) - - expect(result.status).toEqual(200) - expect(result.data.count).toEqual(1) - expect(result.data.stock_locations).toEqual([ - expect.objectContaining({ - name: "Copenhagen", - }), - ]) - }) - - it("should list stock locations filtered by addresses", async () => { - const api = useApi()! as AxiosInstance - - const result = await api.get( - `/admin/stock-locations?address_id=${addressId}`, - adminHeaders - ) - - expect(result.status).toEqual(200) - expect(result.data.count).toEqual(1) - expect(result.data.stock_locations).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - name: "Copenhagen", - }), - ]) - ) - }) - - it("should list stock locations filtered by sales channel Id", async () => { - const api = useApi()! as AxiosInstance - - const result = await api.get( - `/admin/stock-locations?sales_channel_id=${scId}`, - adminHeaders - ) - - expect(result.status).toEqual(200) - expect(result.data.count).toEqual(1) - expect(result.data.stock_locations).toEqual([ - expect.objectContaining({ - name: "Berlin", - }), - ]) - }) - - it("should list stock locations in requested order", async () => { - const api = useApi()! as AxiosInstance - - const nameOrderLocations = [ - expect.objectContaining({ - name: "Berlin", - }), - expect.objectContaining({ - name: "Copenhagen", - }), - expect.objectContaining({ - name: "Paris", - }), - ] - - let result = await api.get( - "/admin/stock-locations?order=name", - adminHeaders - ) - expect(result.status).toEqual(200) - expect(result.data.stock_locations).toEqual(nameOrderLocations) - - result = await api.get("/admin/stock-locations?order=-name", adminHeaders) - expect(result.status).toEqual(200) - expect(result.data.stock_locations).toEqual(nameOrderLocations.reverse()) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/stock-location/service/delete-sales-channels.js b/integration-tests/plugins/__tests__/stock-location/service/delete-sales-channels.js deleted file mode 100644 index 09c95d1a78..0000000000 --- a/integration-tests/plugins/__tests__/stock-location/service/delete-sales-channels.js +++ /dev/null @@ -1,88 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") - -jest.setTimeout(30000) - -describe("Sales channels", () => { - let appContainer - let dbConnection - let shutdownServer - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - describe("Stock Locations", () => { - it("When deleting a sales channel, removes all associated locations with it", async () => { - await adminSeeder(dbConnection) - const api = useApi() - - const stockLocationService = appContainer.resolve("stockLocationService") - const salesChannelService = appContainer.resolve("salesChannelService") - const salesChannelLocationService = appContainer.resolve( - "salesChannelLocationService" - ) - - const loc = await stockLocationService.create({ - name: "warehouse", - }) - const loc2 = await stockLocationService.create({ - name: "other place", - }) - - const sc = await salesChannelService.create({ name: "channel test" }) - - await salesChannelLocationService.associateLocation(sc.id, loc.id) - await salesChannelLocationService.associateLocation(sc.id, loc2.id) - - expect(await salesChannelService.retrieve(sc.id)).toEqual( - expect.objectContaining({ - id: sc.id, - name: "channel test", - }) - ) - - expect( - await salesChannelLocationService.listLocationIds(sc.id) - ).toHaveLength(2) - - await api.delete(`/admin/sales-channels/${sc.id}`, { - headers: { "x-medusa-access-token": "test_token" }, - }) - - await expect(salesChannelService.retrieve(sc.id)).rejects.toThrowError() - - await expect( - salesChannelLocationService.listLocationIds(sc.id) - ).rejects.toThrowError() - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/stock-location/service/delete-stock-location.js b/integration-tests/plugins/__tests__/stock-location/service/delete-stock-location.js deleted file mode 100644 index 68dee64e47..0000000000 --- a/integration-tests/plugins/__tests__/stock-location/service/delete-stock-location.js +++ /dev/null @@ -1,96 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") - -jest.setTimeout(30000) - -describe("Sales channels", () => { - let appContainer - let dbConnection - let shutdownServer - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - describe("Stock Locations", () => { - it("When deleting a stock location, removes all associated sales channels with it", async () => { - await adminSeeder(dbConnection) - const api = useApi() - - const stockLocationService = appContainer.resolve("stockLocationService") - const salesChannelService = appContainer.resolve("salesChannelService") - const salesChannelLocationService = appContainer.resolve( - "salesChannelLocationService" - ) - - const loc = await stockLocationService.create({ - name: "warehouse", - }) - - const saleChannel = await salesChannelService.create({ - name: "channel test", - }) - - const otherChannel = await salesChannelService.create({ - name: "yet another channel", - }) - - await salesChannelLocationService.associateLocation( - saleChannel.id, - loc.id - ) - await salesChannelLocationService.associateLocation( - otherChannel.id, - loc.id - ) - - expect( - await salesChannelLocationService.listLocationIds(saleChannel.id) - ).toHaveLength(1) - - expect( - await salesChannelLocationService.listLocationIds(otherChannel.id) - ).toHaveLength(1) - - await api.delete(`/admin/stock-locations/${loc.id}`, { - headers: { "x-medusa-access-token": "test_token" }, - }) - - expect( - await salesChannelLocationService.listLocationIds(saleChannel.id) - ).toHaveLength(0) - - expect( - await salesChannelLocationService.listLocationIds(otherChannel.id) - ).toHaveLength(0) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/stock-location/service/sales-channels.js b/integration-tests/plugins/__tests__/stock-location/service/sales-channels.js deleted file mode 100644 index ed3a946420..0000000000 --- a/integration-tests/plugins/__tests__/stock-location/service/sales-channels.js +++ /dev/null @@ -1,162 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - useApi, - useExpressServer, -} = require("../../../../environment-helpers/use-api") - -const adminSeeder = require("../../../../helpers/admin-seeder") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") - -jest.setTimeout(30000) - -const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } } - -describe("Sales channels", () => { - let appContainer - let dbConnection - let shutdownServer - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - jest.clearAllMocks() - const db = useDb() - return await db.teardown() - }) - - describe("Stock Locations", () => { - describe("CORE", () => { - it("When listing a sales channel, it brings all associated locations with it", async () => { - await adminSeeder(dbConnection) - - const stockLocationService = appContainer.resolve( - "stockLocationService" - ) - const salesChannelService = appContainer.resolve("salesChannelService") - const salesChannelLocationService = appContainer.resolve( - "salesChannelLocationService" - ) - - const loc = await stockLocationService.create({ - name: "warehouse", - }) - const loc2 = await stockLocationService.create({ - name: "other place", - }) - - const sc = await salesChannelService.create({ name: "channel test" }) - - await salesChannelLocationService.associateLocation(sc.id, loc.id) - await salesChannelLocationService.associateLocation(sc.id, loc2.id) - - expect( - await salesChannelLocationService.listLocationIds(sc.id) - ).toHaveLength(2) - - const [channels] = await salesChannelService.listAndCount( - {}, - { - relations: ["locations"], - } - ) - const createdSC = channels.find((c) => c.id === sc.id) - - expect(channels).toHaveLength(2) - expect(createdSC.locations).toHaveLength(2) - expect(createdSC).toEqual( - expect.objectContaining({ - id: sc.id, - name: "channel test", - locations: expect.arrayContaining([ - expect.objectContaining({ - sales_channel_id: sc.id, - location_id: loc.id, - }), - expect.objectContaining({ - sales_channel_id: sc.id, - location_id: loc2.id, - }), - ]), - }) - ) - }) - }) - - describe("API", () => { - it("Filters stock locations based on sales channel ids", async () => { - const api = useApi() - - await adminSeeder(dbConnection) - - const stockLocationService = appContainer.resolve( - "stockLocationService" - ) - const salesChannelService = appContainer.resolve("salesChannelService") - const salesChannelLocationService = appContainer.resolve( - "salesChannelLocationService" - ) - - const loc = await stockLocationService.create({ - name: "warehouse", - }) - const loc2 = await stockLocationService.create({ - name: "other place", - }) - - const sc = await salesChannelService.create({ name: "Default Channel" }) - const sc2 = await salesChannelService.create({ name: "Physical store" }) - - await salesChannelLocationService.associateLocation(sc.id, loc.id) - await salesChannelLocationService.associateLocation(sc.id, loc2.id) - await salesChannelLocationService.associateLocation(sc2.id, loc2.id) - - const defaultSalesChannelFilterRes = await api.get( - `/admin/stock-locations?sales_channel_id=${sc.id}`, - adminHeaders - ) - - expect(defaultSalesChannelFilterRes.data.stock_locations).toHaveLength( - 2 - ) - expect(defaultSalesChannelFilterRes.data.stock_locations).toEqual( - expect.arrayContaining([ - expect.objectContaining({ name: "warehouse" }), - expect.objectContaining({ name: "other place" }), - ]) - ) - - const physicalStoreSalesChannelFilterRes = await api.get( - `/admin/stock-locations?sales_channel_id=${sc2.id}`, - adminHeaders - ) - expect( - physicalStoreSalesChannelFilterRes.data.stock_locations - ).toHaveLength(1) - - expect(physicalStoreSalesChannelFilterRes.data.stock_locations).toEqual( - expect.arrayContaining([ - expect.objectContaining({ name: "other place" }), - ]) - ) - }) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/stock-location/service/service.js b/integration-tests/plugins/__tests__/stock-location/service/service.js deleted file mode 100644 index 704d1b961b..0000000000 --- a/integration-tests/plugins/__tests__/stock-location/service/service.js +++ /dev/null @@ -1,273 +0,0 @@ -const path = require("path") - -const { - startBootstrapApp, -} = require("../../../../environment-helpers/bootstrap-app") -const { initDb, useDb } = require("../../../../environment-helpers/use-db") -const { - getContainer, -} = require("../../../../environment-helpers/use-container") -const { useExpressServer } = require("../../../../environment-helpers/use-api") - -jest.setTimeout(30000) - -describe("Stock Location Module", () => { - let appContainer - let dbConnection - let shutdownServer - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd }) - appContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - afterEach(async () => { - const db = useDb() - return await db.teardown() - }) - - describe("Stock Location Module Interface", () => { - it("create", async () => { - const stockLocationService = appContainer.resolve("stockLocationService") - - expect( - await stockLocationService.create({ - name: "first location", - }) - ).toEqual( - expect.objectContaining({ - id: expect.any(String), - name: "first location", - deleted_at: null, - address_id: null, - metadata: null, - created_at: expect.any(Date), - updated_at: expect.any(Date), - }) - ) - - expect( - await stockLocationService.create({ - name: "second location", - metadata: { - extra: "abc", - }, - address: { - address_1: "addr_1", - address_2: "line 2", - country_code: "DK", - city: "city", - phone: "111222333", - province: "province", - postal_code: "555-714", - metadata: { - abc: 123, - }, - }, - }) - ).toEqual( - expect.objectContaining({ - id: expect.any(String), - name: "second location", - metadata: { - extra: "abc", - }, - address_id: expect.any(String), - }) - ) - }) - - it("update", async () => { - const stockLocationService = appContainer.resolve("stockLocationService") - - const loc = await stockLocationService.create({ - name: "location", - address: { - address_1: "addr_1", - address_2: "line 2", - country_code: "DK", - city: "city", - phone: "111222333", - province: "province", - postal_code: "555-714", - metadata: { - abc: 123, - }, - }, - }) - const addressId = loc.address_id - - expect( - await stockLocationService.retrieve(loc.id, { - relations: ["address"], - }) - ).toEqual( - expect.objectContaining({ - id: loc.id, - created_at: expect.any(Date), - updated_at: expect.any(Date), - deleted_at: null, - name: "location", - address_id: addressId, - metadata: null, - address: expect.objectContaining({ - id: addressId, - created_at: expect.any(Date), - updated_at: expect.any(Date), - deleted_at: null, - address_1: "addr_1", - address_2: "line 2", - company: null, - city: "city", - country_code: "DK", - phone: "111222333", - province: "province", - postal_code: "555-714", - metadata: { abc: 123 }, - }), - }) - ) - - expect( - await stockLocationService.update(loc.id, { - name: "location name", - address_id: addressId, - address: { - address_1: "addr_1 updated", - country_code: "US", - }, - }) - ).toEqual( - expect.objectContaining({ - id: loc.id, - name: "location name", - address_id: addressId, - }) - ) - - expect( - await stockLocationService.retrieve(loc.id, { - relations: ["address"], - }) - ).toEqual( - expect.objectContaining({ - id: loc.id, - created_at: expect.any(Date), - updated_at: expect.any(Date), - deleted_at: null, - name: "location name", - address_id: addressId, - metadata: null, - address: expect.objectContaining({ - id: addressId, - created_at: expect.any(Date), - updated_at: expect.any(Date), - deleted_at: null, - address_1: "addr_1 updated", - address_2: "line 2", - company: null, - city: "city", - country_code: "US", - phone: "111222333", - province: "province", - postal_code: "555-714", - metadata: { abc: 123 }, - }), - }) - ) - }) - - it("updateAddress", async () => { - const stockLocationService = appContainer.resolve("stockLocationService") - - const loc = await stockLocationService.create({ - name: "location", - address: { - address_1: "addr_1", - address_2: "line 2", - country_code: "DK", - city: "city", - phone: "111222333", - province: "province", - postal_code: "555-714", - metadata: { - abc: 123, - }, - }, - }) - const addressId = loc.address_id - - expect( - await stockLocationService.updateAddress(addressId, { - address_1: "addr_1 updated", - country_code: "US", - }) - ).toEqual( - expect.objectContaining({ - id: addressId, - address_1: "addr_1 updated", - address_2: "line 2", - country_code: "US", - city: "city", - phone: "111222333", - province: "province", - postal_code: "555-714", - metadata: { - abc: 123, - }, - }) - ) - - expect( - await stockLocationService.retrieve(loc.id, { - relations: ["address"], - }) - ).toEqual( - expect.objectContaining({ - id: loc.id, - address_id: addressId, - address: expect.objectContaining({ - id: addressId, - address_1: "addr_1 updated", - }), - }) - ) - }) - - it("delete", async () => { - const stockLocationService = appContainer.resolve("stockLocationService") - - const loc = await stockLocationService.create({ - name: "location", - address: { - address_1: "addr_1", - address_2: "line 2", - country_code: "DK", - city: "city", - phone: "111222333", - province: "province", - postal_code: "555-714", - metadata: { - abc: 123, - }, - }, - }) - - await stockLocationService.delete(loc.id) - - const deletedItem = stockLocationService.retrieve(loc.id) - - await expect(deletedItem).rejects.toThrow( - `StockLocation with id ${loc.id} was not found` - ) - }) - }) -}) diff --git a/integration-tests/plugins/__tests__/workflows/inventory/create-inventory-items.ts b/integration-tests/plugins/__tests__/workflows/inventory/create-inventory-items.ts deleted file mode 100644 index fdc720d1a6..0000000000 --- a/integration-tests/plugins/__tests__/workflows/inventory/create-inventory-items.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { - CreateInventoryItemActions, - createInventoryItems, -} from "@medusajs/core-flows" -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { IInventoryService, WorkflowTypes } from "@medusajs/types" - -import { pipe } from "@medusajs/workflows-sdk" -import path from "path" -import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" -import { getContainer } from "../../../../environment-helpers/use-container" -import { initDb, useDb } from "../../../../environment-helpers/use-db" - -jest.setTimeout(30000) - -describe("CreateInventoryItem workflow", function () { - let medusaContainer - let shutdownServer - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd, skipExpressListen: true }) - medusaContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - it("should compensate all the invoke if something fails", async () => { - const workflow = createInventoryItems(medusaContainer) - - workflow.appendAction( - "fail_step", - CreateInventoryItemActions.createInventoryItems, - { - invoke: pipe({}, async function failStep() { - throw new Error(`Failed`) - }), - }, - { - noCompensation: true, - } - ) - - const input: WorkflowTypes.InventoryWorkflow.CreateInventoryItemsWorkflowInputDTO = - { - inventoryItems: [ - { - sku: "TABLE_LEG", - description: "Table Leg", - }, - ], - } - - const { result, errors, transaction } = await workflow.run({ - input, - context: {}, - throwOnError: false, - }) - - expect(errors).toEqual([ - { - action: "fail_step", - handlerType: "invoke", - error: expect.objectContaining({ message: `Failed` }), - }, - ]) - - expect(transaction.getState()).toEqual("reverted") - - expect(result).toHaveLength(1) - expect(result[0].inventoryItem).toEqual( - expect.objectContaining({ id: expect.any(String) }) - ) - - const inventoryService: IInventoryService = medusaContainer.resolve( - ModuleRegistrationName.INVENTORY - ) - - const [inventoryItems] = await inventoryService.listInventoryItems( - { id: result[0].inventoryItem.id }, - { withDeleted: true } - ) - - expect(inventoryItems[0]).toEqual( - expect.objectContaining({ - id: result[0].inventoryItem.id, - deleted_at: expect.any(Date), - }) - ) - }) -}) diff --git a/integration-tests/plugins/__tests__/workflows/product/create-product.ts b/integration-tests/plugins/__tests__/workflows/product/create-product.ts deleted file mode 100644 index b888e5692c..0000000000 --- a/integration-tests/plugins/__tests__/workflows/product/create-product.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { - CreateProductsActions, - Handlers, - createProducts, -} from "@medusajs/core-flows" -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { IProductModuleService, WorkflowTypes } from "@medusajs/types" -import { pipe } from "@medusajs/workflows-sdk" -import path from "path" -import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" -import { getContainer } from "../../../../environment-helpers/use-container" -import { initDb, useDb } from "../../../../environment-helpers/use-db" - -jest.setTimeout(50000) - -describe.skip("CreateProduct workflow", function () { - let medusaContainer - let shutdownServer - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd, skipExpressListen: true }) - medusaContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - it("should compensate all the invoke if something fails", async () => { - const workflow = createProducts(medusaContainer) - - workflow.appendAction( - "fail_step", - CreateProductsActions.attachInventoryItems, - { - invoke: pipe({}, async function failStep() { - throw new Error(`Failed to create products`) - }), - }, - { - noCompensation: true, - } - ) - - const input: WorkflowTypes.ProductWorkflow.CreateProductsWorkflowInputDTO = - { - products: [ - { - title: "Test product", - type: { value: "physical" }, - tags: [{ value: "test" }], - subtitle: "Test subtitle", - variants: [ - { - title: "Test variant", - prices: [ - { - amount: 100, - currency_code: "usd", - }, - ], - }, - ], - options: [ - { - title: "Test option", - }, - ], - }, - ], - } - - const manager = medusaContainer.resolve("manager") - const context = { - manager, - } - - const { result, errors, transaction } = await workflow.run({ - input, - context, - throwOnError: false, - }) - - expect(errors).toEqual([ - { - action: "fail_step", - handlerType: "invoke", - error: expect.objectContaining({ - message: `Failed to create products`, - }), - }, - ]) - - expect(transaction.getState()).toEqual("reverted") - - expect(result).toHaveLength(1) - expect(result[0]).toEqual( - expect.objectContaining({ - id: expect.any(String), - }) - ) - - const productId = result[0].id - - let [product] = await Handlers.ProductHandlers.listProducts({ - container: medusaContainer, - context, - data: { - ids: [productId], - }, - } as any) - - expect(product).toBeUndefined() - - const productModule = medusaContainer.resolve( - ModuleRegistrationName.PRODUCT - ) as IProductModuleService - - ;[product] = await productModule.list( - { - id: productId, - }, - { - withDeleted: true, - } - ) - - expect(product).toEqual( - expect.objectContaining({ - deleted_at: expect.any(Date), - }) - ) - }) -}) diff --git a/integration-tests/plugins/__tests__/workflows/product/update-product.ts b/integration-tests/plugins/__tests__/workflows/product/update-product.ts deleted file mode 100644 index c795e09a24..0000000000 --- a/integration-tests/plugins/__tests__/workflows/product/update-product.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { - Handlers, - updateProducts, - UpdateProductsActions, -} from "@medusajs/core-flows" -import { WorkflowTypes } from "@medusajs/types" -import { pipe } from "@medusajs/workflows-sdk" -import path from "path" - -import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" -import { getContainer } from "../../../../environment-helpers/use-container" -import { initDb, useDb } from "../../../../environment-helpers/use-db" -import { simpleProductFactory } from "../../../../factories" - -jest.setTimeout(100000) - -describe.skip("UpdateProduct workflow", function () { - let dbConnection - let medusaContainer - let shutdownServer - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd }) - shutdownServer = await startBootstrapApp({ cwd, skipExpressListen: true }) - medusaContainer = getContainer() - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - await shutdownServer() - }) - - beforeEach(async () => { - await simpleProductFactory(dbConnection, { - title: "Original title", - id: "to-update", - variants: [{ id: "original-variant" }], - }) - }) - - it("should compensate all the invoke if something fails", async () => { - const workflow = updateProducts(medusaContainer) - - workflow.appendAction( - "fail_step", - UpdateProductsActions.removeInventoryItems, - { - invoke: pipe({}, async function failStep() { - throw new Error(`Failed to update products`) - }), - }, - { - noCompensation: true, - } - ) - - const input: WorkflowTypes.ProductWorkflow.UpdateProductsWorkflowInputDTO = - { - products: [ - { - id: "to-update", - title: "Updated title", - variants: [ - { - title: "Should be deleted with revert variant", - }, - ], - }, - ], - } - - const manager = medusaContainer.resolve("manager") - const context = { - manager, - } - - const { errors, transaction } = await workflow.run({ - input, - context, - throwOnError: false, - }) - - expect(errors).toEqual([ - { - action: "fail_step", - handlerType: "invoke", - error: expect.objectContaining({ - message: `Failed to update products`, - }), - }, - ]) - - expect(transaction.getState()).toEqual("reverted") - - let [product] = await Handlers.ProductHandlers.listProducts({ - container: medusaContainer, - context, - data: { - ids: ["to-update"], - config: { listConfig: { relations: ["variants"] } }, - }, - } as any) - - expect(product).toEqual( - expect.objectContaining({ - title: "Original title", - id: "to-update", - variants: [expect.objectContaining({ id: "original-variant" })], - }) - ) - }) -}) diff --git a/integration-tests/plugins/helpers/call-helpers.js b/integration-tests/plugins/helpers/call-helpers.js deleted file mode 100644 index 18f2ac1eb4..0000000000 --- a/integration-tests/plugins/helpers/call-helpers.js +++ /dev/null @@ -1,100 +0,0 @@ -const { useApi } = require("../../helpers/use-api") - -const header = { - headers: { - "x-medusa-access-token": "test_token", - }, -} - -const resolveCall = async (path, payload, header) => { - const api = useApi() - let res - try { - const resp = await api.post(path, payload, header) - res = resp.status - } catch (expectedException) { - try { - res = expectedException.response.status - } catch (_) { - console.error(expectedException) - } - } - return res -} - -const determineFail = (actual, expected, path) => { - if (expected !== actual) { - console.log(`failed at path : ${path}`) - } - expect(actual).toEqual(expected) -} - -/** - * Allows you to wrap a Call function so that you may reuse some input values. - * @param {Function} fun - the function to call with partial information - * @param {Object} input - the constant input which we want to supply now - * @returns - */ -module.exports.partial = function (fun, input = {}) { - return async (remaining) => await fun({ ...remaining, ...input }) -} - -/** - * Allows you to assert a specific code result from a POST call. - * @param {Object} input - the information needed to make the call - * (path & payload) and the expected code (code) - */ -module.exports.expectPostCallToReturn = async function ( - input = { - code, - path, - payload: {}, - } -) { - const res = await resolveCall(input.path, input.payload, header) - determineFail(res, input.code, input.path) -} - -/** - * Allows you to assert a specific code result from multiple POST - * calls. - * @param {Object} input - the collection of objects to execute - * calls from (col), a function which yields the path (pathf), - * and another one which provides the payload (payloadf), as - * well as the code (code) which we want to assert. - */ -module.exports.expectAllPostCallsToReturn = async function ( - input = { - code, - col, - pathf, - payloadf, - } -) { - for (const i of input.col) { - const res = await resolveCall( - input.pathf(i), - input.payloadf ? input.payloadf(i) : {}, - header - ) - determineFail(res, input.code, input.pathf(i)) - } -} - -/** - * Allows you to retrieve a specific object the response - * from get call, - * and simultaneously assert that the call was successful. - * @param {Object} param0 - contains the path which to - * call (path), and the object within the response.data (get) - * we want to retrieve. - * @returns {Object} found within response.data corresponding - * to the get parameter provided. - */ -module.exports.callGet = async function ({ path, get }) { - const api = useApi() - const res = await api.get(path, header) - - determineFail(res.status, 200, path) - return res?.data[get] -} diff --git a/integration-tests/plugins/jest.config.js b/integration-tests/plugins/jest.config.js deleted file mode 100644 index ee258587fa..0000000000 --- a/integration-tests/plugins/jest.config.js +++ /dev/null @@ -1,23 +0,0 @@ -process.chdir(__dirname) - -module.exports = { - name: "Plugins", - testEnvironment: `node`, - rootDir: "./", - testPathIgnorePatterns: [ - `/examples/`, - `/www/`, - `/dist/`, - `/node_modules/`, - `/node_modules/`, - `__tests__/fixtures`, - `__testfixtures__`, - `.cache`, - ], - transformIgnorePatterns: ["/dist", "/node_modules/"], - transform: { "^.+\\.[jt]s$": `@swc/jest` }, - setupFiles: ["../setup-env.js"], - setupFilesAfterEnv: ["../setup.js"], - globalSetup: "../globalSetup.js", - globalTeardown: "../globalTeardown.js", -} diff --git a/integration-tests/plugins/medusa-config.js b/integration-tests/plugins/medusa-config.js deleted file mode 100644 index 6dc67d716c..0000000000 --- a/integration-tests/plugins/medusa-config.js +++ /dev/null @@ -1,71 +0,0 @@ -const { Modules } = require("@medusajs/modules-sdk") -const DB_HOST = process.env.DB_HOST -const DB_USERNAME = process.env.DB_USERNAME -const DB_PASSWORD = process.env.DB_PASSWORD -const DB_NAME = process.env.DB_TEMP_NAME -const DB_URL = `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME}` - -process.env.POSTGRES_URL = DB_URL -process.env.LOG_LEVEL = "error" - -const enableMedusaV2 = process.env.MEDUSA_FF_MEDUSA_V2 == "true" - -module.exports = { - plugins: [], - projectConfig: { - // redis_url: REDIS_URL, - database_url: DB_URL, - database_type: "postgres", - jwt_secret: "test", - cookie_secret: "test", - database_extra: { idle_in_transaction_session_timeout: 0 }, - }, - featureFlags: { - medusa_v2: enableMedusaV2, - }, - modules: { - workflows: true, - - [Modules.AUTH]: { - scope: "internal", - resources: "shared", - resolve: "@medusajs/auth", - options: { - providers: [ - { - name: "emailpass", - scopes: { - admin: {}, - store: {}, - }, - }, - ], - }, - }, - [Modules.STOCK_LOCATION]: { - scope: "internal", - resources: "shared", - resolve: "@medusajs/stock-location", - }, - [Modules.INVENTORY]: { - scope: "internal", - resources: "shared", - resolve: "@medusajs/inventory", - }, - [Modules.PRICING]: { - scope: "internal", - resources: "shared", - resolve: "@medusajs/pricing", - }, - [Modules.CACHE]: { - resolve: "@medusajs/cache-inmemory", - options: { ttl: 0 }, // Cache disabled - }, - [Modules.PRODUCT]: { - scope: "internal", - resources: "shared", - resolve: "@medusajs/product", - }, - [Modules.WORKFLOW_ENGINE]: true, - }, -} diff --git a/integration-tests/plugins/package.json b/integration-tests/plugins/package.json deleted file mode 100644 index fece386c8b..0000000000 --- a/integration-tests/plugins/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "integration-tests-plugins", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "private": true, - "scripts": { - "test:integration": "jest --silent=false --maxWorkers=50% --bail --detectOpenHandles --clearMocks --forceExit", - "build": "babel src -d dist --extensions \".ts,.js\"" - }, - "dependencies": { - "@medusajs/api-key": "workspace:^", - "@medusajs/auth": "workspace:*", - "@medusajs/cache-inmemory": "workspace:*", - "@medusajs/currency": "workspace:^", - "@medusajs/customer": "workspace:^", - "@medusajs/event-bus-local": "workspace:*", - "@medusajs/inventory": "latest", - "@medusajs/inventory-next": "workspace:^", - "@medusajs/medusa": "workspace:*", - "@medusajs/modules-sdk": "workspace:^", - "@medusajs/pricing": "workspace:^", - "@medusajs/product": "workspace:^", - "@medusajs/promotion": "workspace:^", - "@medusajs/region": "workspace:^", - "@medusajs/stock-location": "latest", - "@medusajs/store": "workspace:^", - "@medusajs/tax": "workspace:^", - "@medusajs/user": "workspace:^", - "@medusajs/utils": "workspace:^", - "@medusajs/workflow-engine-inmemory": "workspace:*", - "faker": "^5.5.3", - "medusa-interfaces": "workspace:*", - "pg": "^8.11.0", - "typeorm": "^0.3.16" - }, - "devDependencies": { - "@babel/cli": "^7.12.10", - "@babel/core": "^7.12.10", - "@babel/node": "^7.12.10", - "@medusajs/types": "workspace:^", - "@swc/core": "^1.4.8", - "@swc/jest": "^0.2.36", - "babel-preset-medusa-package": "*", - "jest": "^26.6.3", - "jest-environment-node": "26.6.2" - } -} diff --git a/integration-tests/plugins/src/services/local-file-service.js b/integration-tests/plugins/src/services/local-file-service.js deleted file mode 100644 index dc4fbfbe33..0000000000 --- a/integration-tests/plugins/src/services/local-file-service.js +++ /dev/null @@ -1,96 +0,0 @@ -import { AbstractFileService } from "@medusajs/medusa" -import * as fs from "fs" -import mkdirp from "mkdirp" -import { resolve } from "path" -import stream from "stream" - -export default class LocalFileService extends AbstractFileService { - constructor({}, options) { - super({}, options) - this.upload_dir_ = - process.env.UPLOAD_DIR ?? options.upload_dir ?? "uploads/images" - - if (!fs.existsSync(this.upload_dir_)) { - fs.mkdirSync(this.upload_dir_) - } - } - - upload(file) { - return new Promise((resolvePromise, reject) => { - const path = resolve(this.upload_dir_, file.originalname) - - let content = "" - if (file.filename) { - content = fs.readFileSync( - resolve(process.cwd(), "uploads", file.filename) - ) - } - - const pathSegments = path.split("/") - pathSegments.splice(-1) - const dirname = pathSegments.join("/") - mkdirp.sync(dirname, { recursive: true }) - - fs.writeFile(path, content.toString(), (err) => { - if (err) { - reject(err) - } - - resolvePromise({ url: path }) - }) - }) - } - - delete({ fileKey }) { - return new Promise((resolvePromise, reject) => { - const path = resolve(this.upload_dir_, fileKey) - fs.unlink(path, (err) => { - if (err) { - reject(err) - } - - resolvePromise("file unlinked") - }) - }) - } - - async getUploadStreamDescriptor({ name, ext }) { - const fileKey = `${name}.${ext}` - const path = resolve(this.upload_dir_, fileKey) - - const isFileExists = fs.existsSync(path) - if (!isFileExists) { - await this.upload({ originalname: fileKey }) - } - - const pass = new stream.PassThrough() - pass.pipe(fs.createWriteStream(path)) - - return { - writeStream: pass, - promise: Promise.resolve(), - url: `${this.upload_dir_}/${fileKey}`, - fileKey, - } - } - - async getDownloadStream({ fileKey }) { - return new Promise((resolvePromise, reject) => { - try { - const path = resolve(this.upload_dir_, fileKey) - const data = fs.readFileSync(path) - const readable = stream.Readable() - readable._read = function () {} - readable.push(data.toString()) - readable.push(null) - resolvePromise(readable) - } catch (e) { - reject(e) - } - }) - } - - async getPresignedDownloadUrl({ fileKey }) { - return `${this.upload_dir_}/${fileKey}` - } -} diff --git a/integration-tests/plugins/src/services/test-ful.js b/integration-tests/plugins/src/services/test-ful.js deleted file mode 100644 index f7726108ac..0000000000 --- a/integration-tests/plugins/src/services/test-ful.js +++ /dev/null @@ -1,53 +0,0 @@ -import { FulfillmentService } from "medusa-interfaces" - -class TestFulService extends FulfillmentService { - static identifier = "test-ful" - - constructor() { - super() - } - - getFulfillmentOptions() { - return [ - { - id: "manual-fulfillment", - }, - ] - } - - validateFulfillmentData(data, cart) { - return data - } - - validateOption(data) { - return true - } - - canCalculate() { - return false - } - - calculatePrice() { - throw Error("Manual Fulfillment service cannot calculatePrice") - } - - createOrder() { - // No data is being sent anywhere - return Promise.resolve({}) - } - - createReturn() { - return Promise.resolve({}) - } - - createFulfillment() { - // No data is being sent anywhere - return Promise.resolve({}) - } - - cancelFulfillment() { - return Promise.resolve({}) - } -} - -export default TestFulService diff --git a/integration-tests/plugins/src/services/test-not.js b/integration-tests/plugins/src/services/test-not.js deleted file mode 100644 index 39c5ba665a..0000000000 --- a/integration-tests/plugins/src/services/test-not.js +++ /dev/null @@ -1,19 +0,0 @@ -import { NotificationService } from "medusa-interfaces" - -class TestNotiService extends NotificationService { - static identifier = "test-not" - - constructor() { - super() - } - - async sendNotification() { - return Promise.resolve() - } - - async resendNotification() { - return Promise.resolve() - } -} - -export default TestNotiService diff --git a/integration-tests/plugins/src/services/test-pay.js b/integration-tests/plugins/src/services/test-pay.js deleted file mode 100644 index c678898453..0000000000 --- a/integration-tests/plugins/src/services/test-pay.js +++ /dev/null @@ -1,73 +0,0 @@ -import { AbstractPaymentService } from "@medusajs/medusa" - -class TestPayService extends AbstractPaymentService { - static identifier = "test-pay" - - constructor(_) { - super(_) - } - - async getStatus(paymentData) { - return "authorized" - } - - async retrieveSavedMethods(customer) { - return [] - } - - async createPayment(cart) { - const fields = [ - "total", - "subtotal", - "tax_total", - "discount_total", - "shipping_total", - "gift_card_total", - ] - - const data = {} - for (const k of fields) { - data[k] = cart[k] - } - - return data - } - - async retrievePayment(data) { - return {} - } - - async getPaymentData(sessionData) { - return {} - } - - async authorizePayment(sessionData, context = {}) { - return { data: {}, status: "authorized" } - } - - async updatePaymentData(sessionData, update) { - return {} - } - - async updatePayment(sessionData, cart) { - return {} - } - - async deletePayment(payment) { - return {} - } - - async capturePayment(payment) { - return {} - } - - async refundPayment(payment, amountToRefund) { - return {} - } - - async cancelPayment(payment) { - return {} - } -} - -export default TestPayService diff --git a/integration-tests/repositories/__tests__/product-categories/queries.ts b/integration-tests/repositories/__tests__/product-categories/queries.ts deleted file mode 100644 index 6d6701b87d..0000000000 --- a/integration-tests/repositories/__tests__/product-categories/queries.ts +++ /dev/null @@ -1,231 +0,0 @@ -import { ProductCategoryRepository } from "@medusajs/medusa/dist/repositories/product-category" -import path from "path" -import { initDb, useDb } from "../../../environment-helpers/use-db" -import { simpleProductCategoryFactory } from "../../../factories" - -jest.setTimeout(30000) - -describe("Product Categories", () => { - let dbConnection - - beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..")) - dbConnection = await initDb({ cwd }) - }) - - afterAll(async () => { - const db = useDb() - await db.shutdown() - }) - - afterEach(async () => { - const db = useDb() - await db.teardown() - }) - - describe("Tree Queries (Materialized Paths)", () => { - let a1, a11, a111, a12 - let productCategoryRepository - - beforeEach(async () => { - a1 = await simpleProductCategoryFactory(dbConnection, { - name: "a1", - is_active: true, - rank: 0, - }) - a11 = await simpleProductCategoryFactory(dbConnection, { - name: "a11", - parent_category: a1, - is_active: true, - rank: 0, - }) - a111 = await simpleProductCategoryFactory(dbConnection, { - name: "a111", - parent_category: a11, - is_active: true, - is_internal: true, - rank: 0, - }) - a12 = await simpleProductCategoryFactory(dbConnection, { - name: "a12", - parent_category: a1, - is_active: false, - rank: 1, - }) - - productCategoryRepository = dbConnection.manager.withRepository( - ProductCategoryRepository - ) - }) - - it("can fetch all root categories", async () => { - const rootCategories = await productCategoryRepository.findRoots() - - expect(rootCategories).toEqual([ - expect.objectContaining({ - name: "a1", - }), - ]) - }) - - it("can fetch all ancestors of a category", async () => { - const a11Parent = await productCategoryRepository.findAncestors(a11) - - expect(a11Parent).toEqual([ - expect.objectContaining({ - name: "a1", - }), - expect.objectContaining({ - name: "a11", - }), - ]) - }) - - it("can fetch all root descendants of a category", async () => { - const a1Children = await productCategoryRepository.findDescendants(a1) - - expect(a1Children).toEqual([ - expect.objectContaining({ - name: "a1", - }), - expect.objectContaining({ - name: "a11", - }), - expect.objectContaining({ - name: "a111", - }), - expect.objectContaining({ - name: "a12", - }), - ]) - }) - }) - - describe("getFreeTextSearchResultsAndCount", () => { - let a1, a11, a111, a12 - let productCategoryRepository - - beforeEach(async () => { - a1 = await simpleProductCategoryFactory(dbConnection, { - name: "skinny jeans", - handle: "skinny-jeans", - is_active: true, - rank: 0, - }) - - a11 = await simpleProductCategoryFactory(dbConnection, { - name: "winter shirts", - handle: "winter-shirts", - parent_category: a1, - is_active: true, - rank: 0, - }) - - a111 = await simpleProductCategoryFactory(dbConnection, { - name: "running shoes", - handle: "running-shoes", - parent_category: a11, - rank: 0, - }) - - a12 = await simpleProductCategoryFactory(dbConnection, { - name: "casual shoes", - handle: "casual-shoes", - parent_category: a1, - is_internal: true, - rank: 1, - }) - - productCategoryRepository = dbConnection.manager.withRepository( - ProductCategoryRepository - ) - }) - - it("fetches all active categories", async () => { - const [categories, count] = - await productCategoryRepository.getFreeTextSearchResultsAndCount({ - where: { is_active: true }, - }) - - expect(count).toEqual(2) - expect(categories).toEqual([ - expect.objectContaining({ - name: a1.name, - }), - expect.objectContaining({ - name: a11.name, - }), - ]) - }) - - it("fetches all internal categories", async () => { - const [categories, count] = - await productCategoryRepository.getFreeTextSearchResultsAndCount({ - where: { is_internal: true }, - }) - - expect(count).toEqual(1) - expect(categories).toEqual([ - expect.objectContaining({ - name: a12.name, - }), - ]) - }) - - it("fetches all categories with query shoes", async () => { - const [categories, count] = - await productCategoryRepository.getFreeTextSearchResultsAndCount( - { where: {} }, - "shoes" - ) - - expect(count).toEqual(2) - expect(categories).toEqual([ - expect.objectContaining({ - name: a111.name, - }), - expect.objectContaining({ - name: a12.name, - }), - ]) - }) - - it("fetches all categories with query casual-", async () => { - const [categories, count] = - await productCategoryRepository.getFreeTextSearchResultsAndCount( - { where: {} }, - "casual-" - ) - - expect(count).toEqual(1) - expect(categories).toEqual([ - expect.objectContaining({ - name: a12.name, - }), - ]) - }) - - it("builds relations for categories", async () => { - const [categories, count] = - await productCategoryRepository.getFreeTextSearchResultsAndCount({ - where: { id: a11.id }, - relations: { parent_category: true, category_children: true }, - }) - - expect(count).toEqual(1) - expect(categories[0]).toEqual( - expect.objectContaining({ - id: a11.id, - parent_category: expect.objectContaining({ - id: a1.id, - }), - category_children: [ - expect.objectContaining({ - id: a111.id, - }), - ], - }) - ) - }) - }) -}) diff --git a/integration-tests/repositories/jest.config.js b/integration-tests/repositories/jest.config.js deleted file mode 100644 index 8aac35f8d7..0000000000 --- a/integration-tests/repositories/jest.config.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - name: "repositories", - testEnvironment: `node`, - rootDir: "./", - testTimeout: 10000, - testPathIgnorePatterns: [ - `/examples/`, - `/www/`, - `/dist/`, - `/node_modules/`, - `__tests__/fixtures`, - `__testfixtures__`, - `.cache`, - ], - transformIgnorePatterns: ["/dist", "/node_modules/"], - transform: { "^.+\\.[jt]s$": `../../jest-transformer.js` }, - setupFiles: ["../setup-env.js"], - setupFilesAfterEnv: ["../setup.js"], - globalSetup: "../globalSetup.js", - globalTeardown: "../globalTeardown.js", -} diff --git a/integration-tests/repositories/medusa-config.js b/integration-tests/repositories/medusa-config.js deleted file mode 100644 index ef42b43153..0000000000 --- a/integration-tests/repositories/medusa-config.js +++ /dev/null @@ -1,15 +0,0 @@ -const DB_HOST = process.env.DB_HOST -const DB_USERNAME = process.env.DB_USERNAME -const DB_PASSWORD = process.env.DB_PASSWORD -const DB_NAME = process.env.DB_TEMP_NAME - -module.exports = { - plugins: [], - projectConfig: { - redis_url: process.env.REDIS_URL, - database_url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME}`, - database_type: "postgres", - jwt_secret: "test", - cookie_secret: "test", - }, -} diff --git a/integration-tests/repositories/package.json b/integration-tests/repositories/package.json deleted file mode 100644 index 0555cd2a4a..0000000000 --- a/integration-tests/repositories/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "integration-tests-repositories", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "private": true, - "scripts": { - "test:integration": "jest --silent=false --runInBand --bail --detectOpenHandles --forceExit" - }, - "dependencies": { - "@medusajs/cache-inmemory": "workspace:*", - "@medusajs/event-bus-local": "workspace:*", - "@medusajs/medusa": "workspace:*", - "medusa-interfaces": "workspace:*", - "pg": "^8.11.0", - "typeorm": "^0.3.16" - }, - "devDependencies": { - "@babel/cli": "^7.12.10", - "@babel/core": "^7.12.10", - "@babel/node": "^7.12.10", - "babel-preset-medusa-package": "*", - "jest": "^26.6.3", - "jest-environment-node": "26.6.2" - } -} diff --git a/jest.config.js b/jest.config.js index 15a7efc0f8..8e1beec8e0 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,7 +2,15 @@ const path = require(`path`) const glob = require(`glob`) const fs = require(`fs`) -const pkgs = glob.sync(`./packages/*`).map((p) => p.replace(/^\./, ``)) +const pkgs = [ + glob.sync(`./packages/*`).map((p) => p.replace(/^\./, ``)), + glob.sync(`./packages/cli/*`).map((p) => p.replace(/^\./, ``)), + glob.sync(`./packages/core/*`).map((p) => p.replace(/^\./, ``)), + glob.sync(`./packages/modules/*`).map((p) => p.replace(/^\./, ``)), + glob + .sync(`./packages/modules/providers/*`) + .map((p) => p.replace(/^\./, ``)), +].flat(Infinity) const reMedusa = /medusa$/ const medusaDir = pkgs.find((p) => reMedusa.exec(p)) @@ -26,7 +34,13 @@ module.exports = { notify: true, verbose: true, roots: [""], - projects: ["/packages/*/jest.config.js"], + projects: [ + "/packages/*/jest.config.js", + "/packages/cli/*/jest.config.js", + "/packages/core/*/jest.config.js", + "/packages/modules/*/jest.config.js", + "/packages/modules/providers/*/jest.config.js", + ], modulePathIgnorePatterns: ignoreDirs, coveragePathIgnorePatterns: ignoreDirs, testPathIgnorePatterns: [ diff --git a/package.json b/package.json index 1cfdf0aa8d..145824857d 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,6 @@ "packages/core/*", "packages/cli/*", "packages/cli/oas/*", - "packages/medusa-js", - "packages/medusa-react", "packages/*", "packages/admin-next/*", "packages/design-system/*", @@ -78,15 +76,11 @@ "test:chunk": "./scripts/run-workspace-unit-tests-in-chunks.sh", "test:integration:packages": "turbo run test:integration --concurrency=50% --no-daemon --no-cache --force --filter='./packages/*' --filter='./packages/core/*' --filter='./packages/cli/*' --filter='./packages/modules/*' --filter='./packages/modules/providers/*'", "test:integration:api": "turbo run test:integration:chunk --concurrency=50% --no-daemon --no-cache --force --filter=integration-tests-api", - "test:integration:plugins": "turbo run test:integration --concurrency=50% --no-daemon --no-cache --filter=integration-tests-plugins", "test:integration:modules": "turbo run test:integration:chunk --concurrency=50% --no-daemon --no-cache --force --filter=integration-tests-modules", - "test:integration:repositories": "turbo run test:integration --concurrency=50% --no-daemon --no-cache --filter=integration-tests-repositories", - "openapi:generate": "yarn ./packages/cli/oas/oas-github-ci run ci --with-full-file", - "medusa-oas": "yarn ./packages/cli/oas/medusa-oas-cli run medusa-oas", + "openapi:generate": "yarn ./packages/oas/oas-github-ci run ci --with-full-file --v2", + "medusa-oas": "yarn ./packages/oas/medusa-oas-cli run medusa-oas --v2", "release:snapshot": "changeset publish --no-git-tags --snapshot --tag snapshot", - "develop": "ts-node --transpile-only ./integration-tests/development/server.js", - "develop:create:db": "ts-node --transpile-only ./integration-tests/development/create-database.js", - "release:next": "changeset publish --no-git-tags --snapshot --tag next", + "release:next": "chgstangeset publish --no-git-tags --snapshot --tag next", "version:next": "changeset version --snapshot next", "release": "changeset publish", "version": "changeset version && yarn install --no-immutable" diff --git a/packages/admin-next/dashboard/package.json b/packages/admin-next/dashboard/package.json index 1fd5ac3355..0896feab65 100644 --- a/packages/admin-next/dashboard/package.json +++ b/packages/admin-next/dashboard/package.json @@ -36,7 +36,7 @@ "i18next-browser-languagedetector": "7.2.0", "i18next-http-backend": "2.4.2", "match-sorter": "^6.3.4", - "medusa-react": "workspace:^", + "medusa-react": "latest", "qs": "^6.12.0", "react": "^18.2.0", "react-country-flag": "^3.1.0", diff --git a/packages/admin-next/vite-plugin-extension/tsconfig.json b/packages/admin-next/vite-plugin-extension/tsconfig.json index 98f1c02d5c..63180f3cfb 100644 --- a/packages/admin-next/vite-plugin-extension/tsconfig.json +++ b/packages/admin-next/vite-plugin-extension/tsconfig.json @@ -12,7 +12,10 @@ "noEmit": true, "noUnusedLocals": true, "esModuleInterop": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "paths": { + "@babel/types": ["../../../node_modules/@babel/types"] + } }, "include": ["src"] } diff --git a/packages/cli/oas/medusa-oas-cli/src/command-oas.ts b/packages/cli/oas/medusa-oas-cli/src/command-oas.ts index 6798766177..a01a3b13a5 100644 --- a/packages/cli/oas/medusa-oas-cli/src/command-oas.ts +++ b/packages/cli/oas/medusa-oas-cli/src/command-oas.ts @@ -54,7 +54,7 @@ export const commandOptions: Option[] = [ ), new Option("-F, --force", "Ignore OAS validation and output OAS files."), new Option( - "--v2", + "--v2", "Generate OAS files for V2 endpoints. This loads OAS from www/utils/generated/oas-output/operations directory" ), new Option( @@ -151,7 +151,7 @@ async function getOASFromCodebase( ): Promise { /** * OAS output directory - * + * * @privateRemark * This should be the only directory OAS is loaded from for Medusa V2. * For now, we only use it if the --v2 flag it passed to the CLI tool. @@ -165,7 +165,7 @@ async function getOASFromCodebase( path.resolve(oasOutputPath, "schemas"), // We currently load error schemas from here. If we change // that in the future, we should change the path. - path.resolve(medusaPackagePath, "dist", "api/middlewares"), + path.resolve(medusaPackagePath, "dist", "utils/middlewares"), ] : [ path.resolve(medusaTypesPath, "dist"), path.resolve(medusaUtilsPath, "dist"), diff --git a/packages/core/medusa-test-utils/src/medusa-test-runner.ts b/packages/core/medusa-test-utils/src/medusa-test-runner.ts index bb8a4c5c8c..aaa69f9cc2 100644 --- a/packages/core/medusa-test-utils/src/medusa-test-runner.ts +++ b/packages/core/medusa-test-utils/src/medusa-test-runner.ts @@ -1,9 +1,9 @@ -import { getDatabaseURL } from "./database" -import { initDb } from "./medusa-test-runner-utils/use-db" -import { startBootstrapApp } from "./medusa-test-runner-utils/bootstrap-app" -import { createDatabase, dropDatabase } from "pg-god" -import {ContainerLike, MedusaContainer} from "@medusajs/types" +import { ContainerLike, MedusaContainer } from "@medusajs/types" import { createMedusaContainer } from "@medusajs/utils" +import { createDatabase, dropDatabase } from "pg-god" +import { getDatabaseURL } from "./database" +import { startBootstrapApp } from "./medusa-test-runner-utils/bootstrap-app" +import { initDb } from "./medusa-test-runner-utils/use-db" const axios = require("axios").default @@ -114,12 +114,16 @@ export function medusaIntegrationTestRunner({ ) => { const config = originalConfigLoader(rootDirectory) config.projectConfig.database_url = dbConfig.clientUrl - config.projectConfig.database_driver_options = dbConfig.clientUrl.includes("localhost") ? {} : { - connection: { - ssl: { rejectUnauthorized: false }, - }, - idle_in_transaction_session_timeout: 20000, - } + config.projectConfig.database_driver_options = dbConfig.clientUrl.includes( + "localhost" + ) + ? {} + : { + connection: { + ssl: { rejectUnauthorized: false }, + }, + idle_in_transaction_session_timeout: 20000, + } return config } @@ -224,19 +228,6 @@ export function medusaIntegrationTestRunner({ const container = options.getContainer() const copiedContainer = createMedusaContainer({}, container) - if (process.env.MEDUSA_FF_MEDUSA_V2 != "true") { - try { - const defaultLoader = - require("@medusajs/medusa/dist/loaders/defaults").default - await defaultLoader({ - container: copiedContainer, - }) - } catch (error) { - console.error("Error runner medusa loaders", error?.message) - throw error - } - } - try { const medusaAppLoaderRunner = require("@medusajs/medusa/dist/loaders/medusa-app").runModulesLoader diff --git a/packages/design-system/ui/package.json b/packages/design-system/ui/package.json index 4e4671a4f7..fb7f3c0897 100644 --- a/packages/design-system/ui/package.json +++ b/packages/design-system/ui/package.json @@ -82,10 +82,10 @@ "dependencies": { "@medusajs/icons": "^1.2.1", "@radix-ui/react-accordion": "^1.1.2", - "@radix-ui/react-alert-dialog": "^1.0.4", + "@radix-ui/react-alert-dialog": "1.0.4", "@radix-ui/react-avatar": "^1.0.3", "@radix-ui/react-checkbox": "^1.0.4", - "@radix-ui/react-dialog": "^1.0.4", + "@radix-ui/react-dialog": "1.0.4", "@radix-ui/react-dropdown-menu": "^2.0.5", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-popover": "^1.0.6", diff --git a/packages/generated/client-types/src/lib/models/AdminPostCampaignsReq.ts b/packages/generated/client-types/src/lib/models/AdminPostCampaignsReq.ts new file mode 100644 index 0000000000..e9828672f5 --- /dev/null +++ b/packages/generated/client-types/src/lib/models/AdminPostCampaignsReq.ts @@ -0,0 +1,46 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import { SetRelation, Merge } from "../core/ModelUtils" + +import type { CampaignBudget } from "./CampaignBudget" + +/** + * The promotion's campaign. + */ +export interface AdminPostCampaignsReq { + /** + * The campaign's name. + */ + name: string + /** + * The campaign's campaign identifier. + */ + campaign_identifier?: string + /** + * The campaign's description. + */ + description?: string + /** + * The campaign's currency. + */ + currency?: string + budget?: CampaignBudget + /** + * The campaign's starts at. + */ + starts_at?: string + /** + * The campaign's ends at. + */ + ends_at?: string + /** + * The campaign's promotions. + */ + promotions?: Array<{ + /** + * The promotion's ID. + */ + id: string + }> +} diff --git a/packages/generated/client-types/src/lib/models/ApplicationMethod.ts b/packages/generated/client-types/src/lib/models/ApplicationMethod.ts new file mode 100644 index 0000000000..99707bbba8 --- /dev/null +++ b/packages/generated/client-types/src/lib/models/ApplicationMethod.ts @@ -0,0 +1,9 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import { SetRelation, Merge } from "../core/ModelUtils" + +/** + * The promotion's application method. + */ +export interface ApplicationMethod {} diff --git a/packages/generated/client-types/src/lib/models/ApplicationMethodsMethodPostReq.ts b/packages/generated/client-types/src/lib/models/ApplicationMethodsMethodPostReq.ts new file mode 100644 index 0000000000..2d743c6548 --- /dev/null +++ b/packages/generated/client-types/src/lib/models/ApplicationMethodsMethodPostReq.ts @@ -0,0 +1,69 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import { SetRelation, Merge } from "../core/ModelUtils" + +/** + * The promotion's application method. + */ +export interface ApplicationMethodsMethodPostReq { + /** + * The application method's description. + */ + description?: string + /** + * The application method's value. + */ + value?: string + /** + * The application method's max quantity. + */ + max_quantity?: number + type?: "fixed" | "percentage" + target_type?: "order" | "shipping_methods" | "items" + allocation?: "each" | "across" + /** + * The application method's target rules. + */ + target_rules?: Array<{ + operator: "gte" | "lte" | "gt" | "lt" | "eq" | "ne" | "in" + /** + * The target rule's description. + */ + description?: string + /** + * The target rule's attribute. + */ + attribute: string + /** + * The target rule's values. + */ + values: Array + }> + /** + * The application method's buy rules. + */ + buy_rules?: Array<{ + operator: "gte" | "lte" | "gt" | "lt" | "eq" | "ne" | "in" + /** + * The buy rule's description. + */ + description?: string + /** + * The buy rule's attribute. + */ + attribute: string + /** + * The buy rule's values. + */ + values: Array + }> + /** + * The application method's apply to quantity. + */ + apply_to_quantity?: number + /** + * The application method's buy rules min quantity. + */ + buy_rules_min_quantity?: number +} diff --git a/packages/generated/client-types/src/lib/models/Campaign.ts b/packages/generated/client-types/src/lib/models/Campaign.ts new file mode 100644 index 0000000000..809274e05d --- /dev/null +++ b/packages/generated/client-types/src/lib/models/Campaign.ts @@ -0,0 +1,9 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import { SetRelation, Merge } from "../core/ModelUtils" + +/** + * The promotion's campaign. + */ +export interface Campaign {} diff --git a/packages/generated/client-types/src/lib/models/CampaignBudget.ts b/packages/generated/client-types/src/lib/models/CampaignBudget.ts new file mode 100644 index 0000000000..beeef8dd53 --- /dev/null +++ b/packages/generated/client-types/src/lib/models/CampaignBudget.ts @@ -0,0 +1,15 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import { SetRelation, Merge } from "../core/ModelUtils" + +/** + * The campaign's budget. + */ +export interface CampaignBudget { + type?: "spend" | "usage" + /** + * The budget's limit. + */ + limit?: number +} diff --git a/packages/generated/client-types/src/lib/models/CreateApplicationMethod.ts b/packages/generated/client-types/src/lib/models/CreateApplicationMethod.ts new file mode 100644 index 0000000000..79436e2b3c --- /dev/null +++ b/packages/generated/client-types/src/lib/models/CreateApplicationMethod.ts @@ -0,0 +1,85 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import { SetRelation, Merge } from "../core/ModelUtils" + +import type { ApplicationMethod } from "./ApplicationMethod" +import type { Campaign } from "./Campaign" + +/** + * The promotion's application method. + */ +export interface CreateApplicationMethod { + type: "fixed" | "percentage" + target_type: "order" | "shipping_methods" | "items" + allocation?: "each" | "across" + /** + * The application method's value. + */ + value?: number + /** + * The application method's max quantity. + */ + max_quantity?: number + /** + * The application method's buy rules min quantity. + */ + buy_rules_min_quantity?: number + /** + * The application method's apply to quantity. + */ + apply_to_quantity?: number + promotion?: + | string + | { + /** + * The promotion's ID. + */ + id: string + /** + * The promotion's code. + */ + code?: string + type?: "standard" | "buyget" + /** + * The promotion's is automatic. + */ + is_automatic?: boolean + application_method?: ApplicationMethod + /** + * The promotion's rules. + */ + rules?: Array + campaign?: Campaign + } + /** + * The application method's target rules. + */ + target_rules?: Array<{ + /** + * The target rule's description. + */ + description?: string + /** + * The target rule's attribute. + */ + attribute: string + operator: "gt" | "lt" | "eq" | "ne" | "in" | "lte" | "gte" + values: string | Array + }> + /** + * The application method's buy rules. + */ + buy_rules?: Array<{ + /** + * The buy rule's description. + */ + description?: string + /** + * The buy rule's attribute. + */ + attribute: string + operator: "gt" | "lt" | "eq" | "ne" | "in" | "lte" | "gte" + values: string | Array + }> +} diff --git a/packages/generated/client-types/src/lib/models/CreateCampaign.ts b/packages/generated/client-types/src/lib/models/CreateCampaign.ts new file mode 100644 index 0000000000..49d3a696c2 --- /dev/null +++ b/packages/generated/client-types/src/lib/models/CreateCampaign.ts @@ -0,0 +1,46 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import { SetRelation, Merge } from "../core/ModelUtils" + +import type { CreateCampaignBudget } from "./CreateCampaignBudget" + +/** + * The promotion's campaign. + */ +export interface CreateCampaign { + /** + * The campaign's name. + */ + name: string + /** + * The campaign's description. + */ + description?: string + /** + * The campaign's currency. + */ + currency?: string + /** + * The campaign's campaign identifier. + */ + campaign_identifier: string + /** + * The campaign's starts at. + */ + starts_at: string + /** + * The campaign's ends at. + */ + ends_at: string + budget?: CreateCampaignBudget + /** + * The campaign's promotions. + */ + promotions?: Array<{ + /** + * The promotion's ID. + */ + id: string + }> +} diff --git a/packages/generated/client-types/src/lib/models/CreateCampaignBudget.ts b/packages/generated/client-types/src/lib/models/CreateCampaignBudget.ts new file mode 100644 index 0000000000..dae531a4ed --- /dev/null +++ b/packages/generated/client-types/src/lib/models/CreateCampaignBudget.ts @@ -0,0 +1,19 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import { SetRelation, Merge } from "../core/ModelUtils" + +/** + * The campaign's budget. + */ +export interface CreateCampaignBudget { + type: "spend" | "usage" + /** + * The budget's limit. + */ + limit: number + /** + * The budget's used. + */ + used?: number +} diff --git a/packages/generated/client-types/src/lib/models/CreateDefaultTaxRate.ts b/packages/generated/client-types/src/lib/models/CreateDefaultTaxRate.ts new file mode 100644 index 0000000000..2d6cd5ebaf --- /dev/null +++ b/packages/generated/client-types/src/lib/models/CreateDefaultTaxRate.ts @@ -0,0 +1,26 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import { SetRelation, Merge } from "../core/ModelUtils" + +/** + * The tax region's default tax rate. + */ +export interface CreateDefaultTaxRate { + /** + * The default tax rate's rate. + */ + rate?: number + /** + * The default tax rate's code. + */ + code?: string + /** + * The default tax rate's name. + */ + name: string + /** + * The default tax rate's metadata. + */ + metadata?: any +} diff --git a/packages/generated/client-types/src/lib/models/CreateProductType.ts b/packages/generated/client-types/src/lib/models/CreateProductType.ts new file mode 100644 index 0000000000..99fd5258e9 --- /dev/null +++ b/packages/generated/client-types/src/lib/models/CreateProductType.ts @@ -0,0 +1,22 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import { SetRelation, Merge } from "../core/ModelUtils" + +/** + * The product's type. + */ +export interface CreateProductType { + /** + * The type's ID. + */ + id?: string + /** + * The type's value. + */ + value: string + /** + * The type's metadata. + */ + metadata?: any +} diff --git a/packages/generated/client-types/src/lib/models/StockLocationAddress.ts b/packages/generated/client-types/src/lib/models/StockLocationAddress.ts new file mode 100644 index 0000000000..b659b6676b --- /dev/null +++ b/packages/generated/client-types/src/lib/models/StockLocationAddress.ts @@ -0,0 +1,42 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import { SetRelation, Merge } from "../core/ModelUtils" + +/** + * The stock location's address. + */ +export interface StockLocationAddress { + /** + * The address's address 1. + */ + address_1: string + /** + * The address's address 2. + */ + address_2?: string + /** + * The address's company. + */ + company?: string + /** + * The address's city. + */ + city?: string + /** + * The address's country code. + */ + country_code: string + /** + * The address's phone. + */ + phone?: string + /** + * The address's postal code. + */ + postal_code?: string + /** + * The address's province. + */ + province?: string +} diff --git a/packages/generated/client-types/src/lib/models/StorePostPaymentCollectionsPaymentSessionReq.ts b/packages/generated/client-types/src/lib/models/StorePostPaymentCollectionsPaymentSessionReq.ts new file mode 100644 index 0000000000..11a0ebe236 --- /dev/null +++ b/packages/generated/client-types/src/lib/models/StorePostPaymentCollectionsPaymentSessionReq.ts @@ -0,0 +1,19 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import { SetRelation, Merge } from "../core/ModelUtils" + +/** + * SUMMARY + */ +export interface StorePostPaymentCollectionsPaymentSessionReq { + /** + * The payment collection's provider id. + */ + provider_id: string + context?: any + /** + * The payment collection's data. + */ + data?: any +} diff --git a/packages/medusa-js/.gitignore b/packages/medusa-js/.gitignore deleted file mode 100644 index bd07d4e1bc..0000000000 --- a/packages/medusa-js/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -/dist diff --git a/packages/medusa-js/CHANGELOG.md b/packages/medusa-js/CHANGELOG.md deleted file mode 100644 index 44bfd70fc7..0000000000 --- a/packages/medusa-js/CHANGELOG.md +++ /dev/null @@ -1,553 +0,0 @@ -# Change Log - -## 6.1.8 - -### Patch Changes - -- [#6700](https://github.com/medusajs/medusa/pull/6700) [`8f8a4f9b13`](https://github.com/medusajs/medusa/commit/8f8a4f9b1353087d98f6cc75346d43a7f49901a8) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Version all modules to allow for initial testing - -- [#6428](https://github.com/medusajs/medusa/pull/6428) [`44d43e8155`](https://github.com/medusajs/medusa/commit/44d43e8155d1b1ca0af5e900787411c7d0b027c0) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - feat(medusa,medusa-js,medusa-react,icons): Fixes GET /admin/products/:id/variants endpoint in the core, and medusa-js and medusa-react. Pulls latest icons from Figma into `@medusajs/icons`. - -## 6.1.7 - -### Patch Changes - -- [`20cefa033`](https://github.com/medusajs/medusa/commit/20cefa0335384e3c37f593c9698651895765234e) Thanks [@olivermrbl](https://github.com/olivermrbl)! - feat(medusa-js): add axios adapter to config - -## 6.1.6 - -### Patch Changes - -- [#6155](https://github.com/medusajs/medusa/pull/6155) [`db4da5602`](https://github.com/medusajs/medusa/commit/db4da56023c1c0563a545bffb2bec9cf0e1c4c4a) Thanks [@lukebui](https://github.com/lukebui)! - fix(@medusajs/medusa-js): correct invite resend path - -- [#6190](https://github.com/medusajs/medusa/pull/6190) [`d68089b2a`](https://github.com/medusajs/medusa/commit/d68089b2aa2fb4ab52640424ed1a378cd649364f) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - fix(medusa): Implements `listAndCount` method for UserService, and updates list endpoint to accept the expected params. - fix(medusa-js): Update `admin.users.list` to accept query params. - fix(medusa-react): Update `useAdminUsers` hook to accept query params. - -- [`4c4c0f655`](https://github.com/medusajs/medusa/commit/4c4c0f655bad4feb4c34848d195cac4fe8a902d4) Thanks [@olivermrbl](https://github.com/olivermrbl)! - feat(medusa-js): add axios adapter to config #6214 - -## 6.1.5 - -### Patch Changes - -- [#5941](https://github.com/medusajs/medusa/pull/5941) [`bfd10dada`](https://github.com/medusajs/medusa/commit/bfd10dadaf6286aa26dac96d7c0cc5bc24e43c9b) Thanks [@shahednasser](https://github.com/shahednasser)! - fix(medusa-js): remove unnecessary `query` field in `AdminInventoryItemsResource.deleteLocationLevel` method - -- [#5926](https://github.com/medusajs/medusa/pull/5926) [`f25ca30b3`](https://github.com/medusajs/medusa/commit/f25ca30b3aec558094b1dffe70583fcbba64b29a) Thanks [@olivermrbl](https://github.com/olivermrbl)! - fix(medusa, medusa-js): publishable api key bugs - -## 6.1.4 - -### Patch Changes - -- [#5582](https://github.com/medusajs/medusa/pull/5582) [`91615f9c4`](https://github.com/medusajs/medusa/commit/91615f9c459a2d8cb842561c5edb335680d30298) Thanks [@shahednasser](https://github.com/shahednasser)! - fix(@medusajs/client-types): Fix types and TSDocs - fix(medusa-react): Fix response type of Publishable API Key's list sales channels. - fix(@medusajs/medusa-js): Fix incorrect parameter and response types. - fix(@medusajs/medusa): Fix incorrect types and add TSDocs - fix(@medusajs/types): Fix incorrect types and add TSDocs - -## 6.1.3 - -### Patch Changes - -- [`045d1b6a0`](https://github.com/medusajs/medusa/commit/045d1b6a0c2b0d03e5fa1db886d1f81c843059ce) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Bump @medusajs/medusa dep - -## 6.1.2 - -### Patch Changes - -- [#5400](https://github.com/medusajs/medusa/pull/5400) [`5a5c96e21`](https://github.com/medusajs/medusa/commit/5a5c96e2118e50a558d9d6dc340e505454d4c593) Thanks [@dwene](https://github.com/dwene)! - add types to exports to help projects using moduleResolution bundler - -- [#5406](https://github.com/medusajs/medusa/pull/5406) [`98e275551`](https://github.com/medusajs/medusa/commit/98e275551415583602763cf457c3f95400209d0a) Thanks [@dPreininger](https://github.com/dPreininger)! - Fix(medusa-js): Fix JwtTokenManager.register for store domain - -## 6.1.1 - -### Patch Changes - -- [#5233](https://github.com/medusajs/medusa/pull/5233) [`0f34e0f38`](https://github.com/medusajs/medusa/commit/0f34e0f381833a4790ee590a9cbf93b7660634f3) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - feat(admin-ui, medusa, medusa-react, medusa-js): Price List UI revamp - -## 6.1.0 - -### Minor Changes - -- [#4064](https://github.com/medusajs/medusa/pull/4064) [`2caff2efc`](https://github.com/medusajs/medusa/commit/2caff2efc757a3738ae8b7ee6fde77ee7100f995) Thanks [@dPreininger](https://github.com/dPreininger)! - feat(medusa): Authentication overhaul - -## 6.0.4 - -### Patch Changes - -- [#5074](https://github.com/medusajs/medusa/pull/5074) [`7d3572302`](https://github.com/medusajs/medusa/commit/7d35723023ed5bcfaf06ff2480e97508527e8665) Thanks [@shahednasser](https://github.com/shahednasser)! - fix(medusa-react): fix `useAdminAddStoreCurrency` hook - -## 6.0.3 - -### Patch Changes - -- [#4747](https://github.com/medusajs/medusa/pull/4747) [`9469063f6`](https://github.com/medusajs/medusa/commit/9469063f643180002ede7a8e94c6de53d2770d04) Thanks [@olivermrbl](https://github.com/olivermrbl)! - fix(medusa-js): return type of collection hook + export - -- [#4761](https://github.com/medusajs/medusa/pull/4761) [`f1a05f472`](https://github.com/medusajs/medusa/commit/f1a05f4725dcc45150f014769562bd3dfbc0f1f8) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - feat(admin, admin-ui, medusa, medusa-js, medusa-react, stripe-plugin): Support admin extensions - -## 6.0.2 - -### Patch Changes - -- [#4409](https://github.com/medusajs/medusa/pull/4409) [`fe25c8a91`](https://github.com/medusajs/medusa/commit/fe25c8a91f4462c9ac5a15594fa71155df48c1eb) Thanks [@pevey](https://github.com/pevey)! - feat(medusa-react,medusa-js): Allow custom headers - -- [#4501](https://github.com/medusajs/medusa/pull/4501) [`708a55199`](https://github.com/medusajs/medusa/commit/708a55199aeb23f5a75fd240ddd10af2c95f3957) Thanks [@olivermrbl](https://github.com/olivermrbl)! - fix(medusa-js): Update ambiguous type export - -## 6.0.1 - -### Patch Changes - -- [#4276](https://github.com/medusajs/medusa/pull/4276) [`afd1b67f1`](https://github.com/medusajs/medusa/commit/afd1b67f1c7de8cf07fd9fcbdde599a37914e9b5) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Use caret range - -## 6.0.0 - -### Patch Changes - -- [#4081](https://github.com/medusajs/medusa/pull/4081) [`4f3c8f5d7`](https://github.com/medusajs/medusa/commit/4f3c8f5d70b5ae4a11e9d4a2fea4a8410b2daf47) Thanks [@pKorsholm](https://github.com/pKorsholm)! - feat(medusa,client-types,medusa-js,admin-ui,medusa-react): add reservation table and creation - -- Updated dependencies [[`0a35f21af`](https://github.com/medusajs/medusa/commit/0a35f21af7ac8b6cdc1af12a403e95f9bf6142fe), [`4fb443c0e`](https://github.com/medusajs/medusa/commit/4fb443c0ea38bde3148bce059c0ee3b91dfff3d4), [`0476f5251`](https://github.com/medusajs/medusa/commit/0476f52519237c622b37d29de0718f9774b6add7), [`0f87d3d64`](https://github.com/medusajs/medusa/commit/0f87d3d642b56bf19de8136e1f5bfedf364c5193), [`ed382f2ee`](https://github.com/medusajs/medusa/commit/ed382f2ee510cbf96164991efa7ff75e3ce659ff), [`92f01cefb`](https://github.com/medusajs/medusa/commit/92f01cefbc4a190defce425fb237d2d68728fa9a), [`e3cfbcd4a`](https://github.com/medusajs/medusa/commit/e3cfbcd4a78073c63ecd9829bc531e50d3944f07), [`6998666c6`](https://github.com/medusajs/medusa/commit/6998666c6edd6617ca61a8d39c26435bad1273e3), [`81eeaa329`](https://github.com/medusajs/medusa/commit/81eeaa32942b1a7148126a7218ceb168ce8d6cac), [`e2d29d35c`](https://github.com/medusajs/medusa/commit/e2d29d35c4c477bc9b4a3ddce1279276fd072875), [`3a38c84f8`](https://github.com/medusajs/medusa/commit/3a38c84f88b05f74ee0a172af3e3f78b2ec8c2d2), [`4f3c8f5d7`](https://github.com/medusajs/medusa/commit/4f3c8f5d70b5ae4a11e9d4a2fea4a8410b2daf47), [`a91987fab`](https://github.com/medusajs/medusa/commit/a91987fab33745f9864eab21bd1c27e8e3e24571), [`bf18bd0c8`](https://github.com/medusajs/medusa/commit/bf18bd0c8a284dd0042d4c54d84acb2e7c10edd3), [`db4199530`](https://github.com/medusajs/medusa/commit/db419953075e0907b8c4d27ab5188e9bd3e3d72b)]: - - @medusajs/medusa@1.12.0 - -## 5.0.0 - -### Patch Changes - -- Updated dependencies [[`a66646233`](https://github.com/medusajs/medusa/commit/a666462333d20821a3e50e3fbc65bc8a511c726f), [`9518efcca`](https://github.com/medusajs/medusa/commit/9518efccae1961d9b3cd1e85148e293a3744eedb), [`a86f0e815`](https://github.com/medusajs/medusa/commit/a86f0e815a9e75d7d562fbe516c5bb7e0ab1f6ee), [`cdbac2c84`](https://github.com/medusajs/medusa/commit/cdbac2c8403a3c15c0e11993f6b7dab268fa5c08), [`26963acc0`](https://github.com/medusajs/medusa/commit/26963acc0a5caa1bca97cfe4cbcee113a8d75b84)]: - - @medusajs/medusa@1.11.0 - -## 4.0.1 - -### Patch Changes - -- Updated dependencies [[`3d6bcaaf6`](https://github.com/medusajs/medusa/commit/3d6bcaaf65b3a43dfb251460d73e448870b5105f), [`7fd22ecb4`](https://github.com/medusajs/medusa/commit/7fd22ecb4d5190e92c6750a9fbf2d8534bb9f4ab), [`bd53adb23`](https://github.com/medusajs/medusa/commit/bd53adb238a64640533698fbccb98a39a0346590), [`1ea57c3a6`](https://github.com/medusajs/medusa/commit/1ea57c3a69a5377a8dd0821df819743ded4a222b), [`0c58ead6d`](https://github.com/medusajs/medusa/commit/0c58ead6d869f5605cbd2b8aca129984b7493bcf), [`cff54d732`](https://github.com/medusajs/medusa/commit/cff54d73253a4c2d16a174a28f0f5d31c94bcebd), [`a8e73942e`](https://github.com/medusajs/medusa/commit/a8e73942e69662ca673ccc4300e270ff6ab523d1), [`ff37cd190`](https://github.com/medusajs/medusa/commit/ff37cd190fa455f4ba4f76cfb4d641b1611cc32e)]: - - @medusajs/medusa@1.10.1 - -## 4.0.0 - -### Patch Changes - -- Updated dependencies [[`0e488e71b`](https://github.com/medusajs/medusa/commit/0e488e71b186f7d08b18c4c6ba409ef3cadb8152), [`538c9874b`](https://github.com/medusajs/medusa/commit/538c9874ba18c1352284089a789d4a90652bc795), [`d539c6fee`](https://github.com/medusajs/medusa/commit/d539c6feeba8ee431f9a655b6cd4e9102cba2b25), [`b7a782639`](https://github.com/medusajs/medusa/commit/b7a7826394ecd621ca80e6d4ce445ea1c26804ac), [`983872319`](https://github.com/medusajs/medusa/commit/98387231927e9872f54c9e72597576f3273de506), [`284f1eed9`](https://github.com/medusajs/medusa/commit/284f1eed9a9fc7272df3fccdb162ea93750999de), [`4e8045a0a`](https://github.com/medusajs/medusa/commit/4e8045a0ac44b1541ee3cd846079f55d3e0dc957), [`d2443d83e`](https://github.com/medusajs/medusa/commit/d2443d83e60fee3c3f28b762d66378c3f07f1b5f), [`8b93bae8f`](https://github.com/medusajs/medusa/commit/8b93bae8f8ad1f6eb43931a7ba03bfa691475eca)]: - - @medusajs/medusa@1.10.0 - -## 3.0.0 - -### Patch Changes - -- Updated dependencies [[`440f900af`](https://github.com/medusajs/medusa/commit/440f900af03dd0af29c9b16f01576d3eff45cd04), [`366b12fce`](https://github.com/medusajs/medusa/commit/366b12fcea679551c55baaeeaaf41bbddf04b972), [`7e213f210`](https://github.com/medusajs/medusa/commit/7e213f2106ed76449fbdfa6eda5594b59522443a), [`d2826872f`](https://github.com/medusajs/medusa/commit/d2826872fe487a027b677aeb43704f761a6b4e80), [`0d0e9bf20`](https://github.com/medusajs/medusa/commit/0d0e9bf2069718ac54684efbe4d449942bb2ef32), [`2be144ff0`](https://github.com/medusajs/medusa/commit/2be144ff05e852a3541a9a972942cfc15ef3bd38), [`935abeae6`](https://github.com/medusajs/medusa/commit/935abeae68012a93d820789c743941c3c1a1b802), [`3a77e8a88`](https://github.com/medusajs/medusa/commit/3a77e8a88fd327aca579bcd09d767d9315a04d7f), [`af710f1b4`](https://github.com/medusajs/medusa/commit/af710f1b48a4545a5064029a557013af34c4c100), [`491566df6`](https://github.com/medusajs/medusa/commit/491566df6b7ced35f655f810961422945e10ecd0), [`966ddd2f1`](https://github.com/medusajs/medusa/commit/966ddd2f1648d5d3c1c68094f488f307e3186d92), [`3b3236cc0`](https://github.com/medusajs/medusa/commit/3b3236cc01fc8b7448c1bdbad066a19c2c3de2c3), [`4a8562743`](https://github.com/medusajs/medusa/commit/4a8562743569f5bbb7bd0894b025a74725726529)]: - - @medusajs/medusa@1.9.0 - -## 2.0.2 - -### Patch Changes - -- Updated dependencies [[`6bb1654b6`](https://github.com/medusajs/medusa/commit/6bb1654b61880f8658bf1395e4ccef860780aac4), [`95d338262`](https://github.com/medusajs/medusa/commit/95d338262b63e3daa6697bb23806980a8b5e5cdc), [`4f58ddee0`](https://github.com/medusajs/medusa/commit/4f58ddee03509a4c46af160e5824cba80d4c950a)]: - - @medusajs/medusa@1.8.2 - -## 2.0.1 - -### Patch Changes - -- Updated dependencies [[`78ff64e78`](https://github.com/medusajs/medusa/commit/78ff64e7837f6506c641a3c97ffdfa6ee17419ee), [`1a60c6f58`](https://github.com/medusajs/medusa/commit/1a60c6f58dd80d2d8cb8ee10c186975b39325d13), [`713d85a92`](https://github.com/medusajs/medusa/commit/713d85a92cf5249e3b75b96f8bf2c25e4f9b0c90), [`914d57336`](https://github.com/medusajs/medusa/commit/914d57336bc8355533d743745989f793ffd4d513), [`60abb91b7`](https://github.com/medusajs/medusa/commit/60abb91b7c568c6c4cce3b2da7cfb8d54b078299), [`089f1eb19`](https://github.com/medusajs/medusa/commit/089f1eb19e2bb43659c5b300fccb8163c1d60b5c), [`08f85fa33`](https://github.com/medusajs/medusa/commit/08f85fa33b35e15f944a833e1401c7ba2081d3ec), [`282e239df`](https://github.com/medusajs/medusa/commit/282e239dfc0a74f0eb72b17426c8c8bffd86064a), [`abdb74d99`](https://github.com/medusajs/medusa/commit/abdb74d997f49f994bff49787a396179982843b0), [`eab2d22f7`](https://github.com/medusajs/medusa/commit/eab2d22f7d22ec53c68398558ffda32d2a734983), [`08f85fa33`](https://github.com/medusajs/medusa/commit/08f85fa33b35e15f944a833e1401c7ba2081d3ec), [`085fedb1f`](https://github.com/medusajs/medusa/commit/085fedb1f7e982859cff3ef3f1d870dce3bcc8b6), [`4d69d8ef6`](https://github.com/medusajs/medusa/commit/4d69d8ef6aef0a05d0bbb00eed045c2de511be56), [`7f6dc44be`](https://github.com/medusajs/medusa/commit/7f6dc44beb9789088f6d6b796f7545beb3653094), [`d533caa4c`](https://github.com/medusajs/medusa/commit/d533caa4c2986c1c9e320cce97423b0cdc213b6c)]: - - @medusajs/medusa@1.8.1 - -## 2.0.0 - -### Patch Changes - -- [#3041](https://github.com/medusajs/medusa/pull/3041) [`121b42acf`](https://github.com/medusajs/medusa/commit/121b42acfe98c12dd593f9b1f2072ff0f3b61724) Thanks [@riqwan](https://github.com/riqwan)! - chore(medusa): Typeorm fixes / enhancements - - - upgrade typeorm from 0.2.51 to 0.3.11 - - Plugin repository loader to work with Typeorm update - -- [#3435](https://github.com/medusajs/medusa/pull/3435) [`fe9eea4c1`](https://github.com/medusajs/medusa/commit/fe9eea4c18b7e04ba91660716c92b11a49840a3c) Thanks [@pKorsholm](https://github.com/pKorsholm)! - Add create-inventory-item endpoint - -- [#3685](https://github.com/medusajs/medusa/pull/3685) [`8ddb3952c`](https://github.com/medusajs/medusa/commit/8ddb3952c045e6c05c8d0f6922f0d4ba30cf3bd4) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Fix RC package versions - -- [#3436](https://github.com/medusajs/medusa/pull/3436) [`9ba09ba4d`](https://github.com/medusajs/medusa/commit/9ba09ba4d753f132537f0447097fe9f54922c074) Thanks [@riqwan](https://github.com/riqwan)! - feat(medusa, medusa-js, medusa-react): Add store queries to react medusa - -- [#3110](https://github.com/medusajs/medusa/pull/3110) [`12d304307`](https://github.com/medusajs/medusa/commit/12d304307af87ea9287a41869eb33ef09f273d85) Thanks [@StephixOne](https://github.com/StephixOne)! - feat(medusa,medusa-js,medusa-react): Add inventory module endpoints - -- [#3478](https://github.com/medusajs/medusa/pull/3478) [`6748877c6`](https://github.com/medusajs/medusa/commit/6748877c694c1433f666c6987f20af76b201b495) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix(oas,js,react): use AdminExtendedStoresRes instead of AdminStoresRes - -- [#3288](https://github.com/medusajs/medusa/pull/3288) [`7d585f5f8`](https://github.com/medusajs/medusa/commit/7d585f5f84a910c02d274df7a489dc3ff1ea273a) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix(oas): fix paths and fix schema names to match convention - -- [#3474](https://github.com/medusajs/medusa/pull/3474) [`02c77d705`](https://github.com/medusajs/medusa/commit/02c77d7059b7e4cb9f6ebfa8cbec2b84e86118ec) Thanks [@pKorsholm](https://github.com/pKorsholm)! - Fix(medusa): Adjust reservations correctly - -- Updated dependencies [[`d6b1ad1cc`](https://github.com/medusajs/medusa/commit/d6b1ad1ccd9a8f91b169f30ff99492cf3adcccac), [`e143a8697`](https://github.com/medusajs/medusa/commit/e143a86976a5cc6a53b7a795e8486df4db1d1c09), [`121b42acf`](https://github.com/medusajs/medusa/commit/121b42acfe98c12dd593f9b1f2072ff0f3b61724), [`84e448968`](https://github.com/medusajs/medusa/commit/84e44896836b2c44017572ac5192ab1cd937048c), [`33c6ccf05`](https://github.com/medusajs/medusa/commit/33c6ccf0591b8ef527f3b10a70b51e29751b4998), [`788ddc0f4`](https://github.com/medusajs/medusa/commit/788ddc0f43696df607f07133af15a04b29d5447d), [`5fd74b38a`](https://github.com/medusajs/medusa/commit/5fd74b38ae1b4f7dced191983b78db83f7b1f71b), [`30a320364`](https://github.com/medusajs/medusa/commit/30a3203640be9993ba2f8447abfdecc0d3e2f9b6), [`240d0ea7b`](https://github.com/medusajs/medusa/commit/240d0ea7b88ff494d0fe28c7c5348e958c14571f), [`6c0462472`](https://github.com/medusajs/medusa/commit/6c046247275c46d934f03d53471bdd555a19a9ad), [`589d1c09b`](https://github.com/medusajs/medusa/commit/589d1c09b085dcaf9667061201ac9deff3047466), [`0695ff642`](https://github.com/medusajs/medusa/commit/0695ff642b5836e7c28d40118aafe7a769023d5a), [`530740889`](https://github.com/medusajs/medusa/commit/53074088941719ac7ca435e76e3e64ba23fac200), [`13f40d721`](https://github.com/medusajs/medusa/commit/13f40d721702fbcdf6c131354ec9a81322d4a662), [`4342ac884`](https://github.com/medusajs/medusa/commit/4342ac884bc3fe473576ef10d291f3547e0ffc62), [`fe9eea4c1`](https://github.com/medusajs/medusa/commit/fe9eea4c18b7e04ba91660716c92b11a49840a3c), [`a5ad6c054`](https://github.com/medusajs/medusa/commit/a5ad6c05428e1bb090bbc5a51345a00821781c06), [`748833383`](https://github.com/medusajs/medusa/commit/748833383f4bafd05109dac7afa1286fe851cba3), [`7f87c4f2c`](https://github.com/medusajs/medusa/commit/7f87c4f2c8abb876213a595005e67d770be9cbe4), [`e5a2e9c8d`](https://github.com/medusajs/medusa/commit/e5a2e9c8d237bbe4e3563f5a7a892ca41f01ba24), [`0a02b70e5`](https://github.com/medusajs/medusa/commit/0a02b70e59cfbd8888fb58c29ee9aaf96eb8099a), [`8ddb3952c`](https://github.com/medusajs/medusa/commit/8ddb3952c045e6c05c8d0f6922f0d4ba30cf3bd4), [`fe4b8feb7`](https://github.com/medusajs/medusa/commit/fe4b8feb7e0af2ffc436ca77a769ecb37e16e652), [`aa690beed`](https://github.com/medusajs/medusa/commit/aa690beed775646cbc86b445fb5dc90dcac087d5), [`5eb61fa0e`](https://github.com/medusajs/medusa/commit/5eb61fa0ef991b8a9fabb16c2c159e51b9541867), [`f033711ad`](https://github.com/medusajs/medusa/commit/f033711ad649466d72dd9f673d75848c97c0861f), [`eed784d7d`](https://github.com/medusajs/medusa/commit/eed784d7d0b58aeddc9f6f5ea56fe80c608b22f5), [`3171b0e51`](https://github.com/medusajs/medusa/commit/3171b0e518aebcaa31bbe5c6e914d65282873cda), [`a0c919a8d`](https://github.com/medusajs/medusa/commit/a0c919a8d01ca5edf62336de48e9a112e3822f38), [`522e306e2`](https://github.com/medusajs/medusa/commit/522e306e2e9abf4afce63f30714389eba32bef7f), [`80b95a230`](https://github.com/medusajs/medusa/commit/80b95a230056d9ed15f7302f248094f879516faf), [`a1e59313c`](https://github.com/medusajs/medusa/commit/a1e59313c964a944a287b54f6654d1d19ac8a59b), [`10bf05c14`](https://github.com/medusajs/medusa/commit/10bf05c147cb65a263465129790edd44a6d8948b), [`cbbf3ca05`](https://github.com/medusajs/medusa/commit/cbbf3ca054387a900c5777c2eb0218df2c72bae6), [`9ba09ba4d`](https://github.com/medusajs/medusa/commit/9ba09ba4d753f132537f0447097fe9f54922c074), [`12d304307`](https://github.com/medusajs/medusa/commit/12d304307af87ea9287a41869eb33ef09f273d85), [`693015fde`](https://github.com/medusajs/medusa/commit/693015fde3218d67fb9c07eebeaea9950bf3f1f1), [`287c829c9`](https://github.com/medusajs/medusa/commit/287c829c9c5a9797fb8cd118b7a6066ad1935898), [`74bc4b16a`](https://github.com/medusajs/medusa/commit/74bc4b16a07f78668003ca930bf2a0d928897ceb), [`0cca13779`](https://github.com/medusajs/medusa/commit/0cca13779d0e84683193ad82ab163a10a807e903), [`aed7805c0`](https://github.com/medusajs/medusa/commit/aed7805c0e64b884007148bde90cfce7bee8aad4), [`e359d3f85`](https://github.com/medusajs/medusa/commit/e359d3f85bc12fd3868fc4b563cd994366e899dd), [`0d1b63d77`](https://github.com/medusajs/medusa/commit/0d1b63d773ad91846757a6f0b81b78b0b97b3f2b), [`4042beb10`](https://github.com/medusajs/medusa/commit/4042beb1026b9ad8b381aaa6e1a5214cd92db00f), [`809ab2e0e`](https://github.com/medusajs/medusa/commit/809ab2e0eb2d62054481fa6491d3f7cafbadab4f), [`f43e9f0f2`](https://github.com/medusajs/medusa/commit/f43e9f0f20a8b0637252951b2bdfed4d42fb9f5e), [`842423679`](https://github.com/medusajs/medusa/commit/8424236799c3789f884285cd3c8a491e91aef2ca), [`935870e01`](https://github.com/medusajs/medusa/commit/935870e010af1ec884259b1f1328421e99acc3af), [`57d7728dd`](https://github.com/medusajs/medusa/commit/57d7728dd9d00df712e1a872899b8397955dfe46), [`15f47baf5`](https://github.com/medusajs/medusa/commit/15f47baf56e6722b7821cfaa2fb468e582dfa2c1), [`999aeb116`](https://github.com/medusajs/medusa/commit/999aeb116c4742e5b5e0d80793af23f7727276f0), [`55c5fba0d`](https://github.com/medusajs/medusa/commit/55c5fba0d3dbd015c3ffd74d645a8057892d0f52), [`38503fff5`](https://github.com/medusajs/medusa/commit/38503fff56bbceb092e396ac11432a56967b53e9), [`5e405be02`](https://github.com/medusajs/medusa/commit/5e405be02cc94779222dc3d930e747027496d918), [`40de54b01`](https://github.com/medusajs/medusa/commit/40de54b0101bdfd37f577d18c10ec9f1ab1ce8fe), [`54dcc1871`](https://github.com/medusajs/medusa/commit/54dcc1871c8f28bea962dbb9df6e79b038d56449), [`478d1af8d`](https://github.com/medusajs/medusa/commit/478d1af8d0df0af16baf4f130e19b0be34f5f295), [`77d46220c`](https://github.com/medusajs/medusa/commit/77d46220c23bfe19e575cbc445874eb6c22f3c73), [`6748877c6`](https://github.com/medusajs/medusa/commit/6748877c694c1433f666c6987f20af76b201b495), [`7e17e0ddc`](https://github.com/medusajs/medusa/commit/7e17e0ddc2e6b2891e9ee1420b04a541899d2a9d), [`bca1f80dd`](https://github.com/medusajs/medusa/commit/bca1f80dd501d878455e1ad4f5091cf20ef900ea), [`7f2223b65`](https://github.com/medusajs/medusa/commit/7f2223b6507b0a3c452977bfcdee92af2086fa29), [`7d585f5f8`](https://github.com/medusajs/medusa/commit/7d585f5f84a910c02d274df7a489dc3ff1ea273a), [`4e9d257d3`](https://github.com/medusajs/medusa/commit/4e9d257d3bf76703ef5be8ca054cc9f0f7339def), [`ef5ef9f5a`](https://github.com/medusajs/medusa/commit/ef5ef9f5a26febf0b64d9981606c1e59999ca76e), [`feaf8d2e1`](https://github.com/medusajs/medusa/commit/feaf8d2e19715585d154464d003759c3a1f4f322), [`f97b3d7cc`](https://github.com/medusajs/medusa/commit/f97b3d7ccee381d3491337ab5144bb44520382a7), [`55a1f232a`](https://github.com/medusajs/medusa/commit/55a1f232a3746a22adb1fcd1844b2659077a59f9), [`966aea65c`](https://github.com/medusajs/medusa/commit/966aea65c221403bf316ae7665cc8f73bccd9c38), [`48ad2426a`](https://github.com/medusajs/medusa/commit/48ad2426aa7a604c226132e85ef3da5cce045f45)]: - - @medusajs/medusa@1.8.0 - -## 2.0.0-rc.8 - -### Patch Changes - -- Updated dependencies [[`4488ec685`](https://github.com/medusajs/medusa/commit/4488ec68524f95f367cbd352e9e5eb1957d1d0d6)]: - - @medusajs/medusa@1.8.0-rc.8 - -## 2.0.0-rc.7 - -### Patch Changes - -- Updated dependencies [[`748833383`](https://github.com/medusajs/medusa/commit/748833383f4bafd05109dac7afa1286fe851cba3), [`e5a2e9c8d`](https://github.com/medusajs/medusa/commit/e5a2e9c8d237bbe4e3563f5a7a892ca41f01ba24)]: - - @medusajs/medusa@1.8.0-rc.7 - -## 2.0.0-rc.6 - -### Patch Changes - -- Updated dependencies [[`788ddc0f4`](https://github.com/medusajs/medusa/commit/788ddc0f43696df607f07133af15a04b29d5447d), [`a5ad6c054`](https://github.com/medusajs/medusa/commit/a5ad6c05428e1bb090bbc5a51345a00821781c06), [`7f87c4f2c`](https://github.com/medusajs/medusa/commit/7f87c4f2c8abb876213a595005e67d770be9cbe4), [`eed784d7d`](https://github.com/medusajs/medusa/commit/eed784d7d0b58aeddc9f6f5ea56fe80c608b22f5), [`a0c919a8d`](https://github.com/medusajs/medusa/commit/a0c919a8d01ca5edf62336de48e9a112e3822f38), [`0cca13779`](https://github.com/medusajs/medusa/commit/0cca13779d0e84683193ad82ab163a10a807e903)]: - - @medusajs/medusa@1.8.0-rc.6 - -## 2.0.0-rc.5 - -### Patch Changes - -- Updated dependencies [[`4342ac884`](https://github.com/medusajs/medusa/commit/4342ac884bc3fe473576ef10d291f3547e0ffc62), [`809ab2e0e`](https://github.com/medusajs/medusa/commit/809ab2e0eb2d62054481fa6491d3f7cafbadab4f)]: - - @medusajs/medusa@1.8.0-rc.5 - -## 2.0.0-rc.4 - -### Patch Changes - -- Updated dependencies [[`5fd74b38a`](https://github.com/medusajs/medusa/commit/5fd74b38ae1b4f7dced191983b78db83f7b1f71b), [`999aeb116`](https://github.com/medusajs/medusa/commit/999aeb116c4742e5b5e0d80793af23f7727276f0), [`5e405be02`](https://github.com/medusajs/medusa/commit/5e405be02cc94779222dc3d930e747027496d918), [`a7e3f2d34`](https://github.com/medusajs/medusa/commit/a7e3f2d343c4059ba83022ec5c09f8101b251297)]: - - @medusajs/medusa@1.8.0-rc.4 - -## 2.0.0-rc.3 - -### Patch Changes - -- Updated dependencies [[`0695ff642`](https://github.com/medusajs/medusa/commit/0695ff642b5836e7c28d40118aafe7a769023d5a), [`693015fde`](https://github.com/medusajs/medusa/commit/693015fde3218d67fb9c07eebeaea9950bf3f1f1)]: - - @medusajs/medusa@1.8.0-rc.3 - -## 2.0.0-rc.2 - -### Patch Changes - -- chore: Fix RC package versions - -- Updated dependencies []: - - @medusajs/medusa@1.8.0-rc.2 - -## 2.0.0-rc.1 - -### Patch Changes - -- Updated dependencies [[`530740889`](https://github.com/medusajs/medusa/commit/53074088941719ac7ca435e76e3e64ba23fac200), [`e359d3f85`](https://github.com/medusajs/medusa/commit/e359d3f85bc12fd3868fc4b563cd994366e899dd), [`bca1f80dd`](https://github.com/medusajs/medusa/commit/bca1f80dd501d878455e1ad4f5091cf20ef900ea), [`5f41cd9a6`](https://github.com/medusajs/medusa/commit/5f41cd9a67eb0962f999291594c0aac5e38eb916), [`1ce3cc5ae`](https://github.com/medusajs/medusa/commit/1ce3cc5ae4e4cb16eb03be49c9287503f759fc60), [`332a9b686`](https://github.com/medusajs/medusa/commit/332a9b686bd0d224855215213dd11b4704283f62), [`feaf8d2e1`](https://github.com/medusajs/medusa/commit/feaf8d2e19715585d154464d003759c3a1f4f322)]: - - @medusajs/medusa@1.8.0-rc.1 - -## 2.0.0-rc.0 - -### Patch Changes - -- [#3041](https://github.com/medusajs/medusa/pull/3041) [`121b42acf`](https://github.com/medusajs/medusa/commit/121b42acfe98c12dd593f9b1f2072ff0f3b61724) Thanks [@riqwan](https://github.com/riqwan)! - chore(medusa): Typeorm fixes / enhancements - - - upgrade typeorm from 0.2.51 to 0.3.11 - - Plugin repository loader to work with Typeorm update - -- [#3435](https://github.com/medusajs/medusa/pull/3435) [`fe9eea4c1`](https://github.com/medusajs/medusa/commit/fe9eea4c18b7e04ba91660716c92b11a49840a3c) Thanks [@pKorsholm](https://github.com/pKorsholm)! - Add create-inventory-item endpoint - -- [#3436](https://github.com/medusajs/medusa/pull/3436) [`9ba09ba4d`](https://github.com/medusajs/medusa/commit/9ba09ba4d753f132537f0447097fe9f54922c074) Thanks [@riqwan](https://github.com/riqwan)! - feat(medusa, medusa-js, medusa-react): Add store queries to react medusa - -- [#3110](https://github.com/medusajs/medusa/pull/3110) [`12d304307`](https://github.com/medusajs/medusa/commit/12d304307af87ea9287a41869eb33ef09f273d85) Thanks [@StephixOne](https://github.com/StephixOne)! - feat(medusa,medusa-js,medusa-react): Add inventory module endpoints - -- [#3478](https://github.com/medusajs/medusa/pull/3478) [`6748877c6`](https://github.com/medusajs/medusa/commit/6748877c694c1433f666c6987f20af76b201b495) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix(oas,js,react): use AdminExtendedStoresRes instead of AdminStoresRes - -- [#3288](https://github.com/medusajs/medusa/pull/3288) [`7d585f5f8`](https://github.com/medusajs/medusa/commit/7d585f5f84a910c02d274df7a489dc3ff1ea273a) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix(oas): fix paths and fix schema names to match convention - -- [#3474](https://github.com/medusajs/medusa/pull/3474) [`02c77d705`](https://github.com/medusajs/medusa/commit/02c77d7059b7e4cb9f6ebfa8cbec2b84e86118ec) Thanks [@pKorsholm](https://github.com/pKorsholm)! - Fix(medusa): Adjust reservations correctly - -- Updated dependencies [[`d6b1ad1cc`](https://github.com/medusajs/medusa/commit/d6b1ad1ccd9a8f91b169f30ff99492cf3adcccac), [`e143a8697`](https://github.com/medusajs/medusa/commit/e143a86976a5cc6a53b7a795e8486df4db1d1c09), [`121b42acf`](https://github.com/medusajs/medusa/commit/121b42acfe98c12dd593f9b1f2072ff0f3b61724), [`84e448968`](https://github.com/medusajs/medusa/commit/84e44896836b2c44017572ac5192ab1cd937048c), [`33c6ccf05`](https://github.com/medusajs/medusa/commit/33c6ccf0591b8ef527f3b10a70b51e29751b4998), [`30a320364`](https://github.com/medusajs/medusa/commit/30a3203640be9993ba2f8447abfdecc0d3e2f9b6), [`240d0ea7b`](https://github.com/medusajs/medusa/commit/240d0ea7b88ff494d0fe28c7c5348e958c14571f), [`6c0462472`](https://github.com/medusajs/medusa/commit/6c046247275c46d934f03d53471bdd555a19a9ad), [`589d1c09b`](https://github.com/medusajs/medusa/commit/589d1c09b085dcaf9667061201ac9deff3047466), [`13f40d721`](https://github.com/medusajs/medusa/commit/13f40d721702fbcdf6c131354ec9a81322d4a662), [`fe9eea4c1`](https://github.com/medusajs/medusa/commit/fe9eea4c18b7e04ba91660716c92b11a49840a3c), [`0a02b70e5`](https://github.com/medusajs/medusa/commit/0a02b70e59cfbd8888fb58c29ee9aaf96eb8099a), [`fe4b8feb7`](https://github.com/medusajs/medusa/commit/fe4b8feb7e0af2ffc436ca77a769ecb37e16e652), [`aa690beed`](https://github.com/medusajs/medusa/commit/aa690beed775646cbc86b445fb5dc90dcac087d5), [`5eb61fa0e`](https://github.com/medusajs/medusa/commit/5eb61fa0ef991b8a9fabb16c2c159e51b9541867), [`f033711ad`](https://github.com/medusajs/medusa/commit/f033711ad649466d72dd9f673d75848c97c0861f), [`3171b0e51`](https://github.com/medusajs/medusa/commit/3171b0e518aebcaa31bbe5c6e914d65282873cda), [`522e306e2`](https://github.com/medusajs/medusa/commit/522e306e2e9abf4afce63f30714389eba32bef7f), [`80b95a230`](https://github.com/medusajs/medusa/commit/80b95a230056d9ed15f7302f248094f879516faf), [`a1e59313c`](https://github.com/medusajs/medusa/commit/a1e59313c964a944a287b54f6654d1d19ac8a59b), [`10bf05c14`](https://github.com/medusajs/medusa/commit/10bf05c147cb65a263465129790edd44a6d8948b), [`cbbf3ca05`](https://github.com/medusajs/medusa/commit/cbbf3ca054387a900c5777c2eb0218df2c72bae6), [`9ba09ba4d`](https://github.com/medusajs/medusa/commit/9ba09ba4d753f132537f0447097fe9f54922c074), [`12d304307`](https://github.com/medusajs/medusa/commit/12d304307af87ea9287a41869eb33ef09f273d85), [`287c829c9`](https://github.com/medusajs/medusa/commit/287c829c9c5a9797fb8cd118b7a6066ad1935898), [`74bc4b16a`](https://github.com/medusajs/medusa/commit/74bc4b16a07f78668003ca930bf2a0d928897ceb), [`aed7805c0`](https://github.com/medusajs/medusa/commit/aed7805c0e64b884007148bde90cfce7bee8aad4), [`0d1b63d77`](https://github.com/medusajs/medusa/commit/0d1b63d773ad91846757a6f0b81b78b0b97b3f2b), [`4042beb10`](https://github.com/medusajs/medusa/commit/4042beb1026b9ad8b381aaa6e1a5214cd92db00f), [`f43e9f0f2`](https://github.com/medusajs/medusa/commit/f43e9f0f20a8b0637252951b2bdfed4d42fb9f5e), [`842423679`](https://github.com/medusajs/medusa/commit/8424236799c3789f884285cd3c8a491e91aef2ca), [`935870e01`](https://github.com/medusajs/medusa/commit/935870e010af1ec884259b1f1328421e99acc3af), [`57d7728dd`](https://github.com/medusajs/medusa/commit/57d7728dd9d00df712e1a872899b8397955dfe46), [`15f47baf5`](https://github.com/medusajs/medusa/commit/15f47baf56e6722b7821cfaa2fb468e582dfa2c1), [`55c5fba0d`](https://github.com/medusajs/medusa/commit/55c5fba0d3dbd015c3ffd74d645a8057892d0f52), [`38503fff5`](https://github.com/medusajs/medusa/commit/38503fff56bbceb092e396ac11432a56967b53e9), [`40de54b01`](https://github.com/medusajs/medusa/commit/40de54b0101bdfd37f577d18c10ec9f1ab1ce8fe), [`54dcc1871`](https://github.com/medusajs/medusa/commit/54dcc1871c8f28bea962dbb9df6e79b038d56449), [`478d1af8d`](https://github.com/medusajs/medusa/commit/478d1af8d0df0af16baf4f130e19b0be34f5f295), [`77d46220c`](https://github.com/medusajs/medusa/commit/77d46220c23bfe19e575cbc445874eb6c22f3c73), [`6748877c6`](https://github.com/medusajs/medusa/commit/6748877c694c1433f666c6987f20af76b201b495), [`7e17e0ddc`](https://github.com/medusajs/medusa/commit/7e17e0ddc2e6b2891e9ee1420b04a541899d2a9d), [`7f2223b65`](https://github.com/medusajs/medusa/commit/7f2223b6507b0a3c452977bfcdee92af2086fa29), [`7d585f5f8`](https://github.com/medusajs/medusa/commit/7d585f5f84a910c02d274df7a489dc3ff1ea273a), [`4e9d257d3`](https://github.com/medusajs/medusa/commit/4e9d257d3bf76703ef5be8ca054cc9f0f7339def), [`ef5ef9f5a`](https://github.com/medusajs/medusa/commit/ef5ef9f5a26febf0b64d9981606c1e59999ca76e), [`46547f29c`](https://github.com/medusajs/medusa/commit/46547f29c755719e22d2977c5e5f8ab8a4a7fcae), [`f97b3d7cc`](https://github.com/medusajs/medusa/commit/f97b3d7ccee381d3491337ab5144bb44520382a7), [`f3bf351d2`](https://github.com/medusajs/medusa/commit/f3bf351d21d1c2a67ed2d603c8b7ed4ae5cbd366), [`d61d6c7b7`](https://github.com/medusajs/medusa/commit/d61d6c7b7f8549996090f5315597d22d2af968f9), [`55a1f232a`](https://github.com/medusajs/medusa/commit/55a1f232a3746a22adb1fcd1844b2659077a59f9), [`53eda215e`](https://github.com/medusajs/medusa/commit/53eda215e00509eb63e571f1b38b9c8884b8e6d5), [`026bdab05`](https://github.com/medusajs/medusa/commit/026bdab05d4da054d3ffd07b8cce8ccb1bded95d), [`aefe5aa13`](https://github.com/medusajs/medusa/commit/aefe5aa133ea3ab98eb3c1ecd0ba51fb76c173de), [`966aea65c`](https://github.com/medusajs/medusa/commit/966aea65c221403bf316ae7665cc8f73bccd9c38), [`48ad2426a`](https://github.com/medusajs/medusa/commit/48ad2426aa7a604c226132e85ef3da5cce045f45)]: - - @medusajs/medusa@1.8.0-rc.0 - -## 1.3.10 - -### Patch Changes - -- [#3271](https://github.com/medusajs/medusa/pull/3271) [`3a911091f`](https://github.com/medusajs/medusa/commit/3a911091f18c03260d92d81498f63bba31ba61ac) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - hotfix(medusa-js): Export all resources and make client of medusa-js public - -- Updated dependencies [[`9690f07bc`](https://github.com/medusajs/medusa/commit/9690f07bc062c85fcf8b7f0f35a162b930944183), [`5301a1e9d`](https://github.com/medusajs/medusa/commit/5301a1e9d632ddac94e7864fecfdc860a4c2a66d), [`d11ab924b`](https://github.com/medusajs/medusa/commit/d11ab924b88211bc18ed019ca300f6d452972167), [`f88af0c28`](https://github.com/medusajs/medusa/commit/f88af0c28d3fa574cdeea3694607d4df563cb88d)]: - - @medusajs/medusa@1.7.8 - -## 1.3.9 - -### Patch Changes - -- [#3217](https://github.com/medusajs/medusa/pull/3217) [`8c5219a31`](https://github.com/medusajs/medusa/commit/8c5219a31ef76ee571fbce84d7d57a63abe56eb0) Thanks [@adrien2p](https://github.com/adrien2p)! - chore: Fix npm packages files included - -- Updated dependencies [[`507ad00be`](https://github.com/medusajs/medusa/commit/507ad00bec74bb63b17eae8a4a3313eb6e0d2503), [`6e443dc70`](https://github.com/medusajs/medusa/commit/6e443dc708ffe20bf96d45ddc207ed274c28e344), [`eee928381`](https://github.com/medusajs/medusa/commit/eee9283818b1717f37f084c319201ea7144fdf8a), [`4cb44a3a2`](https://github.com/medusajs/medusa/commit/4cb44a3a2ec5bcf3d90e3b6a0e1f6bb9ff45e2b6), [`472f96d7f`](https://github.com/medusajs/medusa/commit/472f96d7fb8668a15df6e6f9ea31291891b3e688), [`61b0b2f3a`](https://github.com/medusajs/medusa/commit/61b0b2f3aa1d54d539b216a99032549485136a82), [`80452332d`](https://github.com/medusajs/medusa/commit/80452332d852ad7d33d74e1f08f12f45d7a35503), [`bbbb3d888`](https://github.com/medusajs/medusa/commit/bbbb3d888292391976355c88ecb0fcf8a7c115bc), [`10ff72c30`](https://github.com/medusajs/medusa/commit/10ff72c30ae59d2174d876b0c4141aad135d9a1c), [`968eb8fc6`](https://github.com/medusajs/medusa/commit/968eb8fc6b7ccd7221f88f42d75717f3a0547861), [`a59bd84e4`](https://github.com/medusajs/medusa/commit/a59bd84e41fb5d8fc2edc7bdc43d3cbf74d9d7dc), [`8c5219a31`](https://github.com/medusajs/medusa/commit/8c5219a31ef76ee571fbce84d7d57a63abe56eb0), [`cac13a88d`](https://github.com/medusajs/medusa/commit/cac13a88da42fa986bd7352fbc12a318b566d98f), [`a2cc084db`](https://github.com/medusajs/medusa/commit/a2cc084db817f8f7699e9b0daceda274b5f0e0c0), [`8194d19b0`](https://github.com/medusajs/medusa/commit/8194d19b0e933310fdc65af25300da5dd185e669)]: - - @medusajs/medusa@1.7.7 - -## 1.3.8 - -### Patch Changes - -- [#2971](https://github.com/medusajs/medusa/pull/2971) [`f65f590a2`](https://github.com/medusajs/medusa/commit/f65f590a2771d6e526d7dfc7ca721be74c8f79a9) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Adding inventory items api - -- [#3185](https://github.com/medusajs/medusa/pull/3185) [`08324355a`](https://github.com/medusajs/medusa/commit/08324355a4466b017a0bc7ab1d333ee3cd27b8c4) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Patches all dependencies + minor bumps `winston` to include a [fix for a significant memory leak](https://github.com/winstonjs/winston/pull/2057) - -- [#3157](https://github.com/medusajs/medusa/pull/3157) [`be0d36432`](https://github.com/medusajs/medusa/commit/be0d36432a552b7a559f15916c5d9141980c95d1) Thanks [@riqwan](https://github.com/riqwan)! - feat(medusa-js): added resources for product categories - -- Updated dependencies [[`ce866475b`](https://github.com/medusajs/medusa/commit/ce866475b4b6c8b453638000f7b1df7a27daf45d), [`53532df8d`](https://github.com/medusajs/medusa/commit/53532df8d597ed5471c07296981b6959cba4ddc3), [`d8ffbe25b`](https://github.com/medusajs/medusa/commit/d8ffbe25b047fda0f644240c9f518f95e74f03cb), [`2d525237b`](https://github.com/medusajs/medusa/commit/2d525237b682e89495b6cc8e3aa677bfad4d0726), [`5b63533c7`](https://github.com/medusajs/medusa/commit/5b63533c77528cab31755cedab9e768f7461f373), [`09dc9c667`](https://github.com/medusajs/medusa/commit/09dc9c6677c0d64cf765b27290e707ea75edd4aa), [`4105405f2`](https://github.com/medusajs/medusa/commit/4105405f28c3f3e54a6077c95a575a268fb5569f), [`ee42b60a2`](https://github.com/medusajs/medusa/commit/ee42b60a20db2afc5e9b6b958502f9e86ec37d80), [`d0adaf57e`](https://github.com/medusajs/medusa/commit/d0adaf57ed1018f29bebf01e5cffde5f7192f89f), [`f65f590a2`](https://github.com/medusajs/medusa/commit/f65f590a2771d6e526d7dfc7ca721be74c8f79a9), [`5ec6d438f`](https://github.com/medusajs/medusa/commit/5ec6d438fb1f909be925461c788f3a3a958528e4), [`5c1d2a5e8`](https://github.com/medusajs/medusa/commit/5c1d2a5e83c3654ae468d17c900892c32ef76060), [`8e41c6996`](https://github.com/medusajs/medusa/commit/8e41c6996601142661bde877b9ee1d80b8325f5f), [`d50db84a3`](https://github.com/medusajs/medusa/commit/d50db84a336da2de9c06a59aa79f2a5e9aa558f1), [`82da3605f`](https://github.com/medusajs/medusa/commit/82da3605fb50cef182699900552109ad654f0df2), [`b242e2232`](https://github.com/medusajs/medusa/commit/b242e22326ce74d5437d0da6863f22facbb5964c), [`4339d47e1`](https://github.com/medusajs/medusa/commit/4339d47e1f6c9f6c8f100b3ac72c8a394b6dd44d), [`2e7e16b91`](https://github.com/medusajs/medusa/commit/2e7e16b9173e2779946776b9b07ce7232c683f36), [`9ebb50104`](https://github.com/medusajs/medusa/commit/9ebb50104cc1f6c8ef1cea446ae595fb2eb532a2), [`08324355a`](https://github.com/medusajs/medusa/commit/08324355a4466b017a0bc7ab1d333ee3cd27b8c4), [`e22a383f4`](https://github.com/medusajs/medusa/commit/e22a383f4738e8bc80394ccaba3ac9a4ae678955), [`dc156861d`](https://github.com/medusajs/medusa/commit/dc156861d413ecfe3fd264bcd5ad736d83d8a08e), [`8f4c84121`](https://github.com/medusajs/medusa/commit/8f4c84121bd9b8c7067d72f03125e13afe4d2571), [`bfa33f444`](https://github.com/medusajs/medusa/commit/bfa33f444cd225906149777c5c6e842685f3dd7c), [`f776ed234`](https://github.com/medusajs/medusa/commit/f776ed234fcfccf23041ffebecbae6c9a8b7e922), [`4d6e63d68`](https://github.com/medusajs/medusa/commit/4d6e63d68f4e64c365ecbba133876d95e6528763), [`fcba70570`](https://github.com/medusajs/medusa/commit/fcba705701b8013183fafb39e8dda4a85718080a), [`4f0d8992a`](https://github.com/medusajs/medusa/commit/4f0d8992a091a05e93dd5be3762dfa47f074610e), [`d25a53104`](https://github.com/medusajs/medusa/commit/d25a531045143d3be68d3cd3b5764bbbc792ee3a), [`86c87c7b1`](https://github.com/medusajs/medusa/commit/86c87c7b1020ab6bb02f931e1ee113f2857cf527), [`78650ea66`](https://github.com/medusajs/medusa/commit/78650ea66517b0a77100228615d8122f84ad235b), [`b9bda3bf4`](https://github.com/medusajs/medusa/commit/b9bda3bf4e0f95675041085cea5008268c37edd5), [`e581d3bd9`](https://github.com/medusajs/medusa/commit/e581d3bd90f9bc40105e7eaf34e0c94d4f657f7a), [`4d3210bfb`](https://github.com/medusajs/medusa/commit/4d3210bfbb84877d951f7319d2e87c1acbdd6aad)]: - - @medusajs/medusa@1.7.6 - -## 1.3.7 - -### Patch Changes - -- [#3051](https://github.com/medusajs/medusa/pull/3051) [`150696de9`](https://github.com/medusajs/medusa/commit/150696de99fc852c5d72a746f168b6f62b2086ed) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - feat(medusa, medusa-js, medusa-react): Add endpoint to retrieve Product Tags through the Storefront API - -- [#3038](https://github.com/medusajs/medusa/pull/3038) [`cb2524400`](https://github.com/medusajs/medusa/commit/cb252440079f34ddfdfff1b891f6f73b98db9d59) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - hotfix: Fixes bundling error making JS client unable to run in Node enviornments. Also fixes wrong payload type of admin file uploads. - -- Updated dependencies [[`9dbccd9ca`](https://github.com/medusajs/medusa/commit/9dbccd9ca78b8b66f9a21947bb863622e7ff326b), [`542daeead`](https://github.com/medusajs/medusa/commit/542daeeadd78d939f5144c690e8907374da6d085), [`8c08d0031`](https://github.com/medusajs/medusa/commit/8c08d003198b94c00f8428a51c0e79d2ca9d1dc7), [`017538883`](https://github.com/medusajs/medusa/commit/017538883588792e1ff37abcab0fd2872c9af932), [`b2839e2e4`](https://github.com/medusajs/medusa/commit/b2839e2e4dc0d9344fa2ac8d4d16b796def4c56d), [`76d175231`](https://github.com/medusajs/medusa/commit/76d17523105d3860028a90a45b6038a64040e5ce), [`9e3beaf53`](https://github.com/medusajs/medusa/commit/9e3beaf5319dc785cf84b856cfcc8193df90c3a4), [`7d4b8b9cc`](https://github.com/medusajs/medusa/commit/7d4b8b9cc59672d01cdf0c6f331bc3d1eeec9bee), [`aab163bab`](https://github.com/medusajs/medusa/commit/aab163babb91759a05b852d34c299cdfac96d800), [`a0c4cfe0f`](https://github.com/medusajs/medusa/commit/a0c4cfe0f74cf30c45956c32c2fb22bf833bea68), [`27a29ef24`](https://github.com/medusajs/medusa/commit/27a29ef24e5ea1ba2bc0be8ecb7dd747d4c7c65b), [`aef842123`](https://github.com/medusajs/medusa/commit/aef8421235d8fff68d7d4f8b73f77484073311a5), [`1dc79590b`](https://github.com/medusajs/medusa/commit/1dc79590b3539af09dbc8fbf931d9b5ee225fb0d), [`9c4647383`](https://github.com/medusajs/medusa/commit/9c4647383ebf0a183ccc566636bcf7af06409060), [`a0c4cfe0f`](https://github.com/medusajs/medusa/commit/a0c4cfe0f74cf30c45956c32c2fb22bf833bea68), [`b80124d32`](https://github.com/medusajs/medusa/commit/b80124d32d950790c2a01b49e8c34d562b1d57f4), [`cb1ec0076`](https://github.com/medusajs/medusa/commit/cb1ec0076b4fd932c686d6027e8b060ceded3a64), [`142c8aa70`](https://github.com/medusajs/medusa/commit/142c8aa70f583d9b11a6add2b8f988e9ba4cf979), [`1547dd814`](https://github.com/medusajs/medusa/commit/1547dd8143889fc30045fc3d0241de8e69acb76e), [`d2c692aa9`](https://github.com/medusajs/medusa/commit/d2c692aa96ea89c053f9a694a9ae6dba77e89b14), [`150696de9`](https://github.com/medusajs/medusa/commit/150696de99fc852c5d72a746f168b6f62b2086ed), [`93d0dc1bd`](https://github.com/medusajs/medusa/commit/93d0dc1bdcb54cf6e87428a7bb9b0dac196b4de2), [`b3e4be720`](https://github.com/medusajs/medusa/commit/b3e4be72087d0b528c3cce322edf9325b855c8ae)]: - - @medusajs/medusa@1.7.4 - -## 1.3.6 - -### Patch Changes - -- [#2964](https://github.com/medusajs/medusa/pull/2964) [`f6c81dab9`](https://github.com/medusajs/medusa/commit/f6c81dab9ecc1388b822d914c845f40c33f950ae) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - Changes build process from using `tsc` to `rollup`. This change ensures that the package works with modern build tools such as Vite@4 and esbuild. - -- [#2907](https://github.com/medusajs/medusa/pull/2907) [`c07ffb616`](https://github.com/medusajs/medusa/commit/c07ffb61658b0cdbff00461d1fa267c6be2d1967) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Stock locations module added - -- Updated dependencies [[`1817b810f`](https://github.com/medusajs/medusa/commit/1817b810fc8563a08119b74b86ec0587d9e443a1), [`28bec599a`](https://github.com/medusajs/medusa/commit/28bec599ae34d29b626b1dc36f762fc0b2fe8f17), [`3f44abe01`](https://github.com/medusajs/medusa/commit/3f44abe01a7807adf0e807811d4bc52b713cd6b5), [`8ed4eab73`](https://github.com/medusajs/medusa/commit/8ed4eab73a2b067e19da5a1c8498cbff7125ea8d), [`645e0d0ec`](https://github.com/medusajs/medusa/commit/645e0d0ec5e2e49048887c62db662427c8a39cdf), [`47d075351`](https://github.com/medusajs/medusa/commit/47d075351fa4fdeaf32d48f2bd7e72943a293d9b), [`32b038fc3`](https://github.com/medusajs/medusa/commit/32b038fc3fb5f8fab09a7d23f881847c7ae02c0c), [`3d200c41f`](https://github.com/medusajs/medusa/commit/3d200c41f953c3c979a1586f6425a2fbdf159e7e), [`16716f5a4`](https://github.com/medusajs/medusa/commit/16716f5a4f94cb6bc1dcea278d1789da760f2767), [`71fa60892`](https://github.com/medusajs/medusa/commit/71fa60892cd7c00dd9cb8c222a1794ad6577fc1b), [`cc10c20f3`](https://github.com/medusajs/medusa/commit/cc10c20f356d4fe98336d879f8c9523bb63e9e48), [`eda26f6e8`](https://github.com/medusajs/medusa/commit/eda26f6e818a56672cdcce1d794c307c5490f956), [`077e4d960`](https://github.com/medusajs/medusa/commit/077e4d960687a909fd254cd69f4dd5b3e0bad204), [`f3ced106a`](https://github.com/medusajs/medusa/commit/f3ced106ad24fe21f099e10bee5666e1f65a9fc7), [`baeacd1cc`](https://github.com/medusajs/medusa/commit/baeacd1cc52c548eef6896fd83e606c858cf2165), [`e4af96853`](https://github.com/medusajs/medusa/commit/e4af9685313077ece7e3fb7bd27053108cd9d5f8), [`cac81749e`](https://github.com/medusajs/medusa/commit/cac81749eaa06b3b00ac5494591c96a0fcd7bf57), [`4a50786fb`](https://github.com/medusajs/medusa/commit/4a50786fbc78b36147f1f45d77c55dc0a582caba), [`c07ffb616`](https://github.com/medusajs/medusa/commit/c07ffb61658b0cdbff00461d1fa267c6be2d1967), [`8ba0addea`](https://github.com/medusajs/medusa/commit/8ba0addea3997c27efe4a50733b02a31e02f55e5), [`b9680b641`](https://github.com/medusajs/medusa/commit/b9680b641f2984eddbc1f49a37c050499fbaff69)]: - - @medusajs/medusa@1.7.3 - -## 1.3.5 - -### Patch Changes - -- [#2804](https://github.com/medusajs/medusa/pull/2804) [`7bb9cd6af`](https://github.com/medusajs/medusa/commit/7bb9cd6aff1d832e6e159f2c878be88a054eddaa) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix: missing devDependency was failing repo build task - -- Updated dependencies [[`7cced6006`](https://github.com/medusajs/medusa/commit/7cced6006a9a6f9108009e9f3e191e9f3ba1b168), [`463f83ffd`](https://github.com/medusajs/medusa/commit/463f83ffdd450d5325a57fe742b68bfb32ef1a42), [`17c3f34e3`](https://github.com/medusajs/medusa/commit/17c3f34e3df0a4c3656ad8909608331e207155f1), [`c16522d6c`](https://github.com/medusajs/medusa/commit/c16522d6ce806aa6289d626b868818409f41c66e), [`2e5ceb795`](https://github.com/medusajs/medusa/commit/2e5ceb795008fbf53d19bb79ac561561dd11311e), [`71b536e01`](https://github.com/medusajs/medusa/commit/71b536e01e32e3ab3fb5d295df9d67497a8bbe6d), [`9e05fef4b`](https://github.com/medusajs/medusa/commit/9e05fef4b973ceb60a2b975c839de96ca743597b), [`3113d8024`](https://github.com/medusajs/medusa/commit/3113d8024fdeb09230675c2053fcefe811e575fd), [`e27b1940c`](https://github.com/medusajs/medusa/commit/e27b1940c7249e835404ac5490cf39e93053d2bb), [`5e4decbc1`](https://github.com/medusajs/medusa/commit/5e4decbc1c4cc25cb1adb1f63b2f8ea8669d352e), [`b700c6ba5`](https://github.com/medusajs/medusa/commit/b700c6ba5b323c7c5e200f721f0335f40b3e357a), [`8a60a7338`](https://github.com/medusajs/medusa/commit/8a60a73389c1b5c8abf96fbbcc7be7c4d427041d), [`ba6bb3e54`](https://github.com/medusajs/medusa/commit/ba6bb3e54b9989cecf476c7411c406a43562efe1), [`ea460b4e0`](https://github.com/medusajs/medusa/commit/ea460b4e0b1a9aa0fe1ab66bc21a8c40f76a65b3), [`c8724da50`](https://github.com/medusajs/medusa/commit/c8724da50300b94255c5fb4ffe9904be279b5923), [`8dcc805cc`](https://github.com/medusajs/medusa/commit/8dcc805ccf8da619549e77f009d6c4d7b2b6c99a), [`a027d5ff9`](https://github.com/medusajs/medusa/commit/a027d5ff9eb821a1c8728476e4f8bf5f4dd102c8)]: - - @medusajs/medusa@1.7.1 - -## 1.3.4 - -### Patch Changes - -- Correct missing version bump - -## 1.3.3 - -### Patch Changes - -- [#2552](https://github.com/medusajs/medusa/pull/2552) [`7b0ceeffb`](https://github.com/medusajs/medusa/commit/7b0ceeffb4616c3f4e0cf51aba2ab381c61ea5d7) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(medusa, medusa-js, medusa-react): /store api product types - -- Updated dependencies [[`2d095a0ce`](https://github.com/medusajs/medusa/commit/2d095a0ce14ab7f24b4e6856cb4850cea18af21c), [`8069ed5e9`](https://github.com/medusajs/medusa/commit/8069ed5e99dc53a912df9bb860114d2258044108), [`7b0ceeffb`](https://github.com/medusajs/medusa/commit/7b0ceeffb4616c3f4e0cf51aba2ab381c61ea5d7), [`5ea4b728e`](https://github.com/medusajs/medusa/commit/5ea4b728e728a7e6d4d6fe7255ea80395ab75bd3)]: - - @medusajs/medusa@1.6.2 - -## 1.3.2 - -### Patch Changes - -- [#2433](https://github.com/medusajs/medusa/pull/2433) [`3c5e31c64`](https://github.com/medusajs/medusa/commit/3c5e31c6455695f854e9df7a3592c12b899fa1e1) Thanks [@pKorsholm](https://github.com/pKorsholm)! - Add protected uploads to fileservices - -* [#2430](https://github.com/medusajs/medusa/pull/2430) [`765a2cccd`](https://github.com/medusajs/medusa/commit/765a2cccda2c4c552ede9ec23e0c1e3dd4ea44fc) Thanks [@adrien2p](https://github.com/adrien2p)! - Feat(medusa, medusa-js, medusa-react): add resources to discount condition by batch - -- [#2270](https://github.com/medusajs/medusa/pull/2270) [`69e579758`](https://github.com/medusajs/medusa/commit/69e579758f81332094d6f0dfa6fbcbc359b0d92c) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - Adds the use of price selection strategy to retrieving variants in the admin API. This moves the responsibility of tax calculations from the frontend (admin) to the backend. - -* [#2444](https://github.com/medusajs/medusa/pull/2444) [`48411157b`](https://github.com/medusajs/medusa/commit/48411157b1cdec0a67f91e06de8ac547af89d7af) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(medusa): Support batch remove resources on discount condition - -* Updated dependencies [[`211720f24`](https://github.com/medusajs/medusa/commit/211720f24cbcb1f01c36aa35660e1ff0c4518ebd), [`c71744245`](https://github.com/medusajs/medusa/commit/c717442451cf9fc2e0961edded5b49ea5a78760e), [`3c5e31c64`](https://github.com/medusajs/medusa/commit/3c5e31c6455695f854e9df7a3592c12b899fa1e1), [`13611e3e5`](https://github.com/medusajs/medusa/commit/13611e3e53d449fbfab7a88f848f6652a360bd14), [`765a2cccd`](https://github.com/medusajs/medusa/commit/765a2cccda2c4c552ede9ec23e0c1e3dd4ea44fc), [`69e579758`](https://github.com/medusajs/medusa/commit/69e579758f81332094d6f0dfa6fbcbc359b0d92c), [`05f921711`](https://github.com/medusajs/medusa/commit/05f921711fb0ac3603d29955648d8ba563a7da7d), [`19ca18e71`](https://github.com/medusajs/medusa/commit/19ca18e71c8feea7277e09db3c5e9e6316adb6ab), [`a9c703d56`](https://github.com/medusajs/medusa/commit/a9c703d56c2678fb509af7f9e1fe2cb65f95ba9d), [`58c7ffdc6`](https://github.com/medusajs/medusa/commit/58c7ffdc6ec1d06f76aaa9427505dc452398770f), [`9deec0fc3`](https://github.com/medusajs/medusa/commit/9deec0fc3c3ff9d89ca194b8b05948141799a412), [`299c4ae7f`](https://github.com/medusajs/medusa/commit/299c4ae7f55b0586f283d7f21792b7b204df421a), [`48411157b`](https://github.com/medusajs/medusa/commit/48411157b1cdec0a67f91e06de8ac547af89d7af), [`144ce0e42`](https://github.com/medusajs/medusa/commit/144ce0e42cd894a2cd5b40b68c095fd1eda851a9), [`8be67c734`](https://github.com/medusajs/medusa/commit/8be67c734c970ef03bf0afaf74cc3818e305466d)]: - - @medusajs/medusa@1.6.0 - -## 1.3.1 - -### Patch Changes - -- [#2207](https://github.com/medusajs/medusa/pull/2207) [`6132711ee`](https://github.com/medusajs/medusa/commit/6132711eef797219f1b93e4bc4bdb1dd47655308) Thanks [@sabakhilji](https://github.com/sabakhilji)! - Use correct payload type for resetting password in `medusa-js` - -* [#2353](https://github.com/medusajs/medusa/pull/2353) [`642902aae`](https://github.com/medusajs/medusa/commit/642902aaeb25144e59177c178f09fb8398951357) Thanks [@pKorsholm](https://github.com/pKorsholm)! - feat(medusa-js, medusa-react): add expand fields to get order - -* Updated dependencies [[`d2b272fab`](https://github.com/medusajs/medusa/commit/d2b272fab649bb272b8af4f2f00aafe89965995e), [`7dc8d3a0c`](https://github.com/medusajs/medusa/commit/7dc8d3a0c90ce06e3f11a6a46dec1f9ec3f26e81), [`3d255302b`](https://github.com/medusajs/medusa/commit/3d255302b022a06b492807774412b1db05fa8d06), [`678a06752`](https://github.com/medusajs/medusa/commit/678a06752a03f71d77265a874fd7d07361337862), [`d8a5942d3`](https://github.com/medusajs/medusa/commit/d8a5942d3d85671e2923668bdbf2867957f5554b), [`edd35631f`](https://github.com/medusajs/medusa/commit/edd35631f722009bdcb2439ff8c2326025425d33), [`df62e618b`](https://github.com/medusajs/medusa/commit/df62e618bcc365ef376b96705d63b465b48b0191), [`3f7317028`](https://github.com/medusajs/medusa/commit/3f7317028808cd3c1b44cb7b66694501a7c706c4)]: - - @medusajs/medusa@1.5.0 - -## 1.3.0 - -### Minor Changes - -- [#2185](https://github.com/medusajs/medusa/pull/2185) [`64949dc72`](https://github.com/medusajs/medusa/commit/64949dc721a6c697e3eb7091db9f2d261111a766) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - Adds missing response types for currency endpoints and exports route. Adds currency endpoints to medusa-js and medusa-react. - -### Patch Changes - -- Updated dependencies [[`64949dc72`](https://github.com/medusajs/medusa/commit/64949dc721a6c697e3eb7091db9f2d261111a766), [`b6161d240`](https://github.com/medusajs/medusa/commit/b6161d24043b8b910320475b8616b7e29a96f6cd), [`af80e0fd2`](https://github.com/medusajs/medusa/commit/af80e0fd2ed75cd3c15282ddcbfb949060dfdd33)]: - - @medusajs/medusa@1.4.0 - -## 1.2.6 - -### Patch Changes - -- [#1234](https://github.com/medusajs/medusa/pull/1234) [`8cbebef40`](https://github.com/medusajs/medusa/commit/8cbebef403a5ac5def1f95b2e591991cfa90b7fb) Thanks [@WalkingPizza](https://github.com/WalkingPizza)! - Add deleteSession endpoint - -* [#1958](https://github.com/medusajs/medusa/pull/1958) [`a88bf3c76`](https://github.com/medusajs/medusa/commit/a88bf3c76ea801d2b17227fb2eb8b8d8dbfe1262) Thanks [@richardwardza](https://github.com/richardwardza)! - Add batch endpoints (remove, add) for Collections to medusa-js - -* Updated dependencies [[`15a5b029a`](https://github.com/medusajs/medusa/commit/15a5b029ae3bd954481c558beeac87ace7ab945d), [`900260c5b`](https://github.com/medusajs/medusa/commit/900260c5b9df4f4f927db5bb6921e5e139ff269a), [`42ed20951`](https://github.com/medusajs/medusa/commit/42ed209518bf0278d1bef3c4c47d0ee21cae84c8), [`a54dc68db`](https://github.com/medusajs/medusa/commit/a54dc68db7a7d476cf4bf8d36c122c7f34629c90), [`aaebb38ea`](https://github.com/medusajs/medusa/commit/aaebb38eae883a225779b03556900ea813c991d2), [`9e0cb1212`](https://github.com/medusajs/medusa/commit/9e0cb1212023d7035165ddd269edab3efc7ebe29), [`c97ccd3fb`](https://github.com/medusajs/medusa/commit/c97ccd3fb5dbe796b0e4fbf37def5bb6e8201557), [`152934f8b`](https://github.com/medusajs/medusa/commit/152934f8b07cb3095788091df6823f9665fdf43d), [`8c4be3353`](https://github.com/medusajs/medusa/commit/8c4be3353630efd18759eb893666e44b1b49e2b7), [`bda83a84b`](https://github.com/medusajs/medusa/commit/bda83a84bc99a4741da2076f59071c177bc5534f), [`11fab121f`](https://github.com/medusajs/medusa/commit/11fab121f4c4b5ec3b6a3afccd4c44844bc5e3d9), [`40ae53567`](https://github.com/medusajs/medusa/commit/40ae53567a23ebe562e571fa22f1721eed174c82), [`80e02130b`](https://github.com/medusajs/medusa/commit/80e02130b4a444287920989654b607f07dd8d4f8), [`c31290c91`](https://github.com/medusajs/medusa/commit/c31290c911450a06d5e4da3dc5e4e3977071a6ea), [`4b663cca3`](https://github.com/medusajs/medusa/commit/4b663cca3acf43b0e02a1fb94b8d4f14913bfe45)]: - - @medusajs/medusa@1.3.6 - -## 1.2.5 - -### Patch Changes - -- [#1985](https://github.com/medusajs/medusa/pull/1985) [`badda5233`](https://github.com/medusajs/medusa/commit/badda5233cf90bfcf974d60dcfa059f6396b0251) Thanks [@adrien2p](https://github.com/adrien2p)! - Only include payload on POST and DELETE requests - -## 1.2.4 - -### Patch Changes - -- [#1914](https://github.com/medusajs/medusa/pull/1914) [`1dec44287`](https://github.com/medusajs/medusa/commit/1dec44287df5ac69b4c5769b59f9ebef58d3da68) Thanks [@fPolic](https://github.com/fPolic)! - Version bump due to missing changesets in merged PRs - -- Updated dependencies [[`1dec44287`](https://github.com/medusajs/medusa/commit/1dec44287df5ac69b4c5769b59f9ebef58d3da68), [`8c283ac3b`](https://github.com/medusajs/medusa/commit/8c283ac3b03dea09203ac1b4c8d806efbc092290), [`b8ddb31f6`](https://github.com/medusajs/medusa/commit/b8ddb31f6fe296a11d2d988276ba8e991c37fa9b), [`dafbfa779`](https://github.com/medusajs/medusa/commit/dafbfa7799410a95f9a1ca02d1db718d1f8693eb), [`df6637853`](https://github.com/medusajs/medusa/commit/df66378535727152bb329c71c38d614e5b642599), [`716297231`](https://github.com/medusajs/medusa/commit/71629723185739a97fc2cf8eaa9029f7963bb120), [`0e0b13148`](https://github.com/medusajs/medusa/commit/0e0b13148892b073a1b46900c6eb1b0d8e05cc37), [`c148064b4`](https://github.com/medusajs/medusa/commit/c148064b4abdc4447d8216a6de0a6ce84e3a061c)]: - - @medusajs/medusa@1.3.5 - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [1.2.3](https://github.com/medusajs/medusa/compare/@medusajs/medusa-js@1.2.2...@medusajs/medusa-js@1.2.3) (2022-07-05) - -### Bug Fixes - -- **medusa-js:** Fix `stringifyNullProperties` util ([#1766](https://github.com/medusajs/medusa/issues/1766)) ([7bee57f](https://github.com/medusajs/medusa/commit/7bee57f7c55e15b6a6c847dfda433e67f258ef8e)) - -### Features - -- **medusa-js:** Create utils to stringify null values and respect object types ([#1748](https://github.com/medusajs/medusa/issues/1748)) ([fc1cbe7](https://github.com/medusajs/medusa/commit/fc1cbe72c7b0cd2879a8b112a6f63fa94c728a19)) -- **medusa,medusa-js,medusa-react:** Add BatchJob API support in `medusa-js` + `medusa-react` ([#1704](https://github.com/medusajs/medusa/issues/1704)) ([7302d76](https://github.com/medusajs/medusa/commit/7302d76e12683c989f340d2fcfaf4338dca6554a)) - -## [1.2.2](https://github.com/medusajs/medusa/compare/@medusajs/medusa-js@1.2.0...@medusajs/medusa-js@1.2.2) (2022-06-19) - -### Bug Fixes - -- **medusa-js:** Updated URLs for JS Client ([#1435](https://github.com/medusajs/medusa/issues/1435)) ([98f5c4e](https://github.com/medusajs/medusa/commit/98f5c4ec8bc9809de44223e90a36dfdfd6835503)) - -### Features - -- **medusa:** Add endpoint for retrieving a DiscountCondition ([#1525](https://github.com/medusajs/medusa/issues/1525)) ([a87e1cd](https://github.com/medusajs/medusa/commit/a87e1cdf6558fd56bd91540853ca0bb715eda46e)) -- **medusa:** Add endpoints specific to DiscountConditions ([#1355](https://github.com/medusajs/medusa/issues/1355)) ([9ca45ea](https://github.com/medusajs/medusa/commit/9ca45ea492e755a88737322f900d60abdfa64024)) -- **medusa:** Support deleting prices from a price list by product or variant ([#1555](https://github.com/medusajs/medusa/issues/1555)) ([fa031fd](https://github.com/medusajs/medusa/commit/fa031fd28be8b12ff38eaec6e56c373324e0beed)) - -## [1.2.1](https://github.com/medusajs/medusa/compare/@medusajs/medusa-js@1.2.0...@medusajs/medusa-js@1.2.1) (2022-05-31) - -### Bug Fixes - -- **medusa-js:** Updated URLs for JS Client ([#1435](https://github.com/medusajs/medusa/issues/1435)) ([98f5c4e](https://github.com/medusajs/medusa/commit/98f5c4ec8bc9809de44223e90a36dfdfd6835503)) - -### Features - -- **medusa:** Add endpoint for retrieving a DiscountCondition ([#1525](https://github.com/medusajs/medusa/issues/1525)) ([a87e1cd](https://github.com/medusajs/medusa/commit/a87e1cdf6558fd56bd91540853ca0bb715eda46e)) -- **medusa:** Add endpoints specific to DiscountConditions ([#1355](https://github.com/medusajs/medusa/issues/1355)) ([9ca45ea](https://github.com/medusajs/medusa/commit/9ca45ea492e755a88737322f900d60abdfa64024)) -- **medusa:** Support deleting prices from a price list by product or variant ([#1555](https://github.com/medusajs/medusa/issues/1555)) ([fa031fd](https://github.com/medusajs/medusa/commit/fa031fd28be8b12ff38eaec6e56c373324e0beed)) - -# [1.2.0](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.1.1...@medusajs/medusa-js@1.2.0) (2022-05-01) - -### Bug Fixes - -- **medusa:** Remove unsupported Discount endpoints ([#1367](https://github.com/medusajs/medusa-js/issues/1367)) ([9acee27](https://github.com/medusajs/medusa-js/commit/9acee2799ead683575edd0f7172f336878569dfe)) -- `CustomerGroups` missing features in the clients ([#1159](https://github.com/medusajs/medusa-js/issues/1159)) ([218b20b](https://github.com/medusajs/medusa-js/commit/218b20b26db46f0a91736ece2530a83fa94aed97)) -- default `POST` request payloads to an empty object ([#1141](https://github.com/medusajs/medusa-js/issues/1141)) ([4e7435e](https://github.com/medusajs/medusa-js/commit/4e7435e4d706e9237e08e1bef1818c4d564a5f9c)) -- merge conflicts ([562a1b4](https://github.com/medusajs/medusa-js/commit/562a1b427a6aeb634fbc8b1a6d023c451ca2cd62)) -- use /admin/returns/:id/receive for swap returns ([#1041](https://github.com/medusajs/medusa-js/issues/1041)) ([7ae754b](https://github.com/medusajs/medusa-js/commit/7ae754bb6187db17c45b2cfadc625df8f997f5ab)) - -### Features - -- customer group customers client endpoints ([#1221](https://github.com/medusajs/medusa-js/issues/1221)) ([b7f6996](https://github.com/medusajs/medusa-js/commit/b7f699654bd8c5b08919667d4e29c835901e1af9)) -- customer groups client endpoints ([#1147](https://github.com/medusajs/medusa-js/issues/1147)) ([93426bf](https://github.com/medusajs/medusa-js/commit/93426bfc0263b3a19e6d47e19cc498fea441fb30)) -- customer groups react hooks ([#1153](https://github.com/medusajs/medusa-js/issues/1153)) ([daf49bc](https://github.com/medusajs/medusa-js/commit/daf49bcaf31e6e86cfd13a24efd5b3de626617a4)) -- new tax api ([#979](https://github.com/medusajs/medusa-js/issues/979)) ([c56660f](https://github.com/medusajs/medusa-js/commit/c56660fca9921a3f3637bc137d9794781c5b090f)), closes [#885](https://github.com/medusajs/medusa-js/issues/885) [#896](https://github.com/medusajs/medusa-js/issues/896) [#911](https://github.com/medusajs/medusa-js/issues/911) [#945](https://github.com/medusajs/medusa-js/issues/945) [#950](https://github.com/medusajs/medusa-js/issues/950) [#951](https://github.com/medusajs/medusa-js/issues/951) [#954](https://github.com/medusajs/medusa-js/issues/954) [#969](https://github.com/medusajs/medusa-js/issues/969) [#998](https://github.com/medusajs/medusa-js/issues/998) [#1017](https://github.com/medusajs/medusa-js/issues/1017) [#1110](https://github.com/medusajs/medusa-js/issues/1110) - -## [1.1.1](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.12...@medusajs/medusa-js@1.1.1) (2022-02-28) - -### Bug Fixes - -- use /admin/returns/:id/receive for swap returns ([#1041](https://github.com/medusajs/medusa-js/issues/1041)) ([7a3a183](https://github.com/medusajs/medusa-js/commit/7a3a1837a1db067c3629f1dfd7c6a95a56d649ca)) - -### Features - -- new tax api ([#979](https://github.com/medusajs/medusa-js/issues/979)) ([47588e7](https://github.com/medusajs/medusa-js/commit/47588e7a8d3b2ae2fed0c1e87fdf1ee2db6bcdc2)), closes [#885](https://github.com/medusajs/medusa-js/issues/885) [#896](https://github.com/medusajs/medusa-js/issues/896) [#911](https://github.com/medusajs/medusa-js/issues/911) [#945](https://github.com/medusajs/medusa-js/issues/945) [#950](https://github.com/medusajs/medusa-js/issues/950) [#951](https://github.com/medusajs/medusa-js/issues/951) [#954](https://github.com/medusajs/medusa-js/issues/954) [#969](https://github.com/medusajs/medusa-js/issues/969) [#998](https://github.com/medusajs/medusa-js/issues/998) [#1017](https://github.com/medusajs/medusa-js/issues/1017) [#1110](https://github.com/medusajs/medusa-js/issues/1110) - -# [1.1.0](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.12...@medusajs/medusa-js@1.1.0) (2022-02-25) - -### Bug Fixes - -- use /admin/returns/:id/receive for swap returns ([#1041](https://github.com/medusajs/medusa-js/issues/1041)) ([7ae754b](https://github.com/medusajs/medusa-js/commit/7ae754bb6187db17c45b2cfadc625df8f997f5ab)) - -### Features - -- new tax api ([#979](https://github.com/medusajs/medusa-js/issues/979)) ([c56660f](https://github.com/medusajs/medusa-js/commit/c56660fca9921a3f3637bc137d9794781c5b090f)), closes [#885](https://github.com/medusajs/medusa-js/issues/885) [#896](https://github.com/medusajs/medusa-js/issues/896) [#911](https://github.com/medusajs/medusa-js/issues/911) [#945](https://github.com/medusajs/medusa-js/issues/945) [#950](https://github.com/medusajs/medusa-js/issues/950) [#951](https://github.com/medusajs/medusa-js/issues/951) [#954](https://github.com/medusajs/medusa-js/issues/954) [#969](https://github.com/medusajs/medusa-js/issues/969) [#998](https://github.com/medusajs/medusa-js/issues/998) [#1017](https://github.com/medusajs/medusa-js/issues/1017) [#1110](https://github.com/medusajs/medusa-js/issues/1110) - -## [1.0.12](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.11...@medusajs/medusa-js@1.0.12) (2022-02-06) - -### Bug Fixes - -- release ([fc3fbc8](https://github.com/medusajs/medusa-js/commit/fc3fbc897fad5c8a5d3eea828ac7277fba9d70af)) - -## [1.0.11](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.10...@medusajs/medusa-js@1.0.11) (2022-02-06) - -### Bug Fixes - -- adds order by functionality to products ([#1021](https://github.com/medusajs/medusa-js/issues/1021)) ([3bf32e5](https://github.com/medusajs/medusa-js/commit/3bf32e5dc9ad3150762b9bb744b0453d3640e204)) - -### Features - -- medusa-react admin hooks ([#978](https://github.com/medusajs/medusa-js/issues/978)) ([2e38484](https://github.com/medusajs/medusa-js/commit/2e384842d5b2e9742a86b96f28a8f00357795b86)), closes [#1019](https://github.com/medusajs/medusa-js/issues/1019) - -## [1.0.10](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.9...@medusajs/medusa-js@1.0.10) (2022-01-11) - -### Bug Fixes - -- client admin endpoints ([#956](https://github.com/medusajs/medusa-js/issues/956)) ([2efab08](https://github.com/medusajs/medusa-js/commit/2efab08040917a2971852d741b82f86134dda075)) -- medusa-js admin endpoint types ([#968](https://github.com/medusajs/medusa-js/issues/968)) ([7cc3640](https://github.com/medusajs/medusa-js/commit/7cc36407962f4cc2b3ddc33ace0e2ffb8cc61c1b)) -- Type in AdminProductListTagsRes to use tags instead of types ([#958](https://github.com/medusajs/medusa-js/issues/958)) ([0ac52b7](https://github.com/medusajs/medusa-js/commit/0ac52b70fa23d9aa3ba6b5e220943ed15db4e643)) - -## [1.0.9](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.8...@medusajs/medusa-js@1.0.9) (2021-12-29) - -**Note:** Version bump only for package @medusajs/medusa-js - -## [1.0.8](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.7...@medusajs/medusa-js@1.0.8) (2021-12-17) - -### Features - -- Add Discount Admin endpoint to JS client ([#919](https://github.com/medusajs/medusa-js/issues/919)) ([2ca1a87](https://github.com/medusajs/medusa-js/commit/2ca1a8762da5bc30a246e2e77521071ed91e6c12)) -- add medusa-react ([#913](https://github.com/medusajs/medusa-js/issues/913)) ([d0d8dd7](https://github.com/medusajs/medusa-js/commit/d0d8dd7bf62eaac71df8714c2dfb4f204d192f51)) -- add returns admin endpoints to medusa-js ([#935](https://github.com/medusajs/medusa-js/issues/935)) ([b9d6f95](https://github.com/medusajs/medusa-js/commit/b9d6f95dbd32c096e59057797fd0cf479ff23c7b)) -- add store admin endpoints to medusa-js ([#938](https://github.com/medusajs/medusa-js/issues/938)) ([31fad74](https://github.com/medusajs/medusa-js/commit/31fad7439cc4b95e269e7b6bc5d813cb2479329c)) -- Adds Auth Admin API to `medusa-js` ([#917](https://github.com/medusajs/medusa-js/issues/917)) ([5c47184](https://github.com/medusajs/medusa-js/commit/5c47184b1035fc36440ff95750a4bb461904246d)) -- Adds Customer Admin routes to JS client ([#918](https://github.com/medusajs/medusa-js/issues/918)) ([25fe224](https://github.com/medusajs/medusa-js/commit/25fe224a10842a7ac93ed496a6724ef113b41916)) -- medusa js admin regions ([#939](https://github.com/medusajs/medusa-js/issues/939)) ([8532c96](https://github.com/medusajs/medusa-js/commit/8532c966b59082ac60d221bc3bb7f92d6f94e5e4)) -- medusa js admin shipping options ([#934](https://github.com/medusajs/medusa-js/issues/934)) ([8b1b551](https://github.com/medusajs/medusa-js/commit/8b1b551260c8f3764135ed65bd099b8e9a0f23da)) -- medusa-js admin return reasons ([#931](https://github.com/medusajs/medusa-js/issues/931)) ([0acc462](https://github.com/medusajs/medusa-js/commit/0acc462e1ebe51368ceedeea85d6f51c6fc3bfc4)) - -## [1.0.7](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.6...@medusajs/medusa-js@1.0.7) (2021-12-08) - -### Bug Fixes - -- complete cart return type ([#902](https://github.com/medusajs/medusa-js/issues/902)) ([2e837fc](https://github.com/medusajs/medusa-js/commit/2e837fcdeeb1f9608c5b0c612c75c87c042d8286)) - -## [1.0.6](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.5...@medusajs/medusa-js@1.0.6) (2021-12-08) - -### Bug Fixes - -- medusa-js complete cart types + oas comments ([#889](https://github.com/medusajs/medusa-js/issues/889)) ([487356a](https://github.com/medusajs/medusa-js/commit/487356a96ffc3886cf233e89e0b17dc3b6a665e5)) -- medusa-js fine-tuning ([#836](https://github.com/medusajs/medusa-js/issues/836)) ([ded496c](https://github.com/medusajs/medusa-js/commit/ded496cee5c8fb9b28b664e308dfb782e441c99b)) -- update payment session route ([#887](https://github.com/medusajs/medusa-js/issues/887)) ([e006402](https://github.com/medusajs/medusa-js/commit/e0064026eddc44c437aa09fc06d38b0005ab80c8)) - -## [1.0.5](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.4...@medusajs/medusa-js@1.0.5) (2021-11-23) - -**Note:** Version bump only for package @medusajs/medusa-js - -## [1.0.4](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.3...@medusajs/medusa-js@1.0.4) (2021-11-22) - -**Note:** Version bump only for package @medusajs/medusa-js - -## [1.0.3](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.2...@medusajs/medusa-js@1.0.3) (2021-11-19) - -### Bug Fixes - -- release ([5fa4848](https://github.com/medusajs/medusa-js/commit/5fa4848b17a9dd432c2361e5d9485950494a2bc6)) - -## [1.0.2](https://github.com/medusajs/medusa-js/compare/@medusajs/medusa-js@1.0.1...@medusajs/medusa-js@1.0.2) (2021-11-19) - -**Note:** Version bump only for package @medusajs/medusa-js - -## 1.0.1 (2021-11-19) - -### Features - -- Typescript for API layer ([#817](https://github.com/medusajs/medusa-js/issues/817)) ([373532e](https://github.com/medusajs/medusa-js/commit/373532ecbc8196f47e71af95a8cf82a14a4b1f9e)) diff --git a/packages/medusa-js/README.md b/packages/medusa-js/README.md deleted file mode 100644 index 644b61d734..0000000000 --- a/packages/medusa-js/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Medusa JS Client - -[![Version](https://img.shields.io/npm/v/stripe.svg)](https://www.npmjs.org/package/@medusajs/medusa-js) - -The Medusa JS Client provides easy access to the Medusa API from a client written in Typescript. - -## Documentation - -You can learn more about how to install and use this client in [our documentation](https://docs.medusajs.com/js-client/overview). - -To learn more about the API endpoints that this client allows you to access check out our [API reference](https://docs.medusajs.com/api/store). diff --git a/packages/medusa-js/jest.config.js b/packages/medusa-js/jest.config.js deleted file mode 100644 index e7f58a3a42..0000000000 --- a/packages/medusa-js/jest.config.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - globals: { - "ts-jest": { - tsconfig: "tsconfig.spec.json", - diagnostics: false, - isolatedModules: true, - }, - }, - transform: { - ".(ts|tsx)$": require.resolve("ts-jest/dist/"), - }, - testEnvironment: "jsdom", -} diff --git a/packages/medusa-js/package.json b/packages/medusa-js/package.json deleted file mode 100644 index 73e0433ba1..0000000000 --- a/packages/medusa-js/package.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "name": "@medusajs/medusa-js", - "version": "6.1.8", - "description": "Client for Medusa Commerce Rest API", - "main": "dist/index.js", - "module": "dist/index.mjs", - "types": "dist/index.d.ts", - "files": [ - "dist" - ], - "exports": { - ".": { - "import": "./dist/index.mjs", - "require": "./dist/index.js", - "types": "./dist/index.d.ts" - }, - "./package.json": "./package.json" - }, - "scripts": { - "build": "tsup src/index.ts", - "prepare": "cross-env NODE_ENV=production yarn run build", - "test": "jest --passWithNoTests" - }, - "author": "Oliver Juhl", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "dependencies": { - "axios": "^0.24.0", - "cross-env": "^5.2.1", - "qs": "^6.10.3", - "retry-axios": "^2.6.0", - "uuid": "^9.0.0" - }, - "peerDependencies": { - "@medusajs/medusa": "^1.17.2" - }, - "repository": { - "type": "git", - "url": "https://github.com/medusajs/medusa", - "directory": "packages/medusa-js" - }, - "bugs": { - "url": "https://github.com/medusajs/medusa/issues" - }, - "devDependencies": { - "@medusajs/medusa": "^1.20.3", - "@types/uuid": "^9.0.0", - "jest": "^27.4.7", - "ts-jest": "^27.1.5", - "tsup": "6.7.0", - "typescript": "^4.9.5" - }, - "gitHead": "cd1f5afa5aa8c0b15ea957008ee19f1d695cbd2e", - "homepage": "https://docs.medusajs.com/js-client/overview" -} diff --git a/packages/medusa-js/src/error.ts b/packages/medusa-js/src/error.ts deleted file mode 100644 index 22bac5baef..0000000000 --- a/packages/medusa-js/src/error.ts +++ /dev/null @@ -1,57 +0,0 @@ -"use strict" -/** - * MedusaError is the base error for every other MedusaError - */ -export default class MedusaError extends Error { - constructor() { - super() - } - - public static factory(type: ErrorType): MedusaError { - switch (type) { - case ErrorType.INVALID_REQUEST: - return new MedusaInvalidRequestError() - case ErrorType.AUTHENTICATION: - return new MedusaAuthenticationError() - case ErrorType.API: - return new MedusaAPIError() - case ErrorType.PERMISSION: - return new MedusaPermissionError() - case ErrorType.CONNECTION: - return new MedusaConnectionError() - } - } -} - -enum ErrorType { - "INVALID_REQUEST", - "API", - "AUTHENTICATION", - "PERMISSION", - "CONNECTION", -} - -/** - * MedusaInvalidRequestError is raised when a request as invalid parameters. - */ -export class MedusaInvalidRequestError extends MedusaError {} - -/** - * MedusaAPIError is raised in case no other type cover the problem - */ -export class MedusaAPIError extends MedusaError {} - -/** - * MedusaAuthenticationError is raised when invalid credentials is used to connect to Medusa - */ -export class MedusaAuthenticationError extends MedusaError {} - -/** - * MedusaPermissionError is raised when attempting to access a resource without permissions - */ -export class MedusaPermissionError extends MedusaError {} - -/** - * MedusaConnectionError is raised when the Medusa servers can't be reached. - */ -export class MedusaConnectionError extends MedusaError {} diff --git a/packages/medusa-js/src/index.ts b/packages/medusa-js/src/index.ts deleted file mode 100644 index 208e760c7b..0000000000 --- a/packages/medusa-js/src/index.ts +++ /dev/null @@ -1,91 +0,0 @@ -import MedusaError from "./error" -import KeyManager from "./key-manager" -import Client, { type Config, type RequestOptions } from "./request" -import { - Admin, - AuthResource, - CartsResource, - CollectionsResource, - CustomersResource, - GiftCardsResource, - OrderEditsResource, - OrdersResource, - PaymentCollectionsResource, - PaymentMethodsResource, - ProductCategoriesResource, - ProductsResource, - ProductTagsResource, - ProductTypesResource, - RegionsResource, - ReturnReasonsResource, - ReturnsResource, - ShippingOptionsResource, - SwapsResource, -} from "./resources" - -class Medusa { - public client: Client - public admin: Admin - - public auth: AuthResource - public carts: CartsResource - public customers: CustomersResource - public errors: MedusaError - public orders: OrdersResource - public orderEdits: OrderEditsResource - public products: ProductsResource - public productTypes: ProductTypesResource - public regions: RegionsResource - public returnReasons: ReturnReasonsResource - public returns: ReturnsResource - public shippingOptions: ShippingOptionsResource - public swaps: SwapsResource - public collections: CollectionsResource - public giftCards: GiftCardsResource - public paymentMethods: PaymentMethodsResource - public paymentCollections: PaymentCollectionsResource - public productTags: ProductTagsResource - public productCategories: ProductCategoriesResource - - constructor(config: Config) { - this.client = new Client(config) - - this.admin = new Admin(this.client) - - this.auth = new AuthResource(this.client) - this.carts = new CartsResource(this.client) - this.customers = new CustomersResource(this.client) - this.errors = new MedusaError() - this.orders = new OrdersResource(this.client) - this.orderEdits = new OrderEditsResource(this.client) - this.products = new ProductsResource(this.client) - this.productTypes = new ProductTypesResource(this.client) - this.regions = new RegionsResource(this.client) - this.returnReasons = new ReturnReasonsResource(this.client) - this.returns = new ReturnsResource(this.client) - this.shippingOptions = new ShippingOptionsResource(this.client) - this.swaps = new SwapsResource(this.client) - this.collections = new CollectionsResource(this.client) - this.giftCards = new GiftCardsResource(this.client) - this.paymentMethods = new PaymentMethodsResource(this.client) - this.paymentCollections = new PaymentCollectionsResource(this.client) - this.productTags = new ProductTagsResource(this.client) - this.productCategories = new ProductCategoriesResource(this.client) - } - - /** - * Set a PublishableApiKey that will be sent with each request - * to define the scope of available resources. - * - * @param key - PublishableApiKey identifier - */ - setPublishableKey(key: string) { - KeyManager.registerPublishableApiKey(key) - } -} - -export default Medusa -export * from "./resources" -export * from "./typings" -export type { Config, RequestOptions } -export { MedusaError, KeyManager, Client } diff --git a/packages/medusa-js/src/jwt-token-manager.ts b/packages/medusa-js/src/jwt-token-manager.ts deleted file mode 100644 index 83ed0fa943..0000000000 --- a/packages/medusa-js/src/jwt-token-manager.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * `JwtTokenManager` holds JWT tokens in state. - */ -class JwtTokenManager { - private adminJwt: string | null = null; - private storeJwt: string | null = null; - - /** - * Set a store or admin jwt token to be sent with each request. - */ - public registerJwt(token: string, domain: "admin" | "store") { - if (domain === "admin") { - this.adminJwt = token; - } else if (domain === "store") { - this.storeJwt = token; - } else { - throw new Error(`'domain' must be wither 'admin' or 'store' received ${domain}`) - } - } - - /** - * Retrieve the store or admin jwt token - */ - public getJwt(domain: "admin" | "store") { - if (domain === "admin") { - return this.adminJwt; - } else if (domain === "store") { - return this.storeJwt; - } else { - throw new Error(`'domain' must be wither 'admin' or 'store' received ${domain}`) - } - } -} - -/** - * Export singleton instance. - */ -export default new JwtTokenManager() diff --git a/packages/medusa-js/src/key-manager.ts b/packages/medusa-js/src/key-manager.ts deleted file mode 100644 index 412cd72527..0000000000 --- a/packages/medusa-js/src/key-manager.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * `KeyManager` holds API keys in state. - */ -class KeyManager { - private publishableApiKey: string | null = null - - /** - * Set a publishable api key to be sent with each request. - */ - public registerPublishableApiKey(key: string) { - this.publishableApiKey = key - } - - /** - * Retrieve the publishable api key. - */ - public getPublishableApiKey() { - return this.publishableApiKey - } -} - -/** - * Export singleton instance. - */ -export default new KeyManager() diff --git a/packages/medusa-js/src/request.ts b/packages/medusa-js/src/request.ts deleted file mode 100644 index d9f928aef8..0000000000 --- a/packages/medusa-js/src/request.ts +++ /dev/null @@ -1,254 +0,0 @@ -import axios, { - AxiosAdapter, - AxiosError, - AxiosInstance, - AxiosRequestHeaders, -} from "axios" -import * as rax from "retry-axios" -import { v4 as uuidv4 } from "uuid" - -import KeyManager from "./key-manager" -import JwtTokenManager from "./jwt-token-manager" - -const unAuthenticatedAdminEndpoints = { - "/admin/auth": "POST", - "/admin/users/password-token": "POST", - "/admin/users/reset-password": "POST", - "/admin/invites/accept": "POST", -} - -export interface Config { - baseUrl: string - maxRetries: number - apiKey?: string - publishableApiKey?: string - customHeaders?: Record - axiosAdapter?: AxiosAdapter -} - -/** - * @interface - * - * Options to pass to requests sent to custom API Routes - */ -export interface RequestOptions { - /** - * The number of milliseconds before the request times out. - */ - timeout?: number - /** - * The number of times to retry a request before failing. - */ - numberOfRetries?: number -} - -export type RequestMethod = "DELETE" | "POST" | "GET" - -const defaultConfig = { - maxRetries: 0, - baseUrl: "http://localhost:9000", -} - -class Client { - private axiosClient: AxiosInstance - private config: Config - - constructor(config: Config) { - /** @private @constant {AxiosInstance} */ - this.axiosClient = this.createClient({ ...defaultConfig, ...config }) - - /** @private @constant {Config} */ - this.config = { ...defaultConfig, ...config } - } - - shouldRetryCondition( - err: AxiosError, - numRetries: number, - maxRetries: number - ): boolean { - // Obviously, if we have reached max. retries we stop - if (numRetries >= maxRetries) { - return false - } - - // If no response, we assume a connection error and retry - if (!err.response) { - return true - } - - // Retry on conflicts - if (err.response.status === 409) { - return true - } - - // All 5xx errors are retried - // OBS: We are currently not retrying 500 requests, since our core needs proper error handling. - // At the moment, 500 will be returned on all errors, that are not of type MedusaError. - if (err.response.status > 500 && err.response.status <= 599) { - return true - } - - return false - } - - // Stolen from https://github.com/stripe/stripe-node/blob/fd0a597064289b8c82f374f4747d634050739043/lib/utils.js#L282 - normalizeHeaders(obj: object): Record { - if (!(obj && typeof obj === "object")) { - return obj - } - - return Object.keys(obj).reduce((result, header) => { - result[this.normalizeHeader(header)] = obj[header] - return result - }, {}) - } - - // Stolen from https://github.com/marten-de-vries/header-case-normalizer/blob/master/index.js#L36-L41 - normalizeHeader(header: string): string { - return header - .split("-") - .map( - (text) => text.charAt(0).toUpperCase() + text.substr(1).toLowerCase() - ) - .join("-") - } - - requiresAuthentication(path, method): boolean { - return ( - path.startsWith("/admin") && - unAuthenticatedAdminEndpoints[path] !== method - ) - } - - /** - * Creates all the initial headers. - * We add the idempotency key, if the request is configured to retry. - * @param {object} userHeaders user supplied headers - * @param {Types.RequestMethod} method request method - * @param {string} path request path - * @param {object} customHeaders user supplied headers - * @return {object} - */ - setHeaders( - userHeaders: RequestOptions, - method: RequestMethod, - path: string, - customHeaders: Record = {} - ): AxiosRequestHeaders { - let defaultHeaders: Record = { - Accept: "application/json", - "Content-Type": "application/json", - } - - if (this.config.apiKey && this.requiresAuthentication(path, method)) { - defaultHeaders = { - ...defaultHeaders, - "x-medusa-access-token": this.config.apiKey, - } - } - - const domain: "admin" | "store" = path.includes("admin") ? "admin" : "store" - - if (JwtTokenManager.getJwt(domain)) { - defaultHeaders = { - ...defaultHeaders, - Authorization: `Bearer ${JwtTokenManager.getJwt(domain)}`, - } - } - - const publishableApiKey = - this.config.publishableApiKey || KeyManager.getPublishableApiKey() - - if (publishableApiKey) { - defaultHeaders["x-publishable-api-key"] = publishableApiKey - } - - // only add idempotency key, if we want to retry - if (this.config.maxRetries > 0 && method === "POST") { - defaultHeaders["Idempotency-Key"] = uuidv4() - } - - return Object.assign( - {}, - defaultHeaders, - this.normalizeHeaders(userHeaders), - customHeaders - ) - } - - /** - * Creates the axios client used for requests - * As part of the creation, we configure the retry conditions - * and the exponential backoff approach. - * @param {Config} config user supplied configurations - * @return {AxiosInstance} - */ - createClient(config: Config): AxiosInstance { - const client = axios.create({ - baseURL: config.baseUrl, - adapter: config.axiosAdapter, - }) - - rax.attach(client) - - client.defaults.raxConfig = { - instance: client, - retry: config.maxRetries, - backoffType: "exponential", - shouldRetry: (err: AxiosError): boolean => { - const cfg = rax.getConfig(err) - if (cfg) { - return this.shouldRetryCondition( - err, - cfg.currentRetryAttempt ?? 1, - cfg.retry ?? 3 - ) - } else { - return false - } - }, - } - - return client - } - - /** - * Axios request - * @param method request method - * @param path request path - * @param payload request payload - * @param options axios configuration - * @param customHeaders custom request headers - * @return - */ - async request( - method: RequestMethod, - path: string, - payload: Record = {}, - options: RequestOptions = {}, - customHeaders: Record = {} - ): Promise { - - customHeaders = { ...this.config.customHeaders, ...customHeaders } - - const reqOpts = { - method, - withCredentials: true, - url: path, - json: true, - headers: this.setHeaders(options, method, path, customHeaders), - } - - if (["POST", "DELETE"].includes(method)) { - reqOpts["data"] = payload - } - - // e.g. data = { cart: { ... } }, response = { status, headers, ... } - const { data, ...response } = await this.axiosClient(reqOpts) - - // e.g. would return an object like of this shape { cart, response } - return { ...data, response } - } -} - -export default Client diff --git a/packages/medusa-js/src/resources/addresses.ts b/packages/medusa-js/src/resources/addresses.ts deleted file mode 100644 index 8223871df5..0000000000 --- a/packages/medusa-js/src/resources/addresses.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { - StoreCustomersRes, - StorePostCustomersCustomerAddressesAddressReq, - StorePostCustomersCustomerAddressesReq, -} from "@medusajs/medusa" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" - -/** - * This class is used to send requests to Address API Routes part of the [Store Customer API Routes](https://docs.medusajs.com/api/store#customers_postcustomers). All its method - * are available in the JS Client under the `medusa.customers.addresses` property. - * - * All methods in this class require {@link AuthResource.authenticate | customer authentication}. - */ -class AddressesResource extends BaseResource { - /** - * Add an address to the logged-in customer's saved addresses. - * @param {StorePostCustomersCustomerAddressesReq} payload - The address to add. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer's details, including the customer's addresses in the `shipping_addresses` attribute. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.addresses.addAddress({ - * address: { - * first_name: "Celia", - * last_name: "Schumm", - * address_1: "225 Bednar Curve", - * city: "Danielville", - * country_code: "US", - * postal_code: "85137", - * phone: "981-596-6748 x90188", - * company: "Wyman LLC", - * province: "Georgia", - * } - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - */ - addAddress( - payload: StorePostCustomersCustomerAddressesReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/customers/me/addresses` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete an address of the logged-in customer. - * @param {string} address_id - The ID of the address to delete. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer's details, including the customer's addresses in the `shipping_addresses` attribute. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.addresses.deleteAddress(addressId) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - */ - deleteAddress( - address_id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/customers/me/addresses/${address_id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Update an address of the logged-in customer. - * @param {string} address_id - The address's ID. - * @param {StorePostCustomersCustomerAddressesAddressReq} payload - The attributes to update in the address. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer's details, including the customer's addresses in the `shipping_addresses` attribute. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.addresses.updateAddress(addressId, { - * first_name: "Gina" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - */ - updateAddress( - address_id: string, - payload: StorePostCustomersCustomerAddressesAddressReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/customers/me/addresses/${address_id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } -} - -export default AddressesResource diff --git a/packages/medusa-js/src/resources/admin/auth.ts b/packages/medusa-js/src/resources/admin/auth.ts deleted file mode 100644 index 1039b65636..0000000000 --- a/packages/medusa-js/src/resources/admin/auth.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { AdminAuthRes, AdminPostAuthReq, AdminBearerAuthRes } from "@medusajs/medusa" -import { ResponsePromise } from "../../typings" -import JwtTokenManager from "../../jwt-token-manager" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Auth API Routes](https://docs.medusajs.com/api/admin#auth_getauth). All its method - * are available in the JS Client under the `medusa.admin.auth` property. - * - * The methods in this class allow admin users to manage their session, such as login or log out. - * You can send authenticated requests for an admin user either using the Cookie header, their API token, or the JWT Token. - * When you log the admin user in using the {@link createSession} method, the JS client will automatically attach the - * cookie header in all subsequent requests. - * - * Related Guide: [How to implement user profiles](https://docs.medusajs.com/modules/users/admin/manage-profile). - */ -class AdminAuthResource extends BaseResource { - /** - * Get the currently logged in user's details. Can also be used to check if there is an authenticated user. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the logged-in user's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.auth.getSession() - * .then(({ user }) => { - * console.log(user.id); - * }) - */ - getSession( - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/auth` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Log out the user and remove their authentication session. This will only work if you're using Cookie session for authentication. If the API token is still passed in the header, - * the user is still authorized to perform admin functionalities in other API Routes. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves when user is logged out successfully. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in - * medusa.admin.auth.deleteSession() - */ - deleteSession( - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/auth` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Log a User in using their credentials. If the user is authenticated successfully, the cookie is automatically attached to subsequent requests sent with the JS Client. - * @param {AdminPostAuthReq} payload - The credentials of the user. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the user's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.admin.AdminAuthResource.createSession({ - * email: "user@example.com", - * password: "supersecret" - * }) - * .then(({ user }) => { - * console.log(user.id); - * }) - */ - createSession( - payload: AdminPostAuthReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/auth` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Authenticate the user and retrieve a JWT token to use for subsequent authenticated requests. - * @param {AdminPostAuthReq} payload - The credentials of the user. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the access token of the user, if they're authenticated successfully. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.admin.auth.getToken({ - * email: 'user@example.com', - * password: 'supersecret' - * }) - * .then(({ access_token }) => { - * console.log(access_token); - * }) - */ - getToken( - payload: AdminPostAuthReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/auth/token` - return this.client.request("POST", path, payload, {}, customHeaders) - .then((res) => { - JwtTokenManager.registerJwt(res.access_token, "admin"); - - return res - }); - } -} - -export default AdminAuthResource diff --git a/packages/medusa-js/src/resources/admin/batch-jobs.ts b/packages/medusa-js/src/resources/admin/batch-jobs.ts deleted file mode 100644 index 80fb2f04f9..0000000000 --- a/packages/medusa-js/src/resources/admin/batch-jobs.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { - AdminBatchJobListRes, - AdminBatchJobRes, - AdminGetBatchParams, - AdminPostBatchesReq, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" -import { stringifyNullProperties } from "../../utils" - -/** - * This class is used to send requests to [Admin Batch Job API Routes](https://docs.medusajs.com/api/admin#batch-jobs). All its method - * are available in the JS Client under the `medusa.admin.batchJobs` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A batch job is a task that is performed by the Medusa backend asynchronusly. For example, the Import Product feature is implemented using batch jobs. - * The methods in this class allow admins to manage the batch jobs and their state. - * - * Related Guide: [How to import products](https://docs.medusajs.com/modules/products/admin/import-products). - */ -class AdminBatchJobsResource extends BaseResource { - - /** - * Create a Batch Job to be executed asynchronously in the Medusa backend. If `dry_run` is set to `true`, the batch job will not be executed until the it is confirmed, - * which can be done using the {@link confirm} method. - * @param payload - The data of the batch job to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the batch job's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.batchJobs.create({ - * type: 'product-export', - * context: {}, - * dry_run: false - * }).then((({ batch_job }) => { - * console.log(batch_job.id); - * }) - */ - create( - payload: AdminPostBatchesReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/batch-jobs` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve a list of Batch Jobs. The batch jobs can be filtered by fields such as `type` or `confirmed_at`. The batch jobs can also be sorted or paginated. - * @param {AdminGetBatchParams} query - Filters and pagination configurations to apply on the retrieved batch jobs. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} The list of batch jobs with pagination fields. - * - * @example - * To list batch jobs: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.batchJobs.list() - * .then(({ batch_jobs, limit, offset, count }) => { - * console.log(batch_jobs.length) - * }) - * ``` - * - * To specify relations that should be retrieved within the batch jobs: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.batchJobs.list({ - * expand: "created_by_user" - * }) - * .then(({ batch_jobs, limit, offset, count }) => { - * console.log(batch_jobs.length) - * }) - * ``` - * - * By default, only the first `10` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.batchJobs.list({ - * expand: "created_by_user", - * limit, - * offset - * }) - * .then(({ batch_jobs, limit, offset, count }) => { - * console.log(batch_jobs.length) - * }) - * ``` - */ - list( - query?: AdminGetBatchParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/batch-jobs` - - if (query) { - const queryString = qs.stringify(stringifyNullProperties(query)) - path = `/admin/batch-jobs?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Mark a batch job as canceled. When a batch job is canceled, the processing of the batch job doesn’t automatically stop. - * @param {string} batchJobId - The ID of the batch job. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the batch job's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.batchJobs.cancel(batchJobId) - * .then(({ batch_job }) => { - * console.log(batch_job.id); - * }) - */ - cancel( - batchJobId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/batch-jobs/${batchJobId}/cancel` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * When a batch job is created, it's not executed automatically if `dry_run` is set to `true`. This method confirms that the batch job should be executed. - * @param {string} batchJobId - The ID of the batch job. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the batch job's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.batchJobs.confirm(batchJobId) - * .then(({ batch_job }) => { - * console.log(batch_job.id); - * }) - */ - confirm( - batchJobId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/batch-jobs/${batchJobId}/confirm` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Retrieve the details of a batch job. - * @param {string} batchJobId - The ID of the batch job. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the batch job's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.batchJobs.retrieve(batchJobId) - * .then(({ batch_job }) => { - * console.log(batch_job.id); - * }) - */ - retrieve( - batchJobId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/batch-jobs/${batchJobId}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminBatchJobsResource diff --git a/packages/medusa-js/src/resources/admin/collections.ts b/packages/medusa-js/src/resources/admin/collections.ts deleted file mode 100644 index 4e8828f395..0000000000 --- a/packages/medusa-js/src/resources/admin/collections.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { - AdminCollectionsDeleteRes, - AdminCollectionsListRes, - AdminCollectionsRes, - AdminDeleteProductsFromCollectionReq, - AdminDeleteProductsFromCollectionRes, - AdminGetCollectionsParams, - AdminPostCollectionsCollectionReq, - AdminPostCollectionsReq, - AdminPostProductsToCollectionReq, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Product Collection API Routes](https://docs.medusajs.com/api/admin#product-collections). All its method - * are available in the JS Client under the `medusa.admin.collections` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A product collection is used to organize products for different purposes such as marketing or discount purposes. For example, you can create a Summer Collection. - */ -class AdminCollectionsResource extends BaseResource { - /** - * Create a product collection. - * @param {AdminPostCollectionsReq} payload - The data of the product collection to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the created product collection's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.create({ - * title: "New Collection" - * }) - * .then(({ collection }) => { - * console.log(collection.id); - * }) - */ - create( - payload: AdminPostCollectionsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/collections` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a product collection's details. - * @param {string} id - The ID of the product collection. - * @param {AdminPostCollectionsCollectionReq} payload - The data to update in the product collection. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product collection's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.update(collectionId, { - * title: "New Collection" - * }) - * .then(({ collection }) => { - * console.log(collection.id); - * }) - */ - update( - id: string, - payload: AdminPostCollectionsCollectionReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/collections/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a product collection. This does not delete associated products. - * @param {string} id - The ID of the product collection. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.delete(collectionId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/collections/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a product collection by its ID. The products associated with it are expanded and returned as well. - * @param {string} id - The ID of the product collection. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product collection's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.retrieve(collectionId) - * .then(({ collection }) => { - * console.log(collection.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/collections/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of product collections. The product collections can be filtered by fields such as `handle` or `title`. The collections can also be sorted or paginated. - * @param {AdminGetCollectionsParams} query - Filters and pagination configurations to apply on the retrieved product collections. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of product collections with pagination fields. - * - * @example - * To list product collections: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.list() - * .then(({ collections, limit, offset, count }) => { - * console.log(collections.length); - * }) - * ``` - * - * By default, only the first `10` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.list({ - * limit, - * offset - * }) - * .then(({ collections, limit, offset, count }) => { - * console.log(collections.length); - * }) - * ``` - */ - list( - query?: AdminGetCollectionsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/collections` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/collections?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Add products to collection. - * @param {string} id - The ID of the product collection. - * @param {AdminPostProductsToCollectionReq} payload - The products to add. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product collection's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.addProducts(collectionId, { - * product_ids: [ - * productId1, - * productId2 - * ] - * }) - * .then(({ collection }) => { - * console.log(collection.products) - * }) - */ - addProducts( - id: string, - payload: AdminPostProductsToCollectionReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/collections/${id}/products/batch` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Remove a list of products from a collection. This would not delete the product, only the association between the product and the collection. - * @param {string} id - the ID of the product collection - * @param {AdminDeleteProductsFromCollectionReq} payload - The products to remove from the collection. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.removeProducts(collectionId, { - * product_ids: [ - * productId1, - * productId2 - * ] - * }) - * .then(({ id, object, removed_products }) => { - * console.log(removed_products) - * }) - */ - removeProducts( - id: string, - payload: AdminDeleteProductsFromCollectionReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/collections/${id}/products/batch` - return this.client.request("DELETE", path, payload, {}, customHeaders) - } -} - -export default AdminCollectionsResource diff --git a/packages/medusa-js/src/resources/admin/currencies.ts b/packages/medusa-js/src/resources/admin/currencies.ts deleted file mode 100644 index b0ddefebd3..0000000000 --- a/packages/medusa-js/src/resources/admin/currencies.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { - AdminCurrenciesListRes, - AdminCurrenciesRes, - AdminGetCurrenciesParams, - AdminPostCurrenciesCurrencyReq, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Currency API Routes](https://docs.medusajs.com/api/admin#currencies). All its method - * are available in the JS Client under the `medusa.admin.currencies` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A store can use unlimited currencies, and each region must be associated with at least one currency. - * Currencies are defined within the Medusa backend. The methods in this class allow admins to list and update currencies. - * - * Related Guide: [How to manage currencies](https://docs.medusajs.com/modules/regions-and-currencies/admin/manage-currencies). - */ -class AdminCurrenciesResource extends BaseResource { - /** - * Retrieve a list of currencies. The currencies can be filtered by fields such as `code`. The currencies can also be sorted or paginated. - * @param {AdminGetCurrenciesParams} query - Filters and pagination configurations to apply on retrieved currencies. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of currencies with pagination fields. - * - * @example - * To list currencies: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.currencies.list() - * .then(({ currencies, count, offset, limit }) => { - * console.log(currencies.length); - * }) - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.currencies.list({ - * limit, - * offset - * }) - * .then(({ currencies, count, offset, limit }) => { - * console.log(currencies.length); - * }) - * ``` - */ - list( - query?: AdminGetCurrenciesParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/currencies` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Update a Currency's details. - * @param {string} code - The code of the currency to update. - * @param {AdminPostCurrenciesCurrencyReq} payload - The attributes to update in the currency. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the currency's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.currencies.update(code, { - * includes_tax: true - * }) - * .then(({ currency }) => { - * console.log(currency.code); - * }) - */ - update( - code: string, - payload: AdminPostCurrenciesCurrencyReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/currencies/${code}` - return this.client.request("POST", path, payload, {}, customHeaders) - } -} - -export default AdminCurrenciesResource diff --git a/packages/medusa-js/src/resources/admin/custom.ts b/packages/medusa-js/src/resources/admin/custom.ts deleted file mode 100644 index 1d96ce9a09..0000000000 --- a/packages/medusa-js/src/resources/admin/custom.ts +++ /dev/null @@ -1,138 +0,0 @@ -import qs from "qs" -import { RequestOptions } from "../../request" -import { ResponsePromise } from "../../typings" -import { createAdminPath } from "../../utils" -import BaseResource from "../base" - -/** - * This class is used to send requests custom API Routes. All its method - * are available in the JS Client under the `medusa.admin.custom` property. - */ -class AdminCustomResource extends BaseResource { - /** - * Send a `GET` request to a custom API Route. The method accepts a tuple of type parameters: the first `TQuery` is the type of accepted query parameters, - * which defaults to `Record`; the second `TResponse` is the type of response, which defaults to `any`. - * @param {string} path - The path of the custom API Route. - * @param {TQuery} query - Query path parameters to pass in the request. - * @param {RequestOptions} options - Configurations to apply on the request. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} The response data. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * type PostsResponse = { - * posts: Post[] - * } - * // must be previously logged in or use api token - * medusa.admin.custom.get, PostsResponse>( - * "/blog/posts" - * ) - * .then(({ posts }) => { - * console.log(posts.length); - * }) - */ - get, TResponse = any>( - path: string, - query?: TQuery, - options?: RequestOptions, - customHeaders?: Record - ): ResponsePromise { - let formattedPath = createAdminPath(path) - - if (query) { - const queryString = qs.stringify(query) - formattedPath += `?${queryString}` - } - - return this.client.request( - "GET", - formattedPath, - undefined, - options, - customHeaders - ) - } - - /** - * Send a `POST` request to a custom API Route. The method accepts a tuple of type parameters: the first `TPayload` is the type of accepted body parameters, - * which defaults to `Record`; the second `TResponse` is the type of response, which defaults to `any`. - * @param {string} path - The path of the custom API Route. - * @param {TPayload} payload - Body parameters to pass in the request. - * @param {RequestOptions} options - Configurations to apply on the request. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} The response data. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * type PostRequest = { - * title: string - * } - * type PostResponse = { - * post: Post - * } - * // must be previously logged in or use api token - * medusa.admin.custom.post( - * "/blog/posts", - * { - * title: "My post", - * } - * ) - * .then(({ post }) => { - * console.log(post.id); - * }) - */ - post, TResponse = any>( - path: string, - payload?: TPayload, - options?: RequestOptions, - customHeaders?: Record - ): ResponsePromise { - const formattedPath = createAdminPath(path) - - return this.client.request( - "POST", - formattedPath, - payload, - options, - customHeaders - ) - } - - /** - * Send a `DELETE` request to a custom API Route. The method accepts a type parameters `TResponse` indicating the type of response, which defaults to `any`. - * @param {string} path - The path of the custom API Route. - * @param {RequestOptions} options - Configurations to apply on the request. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} The response data. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.custom.delete( - * `/blog/posts/${postId}` - * ) - * .then(() => { - * // deleted successfully - * }) - */ - delete( - path: string, - options?: RequestOptions, - customHeaders?: Record - ): ResponsePromise { - const formattedPath = createAdminPath(path) - - return this.client.request( - "DELETE", - formattedPath, - undefined, - options, - customHeaders - ) - } -} - -export default AdminCustomResource diff --git a/packages/medusa-js/src/resources/admin/customer-groups.ts b/packages/medusa-js/src/resources/admin/customer-groups.ts deleted file mode 100644 index dface26da2..0000000000 --- a/packages/medusa-js/src/resources/admin/customer-groups.ts +++ /dev/null @@ -1,267 +0,0 @@ -import { - AdminPostCustomerGroupsReq, - AdminCustomerGroupsRes, - AdminGetCustomerGroupsParams, - AdminCustomerGroupsListRes, - AdminPostCustomerGroupsGroupReq, - AdminCustomerGroupsDeleteRes, - AdminPostCustomerGroupsGroupCustomersBatchReq, - AdminDeleteCustomerGroupsGroupCustomerBatchReq, - AdminGetCustomerGroupsGroupParams, - AdminCustomersListRes, - AdminGetCustomersParams, -} from "@medusajs/medusa" -import qs from "qs" - -import BaseResource from "../base" -import { ResponsePromise } from "../.." - -/** - * This class is used to send requests to [Admin Customer Group API Routes](https://docs.medusajs.com/api/admin#customer-groups). All its method - * are available in the JS Client under the `medusa.admin.customerGroups` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Customer Groups can be used to organize customers that share similar data or attributes into dedicated groups. - * This can be useful for different purposes such as setting a different price for a specific customer group. - * - * Related Guide: [How to manage customer groups](https://docs.medusajs.com/modules/customers/admin/manage-customer-groups). - */ -class AdminCustomerGroupsResource extends BaseResource { - /** - * Create a customer group. - * @param {AdminPostCustomerGroupsReq} payload - The data of the customer group to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer group's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.create({ - * name: "VIP" - * }) - * .then(({ customer_group }) => { - * console.log(customer_group.id); - * }) - */ - create( - payload: AdminPostCustomerGroupsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/customer-groups` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve a customer group by its ID. You can expand the customer group's relations or select the fields that should be returned. - * @param {string} id - The ID of the customer group. - * @param {AdminGetCustomerGroupsGroupParams} query - Configurations to apply on the retrieved customer group. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer group's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.retrieve(customerGroupId) - * .then(({ customer_group }) => { - * console.log(customer_group.id); - * }) - */ - retrieve( - id: string, - query?: AdminGetCustomerGroupsGroupParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/customer-groups/${id}` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - /** - * Update a customer group's details. - * @param {string} id - The ID of the customer group. - * @param {AdminPostCustomerGroupsGroupReq} payload - The attributes to update in the customer group. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer group's details. - */ - update( - id: string, - payload: AdminPostCustomerGroupsGroupReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/customer-groups/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a customer group. This doesn't delete the customers associated with the customer group. - * @param {string} id - The ID of the customer group. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.delete(customerGroupId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/customer-groups/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of customer groups. The customer groups can be filtered by fields such as `name` or `id`. The customer groups can also be sorted or paginated. - * @param {AdminGetCustomerGroupsParams} query - Filters and pagination configurations to apply on the retrieved customer groups. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of customer groups with pagination fields. - * - * @example - * To list customer groups: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.list() - * .then(({ customer_groups, limit, offset, count }) => { - * console.log(customer_groups.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the customer groups: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.list({ - * expand: "customers" - * }) - * .then(({ customer_groups, limit, offset, count }) => { - * console.log(customer_groups.length); - * }) - * ``` - * - * By default, only the first `10` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.list({ - * "expand": "customers", - * limit, - * offset - * }) - * .then(({ customer_groups, limit, offset, count }) => { - * console.log(customer_groups.length); - * }) - * ``` - */ - list( - query?: AdminGetCustomerGroupsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/customer-groups` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/customer-groups?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Add a list of customers to a customer group. - * @param {string} id - The ID of the customer group. - * @param {AdminPostCustomerGroupsGroupCustomersBatchReq} payload - The customers to add to the customer group. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer group's details. - */ - addCustomers( - id: string, - payload: AdminPostCustomerGroupsGroupCustomersBatchReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/customer-groups/${id}/customers/batch` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Remove a list of customers from a customer group. This doesn't delete the customer, only the association between the customer and the customer group. - * @param {string} id - The ID of the customer group. - * @param {AdminDeleteCustomerGroupsGroupCustomerBatchReq} payload - The customers to remove from the customer group. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer group's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.removeCustomers(customerGroupId, { - * customer_ids: [ - * { - * id: customerId - * } - * ] - * }) - * .then(({ customer_group }) => { - * console.log(customer_group.id); - * }) - */ - removeCustomers( - id: string, - payload: AdminDeleteCustomerGroupsGroupCustomerBatchReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/customer-groups/${id}/customers/batch` - return this.client.request("DELETE", path, payload, {}, customHeaders) - } - - /** - * Retrieve a list of customers in a customer group. The customers can be filtered by the `q` field. The customers can also be paginated. - * @param {string} id - The ID of the customer group. - * @param {AdminGetCustomersParams} query - Filters and pagination configurations to apply on the retrieved customers. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of customers with pagination fields. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.listCustomers(customerGroupId) - * .then(({ customers }) => { - * console.log(customers.length); - * }) - */ - listCustomers( - id: string, - query?: AdminGetCustomersParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/customer-groups/${id}/customers` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminCustomerGroupsResource diff --git a/packages/medusa-js/src/resources/admin/customers.ts b/packages/medusa-js/src/resources/admin/customers.ts deleted file mode 100644 index 264ca86814..0000000000 --- a/packages/medusa-js/src/resources/admin/customers.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { - AdminCustomersListRes, - AdminCustomersRes, - AdminGetCustomersParams, - AdminPostCustomersReq, - AdminPostCustomersCustomerReq, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../.." -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Customer API Routes](https://docs.medusajs.com/api/admin#customers). All its method - * are available in the JS Client under the `medusa.admin.customers` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Customers can either be created when they register through the {@link CustomersResource.create} method, or created by the admin using the {@link create} method. - * - * Related Guide: [How to manage customers](https://docs.medusajs.com/modules/customers/admin/manage-customers). - */ -class AdminCustomersResource extends BaseResource { - /** - * Create a customer as an admin. - * @param {AdminPostCustomersReq} payload - The customer to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customers.create({ - * email: "user@example.com", - * first_name: "Caterina", - * last_name: "Yost", - * password: "supersecret" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - */ - create( - payload: AdminPostCustomersReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/customers` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a customer's details. - * @param {string} id - The customer's ID. - * @param {AdminPostCustomersCustomerReq} payload - The attributes to update in the customer. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customers.update(customerId, { - * first_name: "Dolly" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - */ - update( - id: string, - payload: AdminPostCustomersCustomerReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/customers/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve the details of a customer. - * @param {string} id - The customer's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customers.retrieve(customerId) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/customers/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of Customers. The customers can be filtered by fields such as `q` or `groups`. The customers can also be paginated. - * @param {AdminGetCustomersParams} query - Filters and pagination configurations to apply on the retrieved customers. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of customers with pagination fields. - * - * @example - * To list customers: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customers.list() - * .then(({ customers, limit, offset, count }) => { - * console.log(customers.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the customers: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customers.list({ - * expand: "billing_address" - * }) - * .then(({ customers, limit, offset, count }) => { - * console.log(customers.length); - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customers.list({ - * expand: "billing_address", - * limit, - * offset - * }) - * .then(({ customers, limit, offset, count }) => { - * console.log(customers.length); - * }) - * ``` - */ - list( - query?: AdminGetCustomersParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/customers` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/customers?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminCustomersResource diff --git a/packages/medusa-js/src/resources/admin/discounts.ts b/packages/medusa-js/src/resources/admin/discounts.ts deleted file mode 100644 index a0e1f0336a..0000000000 --- a/packages/medusa-js/src/resources/admin/discounts.ts +++ /dev/null @@ -1,626 +0,0 @@ -import { - AdminDeleteDiscountsDiscountConditionsConditionBatchReq, - AdminDiscountConditionsRes, - AdminDiscountsDeleteRes, - AdminDiscountsListRes, - AdminDiscountsRes, - AdminGetDiscountParams, - AdminGetDiscountsDiscountConditionsConditionParams, - AdminGetDiscountsParams, - AdminPostDiscountsDiscountConditions, - AdminPostDiscountsDiscountConditionsCondition, - AdminPostDiscountsDiscountConditionsConditionBatchParams, - AdminPostDiscountsDiscountConditionsConditionBatchReq, - AdminPostDiscountsDiscountConditionsConditionParams, - AdminPostDiscountsDiscountConditionsParams, - AdminPostDiscountsDiscountDynamicCodesReq, - AdminPostDiscountsDiscountReq, - AdminPostDiscountsReq, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Discount API Routes](https://docs.medusajs.com/api/admin#discounts). All its method - * are available in the JS Client under the `medusa.admin.discounts` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Admins can create discounts with conditions and rules, providing them with advanced settings for variety of cases. - * The methods in this class can be used to manage discounts, their conditions, resources, and more. - * - * Related Guide: [How to manage discounts](https://docs.medusajs.com/modules/discounts/admin/manage-discounts). - */ -class AdminDiscountsResource extends BaseResource { - /** - * Add a Region to the list of Regions a Discount can be used in. - * @param {string} id - The discount's ID. - * @param {string} regionId - The ID of the region to add. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the discount's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.addRegion(discountId, regionId) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - */ - addRegion( - id: string, - regionId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/discounts/${id}/regions/${regionId}` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Create a discount with a given set of rules that defines how the discount is applied. - * @param {AdminPostDiscountsReq} payload - The discount to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the discount's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * import { AllocationType, DiscountRuleType } from "@medusajs/medusa" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.create({ - * code: "TEST", - * rule: { - * type: DiscountRuleType.FIXED, - * value: 10, - * allocation: AllocationType.ITEM - * }, - * regions: ["reg_XXXXXXXX"], - * is_dynamic: false, - * is_disabled: false - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - */ - create( - payload: AdminPostDiscountsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/discounts` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a discount with a given set of rules that define how the discount is applied. - * @param {string} id - The discount's ID. - * @param {AdminPostDiscountsDiscountReq} payload - The attributes to update in the discount. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the discount. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.update(discountId, { - * code: "TEST" - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - */ - update( - id: string, - payload: AdminPostDiscountsDiscountReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/discounts/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create a dynamic unique code that can map to a parent discount. This is useful if you want to automatically generate codes with the same rules and conditions. - * @param {string} id - The discount's ID. - * @param {AdminPostDiscountsDiscountDynamicCodesReq} payload - The dynamic code to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the discount. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.createDynamicCode(discountId, { - * code: "TEST", - * usage_limit: 1 - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - */ - createDynamicCode( - id: string, - payload: AdminPostDiscountsDiscountDynamicCodesReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/discounts/${id}/dynamic-codes` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a discount. Deleting the discount will make it unavailable for customers to use. - * @param {string} id - The discount's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the delete operation details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.delete(discountId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/discounts/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Delete a dynamic code from a discount. - * @param {string} id - The discount's ID. - * @param {string} code - The code of the dynamic code to delete. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the discount. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.deleteDynamicCode(discountId, code) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - */ - deleteDynamicCode( - id: string, - code: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/discounts/${id}/dynamic-codes/${code}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a discount. - * @param {string} id - The discount's ID. - * @param {AdminGetDiscountParams} query - Configurations to apply on the retrieved product category. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the discount. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.retrieve(discountId) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - */ - retrieve( - id: string, - query?: AdminGetDiscountParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/discounts/${id}` - - if (query) { - const queryString = qs.stringify(query) - path = `${path}?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a discount's details by its discount code. - * @param {string} code - The code of the discount. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the discount. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.retrieveByCode(code) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - */ - retrieveByCode( - code: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/discounts/code/${code}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of Discounts. The discounts can be filtered by fields such as `rule` or `is_dynamic`. The discounts can also be paginated. - * @param {AdminGetDiscountsParams} query - Filters and pagination configurations to apply on the retrieved discounts. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of discounts with pagination fields. - * - * @example - * To list discounts: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.list() - * .then(({ discounts, limit, offset, count }) => { - * console.log(discounts.id); - * }) - * ``` - * - * To specify relations that should be retrieved within the discounts: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.list({ - * expand: "rule" - * }) - * .then(({ discounts, limit, offset, count }) => { - * console.log(discounts.id); - * }) - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.list({ - * expand: "rule", - * limit, - * offset - * }) - * .then(({ discounts, limit, offset, count }) => { - * console.log(discounts.id); - * }) - * ``` - */ - list( - query?: AdminGetDiscountsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/discounts` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Remove a Region from the list of Regions that a Discount can be used in. This does not delete a region, only the association between it and the discount. - * @param {string} id - The discount's ID. - * @param {string} regionId - The ID of the region to remove. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the discount. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.removeRegion(discountId, regionId) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - */ - removeRegion( - id: string, - regionId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/discounts/${id}/regions/${regionId}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Create a discount condition. Only one of `products`, `product_types`, `product_collections`, `product_tags`, and `customer_groups` should be provided in the `payload` parameter, - * based on the type of discount condition. For example, if the discount condition's type is `products`, the `products` field should be provided in the `payload` parameter. - * @param {string} discountId - The discount's ID. - * @param {AdminPostDiscountsDiscountConditions} payload - The discount condition to create. - * @param {AdminPostDiscountsDiscountConditionsParams} query - Configurations to apply on the returned discount. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the discount. - * - * @example - * To create a condition in a discount: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * import { DiscountConditionOperator } from "@medusajs/medusa" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.createCondition(discountId, { - * operator: DiscountConditionOperator.IN, - * products: [productId] - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * ``` - * - * To specify relations that should be retrieved as part of the response: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * import { DiscountConditionOperator } from "@medusajs/medusa" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.createCondition(discountId, { - * operator: DiscountConditionOperator.IN, - * products: [productId] - * }, { - * expand: "rule" - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * ``` - */ - createCondition( - discountId: string, - payload: AdminPostDiscountsDiscountConditions, - query: AdminPostDiscountsDiscountConditionsParams = {}, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/discounts/${discountId}/conditions` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a discount condition. Only one of `products`, `product_types`, `product_collections`, `product_tags`, and `customer_groups` should be provided in the `payload` parameter, - * based on the type of discount condition. For example, if the discount condition's type is `products`, the `products` field should be provided in the `payload` parameter. - * @param {string} discountId - The discount's ID. - * @param {string} conditionId - The ID of the discount condition. - * @param {AdminPostDiscountsDiscountConditionsCondition} payload - The attributes to update in the discount condition. - * @param {AdminPostDiscountsDiscountConditionsConditionParams} query - Configurations to apply on the returned discount. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the discount. - * - * @example - * To update a condition in a discount: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.updateCondition(discountId, conditionId, { - * products: [ - * productId - * ] - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * ``` - * - * To specify relations that should be retrieved as part of the response: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.updateCondition(discountId, conditionId, { - * products: [ - * productId - * ] - * }, { - * expand: "rule" - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * ``` - */ - updateCondition( - discountId: string, - conditionId: string, - payload: AdminPostDiscountsDiscountConditionsCondition, - query: AdminPostDiscountsDiscountConditionsConditionParams = {}, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/discounts/${discountId}/conditions/${conditionId}` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a discount condition. This doesn't delete resources associated to the discount condition. - * @param {string} discountId - The discount's ID. - * @param {string} conditionId - The ID of the discount condition. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.deleteCondition(discountId, conditionId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - deleteCondition( - discountId: string, - conditionId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/discounts/${discountId}/conditions/${conditionId}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a Discount Condition's details. - * @param {string} discountId - The ID of the discount that the condition belongs to. - * @param {string} conditionId - The ID of the discount condition. - * @param {AdminGetDiscountsDiscountConditionsConditionParams} query - Configurations to apply on the retrieved discount condition. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the discount condition details. - * - * @example - * A simple example that retrieves a discount condition by its ID: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.getCondition(discountId, conditionId) - * .then(({ discount_condition }) => { - * console.log(discount_condition.id); - * }) - * ``` - * - * To specify relations that should be retrieved: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.getCondition(discountId, conditionId, { - * expand: "discount_rule" - * }) - * .then(({ discount_condition }) => { - * console.log(discount_condition.id); - * }) - * ``` - */ - getCondition( - discountId: string, - conditionId: string, - query?: AdminGetDiscountsDiscountConditionsConditionParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/discounts/${discountId}/conditions/${conditionId}` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Add a batch of resources to a discount condition. The type of resource depends on the type of discount condition. For example, if the discount condition's type is `products`, - * the resources being added should be products. - * @param {string} discountId - The ID of the discount the condition belongs to. - * @param {string} conditionId - The ID of the discount condition. - * @param {AdminPostDiscountsDiscountConditionsConditionBatchReq} payload - The resources to add to the discount condition. - * @param {AdminPostDiscountsDiscountConditionsConditionBatchParams} query - Configurations to apply on the retrieved discount. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the discount. - * - * @example - * To add resources to a discount condition: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.addConditionResourceBatch(discountId, conditionId, { - * resources: [{ id: itemId }] - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * ``` - * - * To specify relations to include in the returned discount: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.addConditionResourceBatch(discountId, conditionId, { - * resources: [{ id: itemId }] - * }, { - * expand: "rule" - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * ``` - */ - addConditionResourceBatch( - discountId: string, - conditionId: string, - payload: AdminPostDiscountsDiscountConditionsConditionBatchReq, - query?: AdminPostDiscountsDiscountConditionsConditionBatchParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/discounts/${discountId}/conditions/${conditionId}/batch` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Remove a batch of resources from a discount condition. This will only remove the association between the resource and the discount condition, not the resource itself. - * @param {string} discountId - The ID of the discount the condition belongs to. - * @param {string} conditionId - The ID of the discount condition. - * @param {AdminDeleteDiscountsDiscountConditionsConditionBatchReq} payload - The resources to remove. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the discount. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.deleteConditionResourceBatch(discountId, conditionId, { - * resources: [{ id: itemId }] - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - */ - deleteConditionResourceBatch( - discountId: string, - conditionId: string, - payload: AdminDeleteDiscountsDiscountConditionsConditionBatchReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/discounts/${discountId}/conditions/${conditionId}/batch` - return this.client.request("DELETE", path, payload, {}, customHeaders) - } -} - -export default AdminDiscountsResource diff --git a/packages/medusa-js/src/resources/admin/draft-orders.ts b/packages/medusa-js/src/resources/admin/draft-orders.ts deleted file mode 100644 index cb356660f1..0000000000 --- a/packages/medusa-js/src/resources/admin/draft-orders.ts +++ /dev/null @@ -1,289 +0,0 @@ -import { - AdminDraftOrdersDeleteRes, - AdminDraftOrdersListRes, - AdminDraftOrdersRes, - AdminGetDraftOrdersParams, - AdminPostDraftOrdersDraftOrderLineItemsItemReq, - AdminPostDraftOrdersDraftOrderLineItemsReq, - AdminPostDraftOrdersDraftOrderRegisterPaymentRes, - AdminPostDraftOrdersDraftOrderReq, - AdminPostDraftOrdersReq, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Draft Order API Routes](https://docs.medusajs.com/api/admin#draft-orders). All its method - * are available in the JS Client under the `medusa.admin.draftOrders` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A draft order is an order created manually by the admin. It allows admins to create orders without direct involvement from the customer. - * - * Related Guide: [How to manage draft orders](https://docs.medusajs.com/modules/orders/admin/manage-draft-orders). - */ -class AdminDraftOrdersResource extends BaseResource { - /** - * Create a Draft Order. A draft order is not transformed into an order until payment is captured. - * @param {AdminPostDraftOrdersReq} payload - The draft order to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the draft order's details - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.create({ - * email: "user@example.com", - * region_id, - * items: [ - * { - * quantity: 1 - * } - * ], - * shipping_methods: [ - * { - * option_id - * } - * ], - * }) - * .then(({ draft_order }) => { - * console.log(draft_order.id); - * }) - */ - create( - payload: AdminPostDraftOrdersReq, - customHeaders: Record = {}): ResponsePromise { - const path = `/admin/draft-orders` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create a Line Item in the Draft Order. - * @param {string} id - The ID of the draft order. - * @param {AdminPostDraftOrdersDraftOrderLineItemsReq} payload - The line item to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the draft order's details - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.addLineItem(draftOrderId, { - * quantity: 1 - * }) - * .then(({ draft_order }) => { - * console.log(draft_order.id); - * }) - */ - addLineItem( - id: string, - payload: AdminPostDraftOrdersDraftOrderLineItemsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/draft-orders/${id}/line-items` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a Draft Order. - * @param {string} id - The ID of the draft order. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.delete(draftOrderId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/draft-orders/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Delete a Line Item from a Draft Order. - * @param {string} id - The ID of the draft order that the line item belongs to. - * @param {string} itemId - The ID of the line item to delete from the draft order. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the draft order's details - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.removeLineItem(draftOrderId, itemId) - * .then(({ draft_order }) => { - * console.log(draft_order.id); - * }) - */ - removeLineItem( - id: string, - itemId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/draft-orders/${id}/line-items/${itemId}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a Draft Order's details. - * @param {string} id - The ID of the draft order. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the draft order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.retrieve(draftOrderId) - * .then(({ draft_order }) => { - * console.log(draft_order.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/draft-orders/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve an list of Draft Orders. The draft orders can be filtered by parameters such as `query`. The draft orders can also paginated. - * @param {AdminGetDraftOrdersParams} query - Filters and pagination configurations to apply on the retrieved draft orders. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of draft orders with pagination fields. - * - * @example - * To list draft orders: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.list() - * .then(({ draft_orders, limit, offset, count }) => { - * console.log(draft_orders.length); - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.list({ - * limit, - * offset - * }) - * .then(({ draft_orders, limit, offset, count }) => { - * console.log(draft_orders.length); - * }) - * ``` - */ - list( - query?: AdminGetDraftOrdersParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/draft-orders` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/draft-orders?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Capture the draft order's payment. This will also set the draft order's status to `completed` and create an order from the draft order. The payment is captured through Medusa's system payment, - * which is manual payment that isn't integrated with any third-party payment provider. It is assumed that the payment capturing is handled manually by the admin. - * @param {string} id - The ID of the draft order. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the created order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.markPaid(draftOrderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - markPaid( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/draft-orders/${id}/pay` - return this.client.request("POST", path, {}, customHeaders) - } - - /** - * Update a Draft Order's details. - * @param {string} id - The ID of the draft order. - * @param {AdminPostDraftOrdersDraftOrderReq} payload - The attributes to update in the draft order. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the draft order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.update(draftOrderId, { - * email: "user@example.com" - * }) - * .then(({ draft_order }) => { - * console.log(draft_order.id); - * }) - */ - update( - id: string, - payload: AdminPostDraftOrdersDraftOrderReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/draft-orders/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a Line Item in a Draft Order. - * @param {string} id - The ID of the draft order that the line item belongs to. - * @param {string} itemId - The ID of the line item to update. - * @param {AdminPostDraftOrdersDraftOrderLineItemsItemReq} payload - The attributes to update in the line item. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the draft order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.updateLineItem(draftOrderId, lineId, { - * quantity: 1 - * }) - * .then(({ draft_order }) => { - * console.log(draft_order.id); - * }) - */ - updateLineItem( - id: string, - itemId: string, - payload: AdminPostDraftOrdersDraftOrderLineItemsItemReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/draft-orders/${id}/line-items/${itemId}` - return this.client.request("POST", path, payload, {}, customHeaders) - } -} - -export default AdminDraftOrdersResource diff --git a/packages/medusa-js/src/resources/admin/gift-cards.ts b/packages/medusa-js/src/resources/admin/gift-cards.ts deleted file mode 100644 index fb5685b4fb..0000000000 --- a/packages/medusa-js/src/resources/admin/gift-cards.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { - AdminGetGiftCardsParams, - AdminGiftCardsDeleteRes, - AdminGiftCardsListRes, - AdminGiftCardsRes, - AdminPostGiftCardsGiftCardReq, - AdminPostGiftCardsReq, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Gift Card API Routes](https://docs.medusajs.com/api/admin#gift-cards). All its method - * are available in the JS Client under the `medusa.admin.giftCards` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Admins can create gift cards and send them directly to customers, specifying options like their balance, region, and more. - * These gift cards are different than the saleable gift cards in a store, which are created and managed through {@link AdminProductsResource}. - * - * Related Guide: [How to manage gift cards](https://docs.medusajs.com/modules/gift-cards/admin/manage-gift-cards#manage-custom-gift-cards). - */ -class AdminGiftCardsResource extends BaseResource { - /** - * Create a gift card that can redeemed by its unique code. The Gift Card is only valid within one region. - * @param {AdminPostGiftCardsReq} payload - The gift card to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the gift card's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.giftCards.create({ - * region_id - * }) - * .then(({ gift_card }) => { - * console.log(gift_card.id); - * }) - */ - create( - payload: AdminPostGiftCardsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/gift-cards` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a gift card's details. - * @param {string} id - The ID of the gift card. - * @param {AdminPostGiftCardsGiftCardReq} payload - The attributes to update in the gift card. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the gift card's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.giftCards.update(giftCardId, { - * region_id - * }) - * .then(({ gift_card }) => { - * console.log(gift_card.id); - * }) - */ - update( - id: string, - payload: AdminPostGiftCardsGiftCardReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/gift-cards/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a gift card. Once deleted, it can't be used by customers. - * @param {string} id - The ID of the gift card. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.giftCards.delete(giftCardId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/gift-cards/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a gift card's details. - * @param {string} id - The ID of the gift card. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the gift card's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.giftCards.retrieve(giftCardId) - * .then(({ gift_card }) => { - * console.log(gift_card.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/gift-cards/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of gift cards. The gift cards can be filtered by fields such as `q` passed in the `query` parameter. The gift cards can also paginated. - * @param {AdminGetGiftCardsParams} query - Filters and pagination configurations to apply on the retrieved gift cards. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of gift cards with pagination fields. - * - * @example - * To list gift cards: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.giftCards.list() - * .then(({ gift_cards, limit, offset, count }) => { - * console.log(gift_cards.length); - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.giftCards.list({ - * limit, - * offset - * }) - * .then(({ gift_cards, limit, offset, count }) => { - * console.log(gift_cards.length); - * }) - * ``` - */ - list( - query?: AdminGetGiftCardsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/gift-cards/` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/gift-cards?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminGiftCardsResource diff --git a/packages/medusa-js/src/resources/admin/index.ts b/packages/medusa-js/src/resources/admin/index.ts deleted file mode 100644 index 32785fc9b1..0000000000 --- a/packages/medusa-js/src/resources/admin/index.ts +++ /dev/null @@ -1,240 +0,0 @@ -import BaseResource from "../base" -import AdminAuthResource from "./auth" -import AdminBatchJobsResource from "./batch-jobs" -import AdminCollectionsResource from "./collections" -import AdminCurrenciesResource from "./currencies" -import AdminCustomResource from "./custom" -import AdminCustomerGroupsResource from "./customer-groups" -import AdminCustomersResource from "./customers" -import AdminDiscountsResource from "./discounts" -import AdminDraftOrdersResource from "./draft-orders" -import AdminGiftCardsResource from "./gift-cards" -import AdminInventoryItemsResource from "./inventory-item" -import AdminInvitesResource from "./invites" -import AdminNotesResource from "./notes" -import AdminNotificationsResource from "./notifications" -import AdminOrderEditsResource from "./order-edits" -import AdminOrdersResource from "./orders" -import AdminPaymentCollectionsResource from "./payment-collections" -import AdminPaymentsResource from "./payments" -import AdminPriceListResource from "./price-lists" -import AdminProductCategoriesResource from "./product-categories" -import AdminProductTagsResource from "./product-tags" -import AdminProductTypesResource from "./product-types" -import AdminProductsResource from "./products" -import AdminPublishableApiKeyResource from "./publishable-api-keys" -import AdminRegionsResource from "./regions" -import AdminReservationsResource from "./reservations" -import AdminReturnReasonsResource from "./return-reasons" -import AdminReturnsResource from "./returns" -import AdminSalesChannelsResource from "./sales-channels" -import AdminShippingOptionsResource from "./shipping-options" -import AdminShippingProfilesResource from "./shipping-profiles" -import AdminStockLocationsResource from "./stock-locations" -import AdminStoresResource from "./store" -import AdminSwapsResource from "./swaps" -import AdminTaxRatesResource from "./tax-rates" -import AdminUploadsResource from "./uploads" -import AdminUsersResource from "./users" -import AdminVariantsResource from "./variants" - -/** - * This class includes properties used to send requests to the [Admin API Routes](https://docs.medusajs.com/api/admin). All its properties - * are available in the JS Client under the `medusa.admin` property. - */ -class Admin extends BaseResource { - /** - * An instance of {@link AdminAuthResource} used to send requests to [Admin Auth API Routes](https://docs.medusajs.com/api/admin#auth). - */ - public auth = new AdminAuthResource(this.client) - /** - * An instance of {@link AdminBatchJobsResource} used to send requests to [Admin Batch Job API Routes](https://docs.medusajs.com/api/admin#batch-jobs). - */ - public batchJobs = new AdminBatchJobsResource(this.client) - /** - * An instance of {@link AdminCustomersResource} used to send requests to [Admin Customer API Routes](https://docs.medusajs.com/api/admin#customers). - */ - public customers = new AdminCustomersResource(this.client) - /** - * An instance of {@link AdminCustomerGroupsResource} used to send requests to [Admin Customer Group API Routes](https://docs.medusajs.com/api/admin#customer-groups). - */ - public customerGroups = new AdminCustomerGroupsResource(this.client) - /** - * An instance of {@link AdminDiscountsResource} used to send requests to [Admin Discount API Routes](https://docs.medusajs.com/api/admin#discounts). - */ - public discounts = new AdminDiscountsResource(this.client) - /** - * An instance of {@link AdminCurrenciesResource} used to send requests to [Admin Currency API Routes](https://docs.medusajs.com/api/admin#currencies_getcurrencies). - */ - public currencies = new AdminCurrenciesResource(this.client) - /** - * An instance of {@link AdminCollectionsResource} used to send requests to [Admin Product Collection API Routes](https://docs.medusajs.com/api/admin#product-collections). - */ - public collections = new AdminCollectionsResource(this.client) - /** - * An instance of {@link AdminDraftOrdersResource} used to send requests to [Admin Draft Order API Routes](https://docs.medusajs.com/api/admin#draft-orders). - */ - public draftOrders = new AdminDraftOrdersResource(this.client) - /** - * An instance of {@link AdminGiftCardsResource} used to send requests to [Admin Gift Card API Routes](https://docs.medusajs.com/api/admin#gift-cards). - */ - public giftCards = new AdminGiftCardsResource(this.client) - /** - * An instance of {@link AdminInvitesResource} used to send requests to [Admin Invite API Routes](https://docs.medusajs.com/api/admin#invites). - */ - public invites = new AdminInvitesResource(this.client) - /** - * An instance of {@link AdminInventoryItemsResource} used to send requests to [Admin Inventory Item API Routes](https://docs.medusajs.com/api/admin#inventory-items). - */ - public inventoryItems = new AdminInventoryItemsResource(this.client) - /** - * An instance of {@link AdminNotesResource} used to send requests to [Admin Note API Routes](https://docs.medusajs.com/api/admin#notes). - */ - public notes = new AdminNotesResource(this.client) - /** - * An instance of {@link AdminPriceListResource} used to send requests to [Admin Price List API Routes](https://docs.medusajs.com/api/admin#price-lists). - */ - public priceLists = new AdminPriceListResource(this.client) - /** - * An instance of {@link AdminProductsResource} used to send requests to [Admin Product API Routes](https://docs.medusajs.com/api/admin#products). - */ - public products = new AdminProductsResource(this.client) - /** - * An instance of {@link AdminProductTagsResource} used to send requests to [Admin Product Tag API Routes](https://docs.medusajs.com/api/admin#product-tags). - */ - public productTags = new AdminProductTagsResource(this.client) - /** - * An instance of {@link AdminProductTypesResource} used to send requests to [Admin Product Type API Routes](https://docs.medusajs.com/api/admin#product-types). - */ - public productTypes = new AdminProductTypesResource(this.client) - /** - * An instance of {@link AdminUsersResource} used to send requests to [Admin User API Routes](https://docs.medusajs.com/api/admin#users). - */ - public users = new AdminUsersResource(this.client) - /** - * An instance of {@link AdminReturnsResource} used to send requests to [Admin Return API Routes](https://docs.medusajs.com/api/admin#returns). - */ - public returns = new AdminReturnsResource(this.client) - /** - * An instance of {@link AdminOrdersResource} used to send requests to [Admin Order API Routes](https://docs.medusajs.com/api/admin#orders). - */ - public orders = new AdminOrdersResource(this.client) - /** - * An instance of {@link AdminOrderEditsResource} used to send requests to [Admin Order Edit API Routes](https://docs.medusajs.com/api/admin#order-edits). - */ - public orderEdits = new AdminOrderEditsResource(this.client) - /** - * An instance of {@link AdminPublishableApiKeyResource} used to send requests to [Admin Publishable API Key API Routes](https://docs.medusajs.com/api/admin#publishable-api-keys). - */ - public publishableApiKeys = new AdminPublishableApiKeyResource(this.client) - /** - * An instance of {@link AdminReturnReasonsResource} used to send requests to [Admin Return Reason API Routes](https://docs.medusajs.com/api/admin#return-reasons). - */ - public returnReasons = new AdminReturnReasonsResource(this.client) - /** - * @props variants - An instance of {@link AdminVariantsResource} used to send requests to [Admin Product Variant API Routes](https://docs.medusajs.com/api/admin#product-variants). - */ - public variants = new AdminVariantsResource(this.client) - /** - * An instance of {@link AdminSalesChannelsResource} used to send requests to [Admin Sales Channel API Routes](https://docs.medusajs.com/api/admin#sales-channels). - */ - public salesChannels = new AdminSalesChannelsResource(this.client) - /** - * An instance of {@link AdminSwapsResource} used to send requests to [Admin Swap API Routes](https://docs.medusajs.com/api/admin#swaps). - */ - public swaps = new AdminSwapsResource(this.client) - /** - * An instance of {@link AdminShippingProfilesResource} used to send requests to [Admin Shipping Profile API Routes](https://docs.medusajs.com/api/admin#shipping-profiles). - */ - public shippingProfiles = new AdminShippingProfilesResource(this.client) - /** - * An instance of {@link AdminStockLocationsResource} used to send requests to [Admin Stock Location API Routes](https://docs.medusajs.com/api/admin#stock-locations). - */ - public stockLocations = new AdminStockLocationsResource(this.client) - /** - * An instance of {@link AdminStoresResource} used to send requests to [Admin Store API Routes](https://docs.medusajs.com/api/admin#store). - */ - public store = new AdminStoresResource(this.client) - /** - * An instance of {@link AdminShippingOptionsResource} used to send requests to [Admin Shipping Option API Routes](https://docs.medusajs.com/api/admin#shipping-options). - */ - public shippingOptions = new AdminShippingOptionsResource(this.client) - /** - * An instance of {@link AdminRegionsResource} used to send requests to [Admin Region API Routes](https://docs.medusajs.com/api/admin#regions). - */ - public regions = new AdminRegionsResource(this.client) - /** - * An instance of {@link AdminReservationsResource} used to send requests to [Admin Reservation API Routes](https://docs.medusajs.com/api/admin#reservations). - */ - public reservations = new AdminReservationsResource(this.client) - /** - * An instance of {@link AdminNotificationsResource} used to send requests to [Admin Notification API Routes](https://docs.medusajs.com/api/admin#notifications). - */ - public notifications = new AdminNotificationsResource(this.client) - /** - * An instance of {@link AdminTaxRatesResource} used to send requests to [Admin Tax Rate API Routes](https://docs.medusajs.com/api/admin#tax-rates). - */ - public taxRates = new AdminTaxRatesResource(this.client) - /** - * An instance of {@link AdminUploadsResource} used to send requests to [Admin Upload API Routes](https://docs.medusajs.com/api/admin#uploads). - */ - public uploads = new AdminUploadsResource(this.client) - /** - * An instance of {@link AdminPaymentCollectionsResource} used to send requests to [Admin Payment Collection API Routes](https://docs.medusajs.com/api/admin#payment-collections). - */ - public paymentCollections = new AdminPaymentCollectionsResource(this.client) - /** - * An instance of {@link AdminPaymentsResource} used to send requests to [Admin Payment API Routes](https://docs.medusajs.com/api/admin#payments). - */ - public payments = new AdminPaymentsResource(this.client) - /** - * An instance of {@link AdminProductCategoriesResource} used to send requests to [Admin Product Category API Routes](https://docs.medusajs.com/api/admin#product-categories). - */ - public productCategories = new AdminProductCategoriesResource(this.client) - /** - * An instance of {@link AdminCustomResource} used to send requests to custom API Routes. - */ - public custom = new AdminCustomResource(this.client) -} - -export { - Admin, - AdminCustomResource, - AdminAuthResource, - AdminBatchJobsResource, - AdminCollectionsResource, - AdminCurrenciesResource, - AdminCustomerGroupsResource, - AdminCustomersResource, - AdminDiscountsResource, - AdminDraftOrdersResource, - AdminGiftCardsResource, - AdminInventoryItemsResource, - AdminInvitesResource, - AdminNotesResource, - AdminNotificationsResource, - AdminOrdersResource, - AdminOrderEditsResource, - AdminPriceListResource, - AdminProductTagsResource, - AdminProductTypesResource, - AdminProductsResource, - AdminPublishableApiKeyResource, - AdminRegionsResource, - AdminReservationsResource, - AdminReturnReasonsResource, - AdminReturnsResource, - AdminSalesChannelsResource, - AdminShippingOptionsResource, - AdminShippingProfilesResource, - AdminStockLocationsResource, - AdminStoresResource, - AdminSwapsResource, - AdminTaxRatesResource, - AdminUploadsResource, - AdminUsersResource, - AdminVariantsResource, - AdminPaymentCollectionsResource, - AdminPaymentsResource, - AdminProductCategoriesResource, -} diff --git a/packages/medusa-js/src/resources/admin/inventory-item.ts b/packages/medusa-js/src/resources/admin/inventory-item.ts deleted file mode 100644 index c58bc19fb0..0000000000 --- a/packages/medusa-js/src/resources/admin/inventory-item.ts +++ /dev/null @@ -1,337 +0,0 @@ -import { - AdminGetInventoryItemsItemLocationLevelsParams, - AdminGetInventoryItemsItemParams, - AdminGetInventoryItemsParams, - AdminInventoryItemsDeleteRes, - AdminInventoryItemsListWithVariantsAndLocationLevelsRes, - AdminInventoryItemsLocationLevelsRes, - AdminInventoryItemsRes, - AdminPostInventoryItemsInventoryItemReq, - AdminPostInventoryItemsItemLocationLevelsLevelReq, - AdminPostInventoryItemsItemLocationLevelsParams, - AdminPostInventoryItemsItemLocationLevelsReq, - AdminPostInventoryItemsParams, - AdminPostInventoryItemsReq, -} from "@medusajs/medusa" - -import BaseResource from "../base" -import { ResponsePromise } from "../../typings" -import qs from "qs" -import { AdminPostInventoryItemsInventoryItemParams } from "@medusajs/medusa" -import { AdminPostInventoryItemsItemLocationLevelsLevelParams } from "@medusajs/medusa" - -/** - * This class is used to send requests to [Admin Inventory Item API Routes](https://docs.medusajs.com/api/admin#inventory-items). To use these API Routes, make sure to install the - * [@medusajs/inventory](https://docs.medusajs.com/modules/multiwarehouse/install-modules#inventory-module) module in your Medusa backend. All its method - * are available in the JS Client under the `medusa.admin.inventoryItems` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Inventory items, provided by the [Inventory Module](https://docs.medusajs.com/modules/multiwarehouse/inventory-module), can be used to manage the inventory of saleable items in your store. - * - * Related Guide: [How to manage inventory items](https://docs.medusajs.com/modules/multiwarehouse/admin/manage-inventory-items). - */ -class AdminInventoryItemsResource extends BaseResource { - /** - * Retrieve an Inventory Item's details. - * @param {string} inventoryItemId - The ID of the inventory item. - * @param {AdminGetInventoryItemsItemParams} query - Configurations applied on the retrieved inventory item. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} The inventory item's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.retrieve(inventoryItemId) - * .then(({ inventory_item }) => { - * console.log(inventory_item.id); - * }) - */ - retrieve( - inventoryItemId: string, - query?: AdminGetInventoryItemsItemParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/inventory-items/${inventoryItemId}` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Update an Inventory Item's details. - * @param {string} inventoryItemId - The ID of the inventory item. - * @param {AdminPostInventoryItemsInventoryItemReq} payload - The attributes to update in the inventory item. - * @param {AdminPostInventoryItemsInventoryItemParams} query - Configurations to apply on the retrieved inventory item. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} The inventory item's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.update(inventoryItemId, { - * origin_country: "US", - * }) - * .then(({ inventory_item }) => { - * console.log(inventory_item.id); - * }) - */ - update( - inventoryItemId: string, - payload: AdminPostInventoryItemsInventoryItemReq, - query?: AdminPostInventoryItemsInventoryItemParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/inventory-items/${inventoryItemId}` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete an Inventory Item. This does not delete the associated product variant. - * @param {string} inventoryItemId - The ID of the inventory item. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} The deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.delete(inventoryItemId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - */ - delete( - inventoryItemId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/inventory-items/${inventoryItemId}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Create an Inventory Item for a product variant. - * @param {AdminPostInventoryItemsReq} payload - The inventory item to create. - * @param {AdminPostInventoryItemsParams} query - Configurations to apply on the retrieved inventory item. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} The inventory item's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.create({ - * variant_id: "variant_123", - * }) - * .then(({ inventory_item }) => { - * console.log(inventory_item.id); - * }) - */ - create( - payload: AdminPostInventoryItemsReq, - query?: AdminPostInventoryItemsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/inventory-items` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve a list of inventory items. The inventory items can be filtered by fields such as `q` or `location_id` passed in the `query` parameter. - * The inventory items can also be paginated. - * @param {AdminGetInventoryItemsParams} query - Filters and pagination configurations applied on the retrieved inventory items. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} The list of inventory items with pagination fields. - * - * @example - * To list inventory items: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.list() - * .then(({ inventory_items, count, offset, limit }) => { - * console.log(inventory_items.length); - * }) - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.list({ - * limit, - * offset - * }) - * .then(({ inventory_items, count, offset, limit }) => { - * console.log(inventory_items.length); - * }) - * ``` - */ - list( - query?: AdminGetInventoryItemsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/inventory-items` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Update a location level's details for a given inventory item. - * @param {string} inventoryItemId - The ID of the inventory item that the location level belongs to. - * @param {string} locationId - The ID of the location level to update. - * @param {AdminPostInventoryItemsItemLocationLevelsLevelReq} payload - The attributes to update in the location level. - * @param {AdminPostInventoryItemsItemLocationLevelsLevelParams} query - Configurations to apply on the returned inventory item. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} the inventory item's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.updateLocationLevel(inventoryItemId, locationId, { - * stocked_quantity: 15, - * }) - * .then(({ inventory_item }) => { - * console.log(inventory_item.id); - * }) - */ - updateLocationLevel( - inventoryItemId: string, - locationId: string, - payload: AdminPostInventoryItemsItemLocationLevelsLevelReq, - query?: AdminPostInventoryItemsItemLocationLevelsLevelParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/inventory-items/${inventoryItemId}/location-levels/${locationId}` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create a Location Level for a given Inventory Item. - * @param {string} inventoryItemId - The ID of the inventory item that the location level belongs to. - * @param {AdminPostInventoryItemsItemLocationLevelsReq} payload - The location level to create. - * @param {AdminPostInventoryItemsItemLocationLevelsParams} query - Configurations to apply on the returned inventory item. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} the inventory item's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.createLocationLevel(inventoryItemId, { - * location_id: "sloc_123", - * stocked_quantity: 10, - * }) - * .then(({ inventory_item }) => { - * console.log(inventory_item.id); - * }) - */ - createLocationLevel( - inventoryItemId: string, - payload: AdminPostInventoryItemsItemLocationLevelsReq, - query?: AdminPostInventoryItemsItemLocationLevelsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/inventory-items/${inventoryItemId}/location-levels` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a location level of an Inventory Item. - * @param {string} inventoryItemId - The ID of the inventory item. - * @param {string} locationId - The ID of the location level to delete. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} the inventory item's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.deleteLocationLevel(inventoryItemId, locationId) - * .then(({ inventory_item }) => { - * console.log(inventory_item.id); - * }) - */ - deleteLocationLevel( - inventoryItemId: string, - locationId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/inventory-items/${inventoryItemId}/location-levels/${locationId}` - - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of inventory levels of an inventory item. The inventory levels can be filtered by fields such as `location_id` passed in the `query` parameter. - * @param {string} inventoryItemId - The ID of the inventory item that the location levels belong to. - * @param {AdminGetInventoryItemsItemLocationLevelsParams} query - Filters to apply on the retrieved location levels. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} The inventory item's details and list of location levels. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.listLocationLevels(inventoryItemId) - * .then(({ inventory_item }) => { - * console.log(inventory_item.location_levels); - * }) - */ - listLocationLevels( - inventoryItemId: string, - query?: AdminGetInventoryItemsItemLocationLevelsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/inventory-items/${inventoryItemId}/location-levels` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminInventoryItemsResource diff --git a/packages/medusa-js/src/resources/admin/invites.ts b/packages/medusa-js/src/resources/admin/invites.ts deleted file mode 100644 index 0dde3303d0..0000000000 --- a/packages/medusa-js/src/resources/admin/invites.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { - AdminInviteDeleteRes, - AdminListInvitesRes, - AdminPostInvitesInviteAcceptReq, -} from "@medusajs/medusa" -import { AdminPostInvitesPayload, ResponsePromise } from "../.." -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Invite API Routes](https://docs.medusajs.com/api/admin#invites). All its method - * are available in the JS Client under the `medusa.admin.invites` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * An admin can invite new users to manage their team. This would allow new users to authenticate as admins and perform admin functionalities. - * - * Related Guide: [How to manage invites](https://docs.medusajs.com/modules/users/admin/manage-invites). - */ -class AdminInvitesResource extends BaseResource { - /** - * Accept an Invite. This will also delete the invite and create a new user that can log in and perform admin functionalities. - * The user will have the email associated with the invite, and the password provided in the `payload` parameter. - * @param {AdminPostInvitesInviteAcceptReq} payload - The user accepting the invite. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves when the invite is accepted successfully. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.invites.accept({ - * token, - * user: { - * first_name: "Brigitte", - * last_name: "Collier", - * password: "supersecret" - * } - * }) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // an error occurred - * }) - */ - accept( - payload: AdminPostInvitesInviteAcceptReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/invites/accept` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create an invite. This will generate a token associated with the invite and trigger an `invite.created` event. If you have a Notification Provider installed that handles this - * event, a notification should be sent to the email associated with the invite to allow them to accept the invite. - * @param {AdminPostInvitesPayload} payload - The invite to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves when the invite is created successfully. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.invites.create({ - * user: "user@example.com", - * role: "admin" - * }) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // an error occurred - * }) - */ - create( - payload: AdminPostInvitesPayload, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/invites` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete an invite. Only invites that weren't accepted can be deleted. - * @param {string} id - The invite's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.invites.delete(inviteId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/invites/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of invites. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of invites. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.invites.list() - * .then(({ invites }) => { - * console.log(invites.length); - * }) - */ - list( - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/invites` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Resend an invite. This renews the expiry date by seven days and generates a new token for the invite. It also triggers the `invite.created` event, - * so if you have a Notification Provider installed that handles this event, a notification should be sent to the email associated with the - * invite to allow them to accept the invite. - * @param {string} id - The invite's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves when the invite is resent successfully. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.invites.resend(inviteId) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // an error occurred - * }) - */ - resend(id: string, customHeaders: Record = {}): ResponsePromise { - const path = `/admin/invites/${id}/resend` - return this.client.request("POST", path, undefined, {}, customHeaders) - } -} - -export default AdminInvitesResource diff --git a/packages/medusa-js/src/resources/admin/notes.ts b/packages/medusa-js/src/resources/admin/notes.ts deleted file mode 100644 index fdbc75772d..0000000000 --- a/packages/medusa-js/src/resources/admin/notes.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { - AdminGetNotesParams, - AdminNotesDeleteRes, - AdminNotesListRes, - AdminNotesRes, - AdminPostNotesNoteReq, - AdminPostNotesReq, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Note API Routes](https://docs.medusajs.com/api/admin#notes). All its method - * are available in the JS Client under the `medusa.admin.notes` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Notes are created by admins and can be associated with any resource. For example, an admin can add a note to an order for additional details or remarks. - */ -class AdminNotesResource extends BaseResource { - /** - * Create a Note which can be associated with any resource. - * @param {AdminPostNotesReq} payload - The note to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the note's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notes.create({ - * resource_id, - * resource_type: "order", - * value: "We delivered this order" - * }) - * .then(({ note }) => { - * console.log(note.id); - * }) - */ - create( - payload: AdminPostNotesReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/notes` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a Note's details. - * @param {string} id - The note's ID. - * @param {AdminPostNotesNoteReq} payload - The attributes to update in the note. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the note's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notes.update(noteId, { - * value: "We delivered this order" - * }) - * .then(({ note }) => { - * console.log(note.id); - * }) - */ - update( - id: string, - payload: AdminPostNotesNoteReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/notes/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a Note. - * @param {string} id - The note's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notes.delete(noteId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/notes/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a note's details. - * @param {string} id - The note's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the note's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notes.retrieve(noteId) - * .then(({ note }) => { - * console.log(note.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/notes/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of notes. The notes can be filtered by fields such as `resource_id` passed in the `query` parameter. The notes can also be paginated. - * @param {AdminGetNotesParams} query - Filters and pagination configurations applied on retrieved notes. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of notes with pagination fields. - * - * @example - * To list notes: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notes.list() - * .then(({ notes, limit, offset, count }) => { - * console.log(notes.length); - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notes.list({ - * limit, - * offset - * }) - * .then(({ notes, limit, offset, count }) => { - * console.log(notes.length); - * }) - * ``` - */ - list( - query?: AdminGetNotesParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/notes/` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/notes?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminNotesResource diff --git a/packages/medusa-js/src/resources/admin/notifications.ts b/packages/medusa-js/src/resources/admin/notifications.ts deleted file mode 100644 index 23038c658e..0000000000 --- a/packages/medusa-js/src/resources/admin/notifications.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { - AdminGetNotificationsParams, - AdminNotificationsListRes, - AdminNotificationsRes, - AdminPostNotificationsNotificationResendReq, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../.." -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Notification API Routes](https://docs.medusajs.com/api/admin#notifications). All its method - * are available in the JS Client under the `medusa.admin.notifications` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Notifications are sent to customers to inform them of new updates. For example, a notification can be sent to the customer when their order is place or its state is updated. - * The notification's type, such as an email or SMS, is determined by the notification provider installed on the Medusa backend. - */ -class AdminNotificationsResource extends BaseResource { - /** - * Retrieve a list of notifications. The notifications can be filtered by fields such as `event_name` or `resource_type` passed in the `query` parameter. - * The notifications can also be paginated. - * @param {AdminGetNotificationsParams} query - Filters and pagination configurations applied to the retrieved notifications. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of notifications with pagination fields. - * - * @example - * To list notifications: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notifications.list() - * .then(({ notifications }) => { - * console.log(notifications.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the notifications: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notifications.list({ - * expand: "provider" - * }) - * .then(({ notifications }) => { - * console.log(notifications.length); - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notifications.list({ - * expand: "provider", - * limit, - * offset - * }) - * .then(({ notifications }) => { - * console.log(notifications.length); - * }) - * ``` - */ - list( - query?: AdminGetNotificationsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/notifications` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/notifications?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Resend a previously sent notifications, with the same data but optionally to a different address. - * @param {string} id - The notification's ID. - * @param {AdminPostNotificationsNotificationResendReq} payload - The details necessary to resend the notification. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the notification's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notifications.resend(notificationId) - * .then(({ notification }) => { - * console.log(notification.id); - * }) - */ - resend( - id: string, - payload: AdminPostNotificationsNotificationResendReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/notifications/${id}/resend` - return this.client.request("POST", path, payload, {}, customHeaders) - } -} - -export default AdminNotificationsResource diff --git a/packages/medusa-js/src/resources/admin/order-edits.ts b/packages/medusa-js/src/resources/admin/order-edits.ts deleted file mode 100644 index 7e9d675aab..0000000000 --- a/packages/medusa-js/src/resources/admin/order-edits.ts +++ /dev/null @@ -1,394 +0,0 @@ -import { - AdminOrderEditDeleteRes, - AdminOrderEditItemChangeDeleteRes, - AdminOrderEditsListRes, - AdminOrderEditsRes, - AdminPostOrderEditsEditLineItemsLineItemReq, - AdminPostOrderEditsEditLineItemsReq, - AdminPostOrderEditsOrderEditReq, - AdminPostOrderEditsReq, - GetOrderEditsOrderEditParams, - GetOrderEditsParams, -} from "@medusajs/medusa" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" -import qs from "qs" - -/** - * This class is used to send requests to [Admin Order Edit API Routes](https://docs.medusajs.com/api/admin#order-edits). All its method - * are available in the JS Client under the `medusa.admin.orderEdits` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * An admin can edit an order to remove, add, or update an item's quantity. When an admin edits an order, they're stored as an `OrderEdit`. - * - * Related Guide: [How to edit an order](https://docs.medusajs.com/modules/orders/admin/edit-order). - */ -class AdminOrderEditsResource extends BaseResource { - /** - * Retrieve an order edit's details. - * @param {string} id - The ID of the order edit. - * @param {GetOrderEditsOrderEditParams} query - Configurations to apply on the retrieved order edit. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order edit's details. - * - * @example - * A simple example that retrieves an order edit by its ID: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.retrieve(orderEditId) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - * ``` - * - * To specify relations that should be retrieved: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.retrieve(orderEditId, { - * expand: "order" - * }) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - * ``` - */ - retrieve( - id: string, - query?: GetOrderEditsOrderEditParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/order-edits/${id}` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of order edits. The order edits can be filtered by fields such as `q` or `order_id` passed to the `query` parameter. The order edits can also be paginated. - * @param {GetOrderEditsParams} query - Filters and pagination configurations applied to retrieved order edits. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of order edits with pagination fields. - * - * @example - * To list order edits: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.list() - * .then(({ order_edits, count, limit, offset }) => { - * console.log(order_edits.length) - * }) - * ``` - * - * To specify relations that should be retrieved within the order edits: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.list({ - * expand: "order" - * }) - * .then(({ order_edits, count, limit, offset }) => { - * console.log(order_edits.length) - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.list({ - * expand: "order", - * limit, - * offset - * }) - * .then(({ order_edits, count, limit, offset }) => { - * console.log(order_edits.length) - * }) - * ``` - */ - list( - query?: GetOrderEditsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/order-edits` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Create an order edit. - * @param {AdminPostOrderEditsReq} payload - The order edit to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order edit's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.create({ orderId }) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - */ - create( - payload: AdminPostOrderEditsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/order-edits` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update an Order Edit's details. - * @param {string} id - The ID of the order edit. - * @param {AdminPostOrderEditsOrderEditReq} payload - The attributes to update in an order edit. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order edit's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.update(orderEditId, { - * internal_note: "internal reason XY" - * }) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - */ - update( - id: string, - payload: AdminPostOrderEditsOrderEditReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/order-edits/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete an order edit. Only order edits that have the status `created` can be deleted. - * @param {string} id - The ID of the order edit. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.delete(orderEditId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/order-edits/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Create a line item change in the order edit that indicates adding an item in the original order. The item will not be added to the original order until the order edit is - * confirmed. - * @param {string} id - The ID of the order edit to add the line item change to. - * @param {AdminPostOrderEditsEditLineItemsReq} payload - The line item change to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order edit's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.addLineItem(orderEditId, { - * variant_id, - * quantity - * }) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - */ - addLineItem( - id: string, - payload: AdminPostOrderEditsEditLineItemsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/order-edits/${id}/items` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a line item change that indicates the addition, deletion, or update of a line item in the original order. - * @param {string} orderEditId - The ID of the order edit. - * @param {string} itemChangeId - The ID of the line item change. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.deleteItemChange(orderEdit_id, itemChangeId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - */ - deleteItemChange( - orderEditId: string, - itemChangeId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/order-edits/${orderEditId}/changes/${itemChangeId}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Request customer confirmation of an order edit. This would emit the event `order-edit.requested` which Notification Providers listen to and send - * a notification to the customer about the order edit. - * @param {string} id - The ID of the order edit. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order edit's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.requestConfirmation(orderEditId) - * .then({ order_edit }) => { - * console.log(order_edit.id) - * }) - */ - requestConfirmation( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/order-edits/${id}/request` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Cancel an order edit. - * @param {string} id - The ID of the order edit to cancel. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order edit's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.cancel(orderEditId) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - */ - cancel( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/order-edits/${id}/cancel` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Confirm an order edit. This will reflect the changes in the order edit on the associated order. - * @param {string} id - The ID of the order edit to confirm. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order edit's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.confirm(orderEditId) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - */ - confirm( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/order-edits/${id}/confirm` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Create or update a line item change in the order edit that indicates addition, deletion, or update of a line item into an original order. Line item changes - * are only reflected on the original order after the order edit is confirmed. - * @param {string} orderEditId - The ID of the order edit that the line item belongs to. - * @param {string} itemId - The ID of the line item to create or update its line item change. - * @param {AdminPostOrderEditsEditLineItemsLineItemReq} payload - The creation or update of the line item change. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order edit's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.updateLineItem(orderEditId, lineItemId, { - * quantity: 5 - * }) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - */ - updateLineItem( - orderEditId: string, - itemId: string, - payload: AdminPostOrderEditsEditLineItemsLineItemReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/order-edits/${orderEditId}/items/${itemId}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create a line item change in the order edit that indicates deleting an item in the original order. The item in the original order will not be deleted until the order edit is - * confirmed. - * @param {string} orderEditId - The ID of the order edit that the line item change belongs to. - * @param {string} itemId - The ID of the line item. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order edit's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.removeLineItem(orderEditId, lineItemId) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - */ - removeLineItem( - orderEditId: string, - itemId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/order-edits/${orderEditId}/items/${itemId}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } -} - -export default AdminOrderEditsResource diff --git a/packages/medusa-js/src/resources/admin/orders.ts b/packages/medusa-js/src/resources/admin/orders.ts deleted file mode 100644 index 3bb36506da..0000000000 --- a/packages/medusa-js/src/resources/admin/orders.ts +++ /dev/null @@ -1,787 +0,0 @@ -import { - AdminGetOrdersParams, - AdminOrdersListRes, - AdminOrdersRes, - AdminPostOrdersOrderClaimsClaimFulfillmentsReq, - AdminPostOrdersOrderClaimsClaimReq, - AdminPostOrdersOrderClaimsClaimShipmentsReq, - AdminPostOrdersOrderClaimsReq, - AdminPostOrdersOrderFulfillmentsReq, - AdminPostOrdersOrderRefundsReq, - AdminPostOrdersOrderReq, - AdminPostOrdersOrderReturnsReq, - AdminPostOrdersOrderShipmentReq, - AdminPostOrdersOrderShippingMethodsReq, - AdminPostOrdersOrderSwapsReq, - AdminPostOrdersOrderSwapsSwapFulfillmentsReq, - AdminPostOrdersOrderSwapsSwapShipmentsReq, -} from "@medusajs/medusa" -import { FindParams } from "@medusajs/medusa/dist/types/common" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Order API Routes](https://docs.medusajs.com/api/admin#orders). All its method - * are available in the JS Client under the `medusa.admin.orders` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Orders are purchases made by customers, typically through a storefront using {@link CartsResource}. Draft orders created by the admin are also transformed to an Order once the payment is captured. - * Managing orders include managing fulfillment, payment, claims, reservations, and more. - * - * Related Guide: [How to manage orders](https://docs.medusajs.com/modules/orders/admin/manage-orders). - */ -class AdminOrdersResource extends BaseResource { - /** - * Update an order's details. - * @param {string} id - The order's ID. - * @param {AdminPostOrdersOrderReq} payload - The attributes to update in the order. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.update(orderId, { - * email: "user@example.com" - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - update( - id: string, - payload: AdminPostOrdersOrderReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve an order's details. - * @param {string} id - The order's ID. - * @param {FindParams} query - Configurations to apply on the retrieved order. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * A simple example that retrieves an order by its ID: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.retrieve(orderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * ``` - * - * To specify relations that should be retrieved: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.retrieve(orderId, { - * expand: "customer" - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * ``` - */ - retrieve( - id: string, - query?: FindParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/orders/${id}` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/orders/${id}?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of orders. The orders can be filtered by fields such as `status` or `display_id` passed in the `query` parameter. The order can also be paginated. - * @param {AdminGetOrdersParams} query - Filters and pagination configurations applied on the retrieved orders. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of orders with pagination fields. - * - * @example - * To list orders: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.list() - * .then(({ orders, limit, offset, count }) => { - * console.log(orders.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the orders: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.list({ - * expand: "customers" - * }) - * .then(({ orders, limit, offset, count }) => { - * console.log(orders.length); - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.list({ - * expand: "customers", - * limit, - * offset - * }) - * .then(({ orders, limit, offset, count }) => { - * console.log(orders.length); - * }) - * ``` - */ - list( - query?: AdminGetOrdersParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/orders` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/orders?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Complete an order and change its status. A canceled order can't be completed. - * @param {string} id - The order's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.complete(orderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - complete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/complete` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Capture all the payments associated with an order. The payment of canceled orders can't be captured. - * @param {string} id - The ID of the order whose payments should be captured. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.capturePayment(orderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - capturePayment( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/capture` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Refund an amount for an order. The amount must be less than or equal the `refundable_amount` of the order. - * @param {string} id - The ID of the order whose customer should be refunded. - * @param {AdminPostOrdersOrderRefundsReq} payload - The refund's details. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.refundPayment(orderId, { - * amount: 1000, - * reason: "Do not like it" - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - refundPayment( - id: string, - payload: AdminPostOrdersOrderRefundsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/refund` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create a Fulfillment of an Order using the fulfillment provider, and change the order's fulfillment status to either `partially_fulfilled` or `fulfilled`, depending on - * whether all the items were fulfilled. - * @param {string} id - The ID of the order that the fulfillment belongs to. - * @param {AdminPostOrdersOrderFulfillmentsReq} payload - The fulfillment to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.createFulfillment(orderId, { - * items: [ - * { - * item_id, - * quantity: 1 - * } - * ] - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - createFulfillment( - id: string, - payload: AdminPostOrdersOrderFulfillmentsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/fulfillment` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Cancel an order's fulfillment and change its fulfillment status to `canceled`. - * @param {string} id - The ID of the order that the fulfillment belongs to. - * @param {string} fulfillmentId - The fulfillment's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.cancelFulfillment(orderId, fulfillmentId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - cancelFulfillment( - id: string, - fulfillmentId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/fulfillments/${fulfillmentId}/cancel` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Cancel a swap's fulfillment and change its fulfillment status to `canceled`. - * @param {string} id - The ID of the order that the swap is associated with. - * @param {string} swapId - The ID of the swap the fulfillment belongs to. - * @param {string} fulfillmentId - The fulfillment's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.cancelSwapFulfillment(orderId, swapId, fulfillmentId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - cancelSwapFulfillment( - id: string, - swapId: string, - fulfillmentId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/swaps/${swapId}/fulfillments/${fulfillmentId}/cancel` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Cancel a claim's fulfillment and change its fulfillment status to `canceled`. - * @param {string} id - The ID of the order that the claim is associated with. - * @param {string} claimId - The claim's ID. - * @param {string} fulfillmentId - The fulfillment's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.cancelClaimFulfillment(orderId, claimId, fulfillmentId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - cancelClaimFulfillment( - id: string, - claimId: string, - fulfillmentId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/claims/${claimId}/fulfillments/${fulfillmentId}/cancel` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Create a shipment and mark a fulfillment as shipped. This changes the order's fulfillment status to either `partially_shipped` or `shipped`, depending on - * whether all the items were shipped. - * @param {string} id - The ID of the order - * @param {AdminPostOrdersOrderShipmentReq} payload - The shipment to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.createShipment(order_id, { - * fulfillment_id - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - createShipment( - id: string, - payload: AdminPostOrdersOrderShipmentReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/shipment` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Request and create a return for items in an order. If the return shipping method is specified, it will be automatically fulfilled. - * @param {string} id - The order's ID. - * @param {AdminPostOrdersOrderReturnsReq} payload - The return to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. You can access the return under the `returns` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.requestReturn(orderId, { - * items: [ - * { - * item_id, - * quantity: 1 - * } - * ] - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - requestReturn( - id: string, - payload: AdminPostOrdersOrderReturnsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/return` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Cancel an order and change its status. This will also cancel any associated fulfillments and payments, and it may fail if the payment or fulfillment Provider - * is unable to cancel the payment/fulfillment. - * @param {string} id - The order's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.cancel(orderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - cancel( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/cancel` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Add a shipping method to an order. If another shipping method exists with the same shipping profile, the previous shipping method will be replaced. - * @param {string} id - The order's ID. - * @param {AdminPostOrdersOrderShippingMethodsReq} payload - The shipping method to be added. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.addShippingMethod(orderId, { - * price: 1000, - * option_id - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - addShippingMethod( - id: string, - payload: AdminPostOrdersOrderShippingMethodsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/shipping-methods` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Archive an order and change its status. - * @param {string} id - The order's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.archive(orderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - archive( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/archive` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Create a swap for an order. This includes creating a return that is associated with the swap. - * @param {string} id - The order's ID. - * @param {AdminPostOrdersOrderSwapsReq} payload - The swap to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. You can access the swap under the `swaps` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.createSwap(orderId, { - * return_items: [ - * { - * item_id, - * quantity: 1 - * } - * ] - * }) - * .then(({ order }) => { - * console.log(order.swaps); - * }) - */ - createSwap( - id: string, - payload: AdminPostOrdersOrderSwapsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/swaps` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Cancel a swap and change its status. - * @param {string} id - The ID of the order that the swap belongs to. - * @param {string} swapId - The swap's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. You can access the swap under the `swaps` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.cancelSwap(orderId, swapId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - cancelSwap( - id: string, - swapId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/swaps/${swapId}/cancel` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Create a Fulfillment for a Swap and change its fulfillment status to `fulfilled`. If it requires any additional actions, - * its fulfillment status may change to `requires_action`. - * @param {string} id - The ID of the order that the swap belongs to. - * @param {string} swapId - The swap's ID. - * @param {AdminPostOrdersOrderSwapsSwapFulfillmentsReq} payload - The fulfillment to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. You can access the swap under the `swaps` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.fulfillSwap(orderId, swapId, { - * no_notification: true, - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - fulfillSwap( - id: string, - swapId: string, - payload: AdminPostOrdersOrderSwapsSwapFulfillmentsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/swaps/${swapId}/fulfillments` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create a shipment for a swap and mark its fulfillment as shipped. This changes the swap's fulfillment status to either `shipped` or `partially_shipped`, depending on - * whether all the items were shipped. - * @param {string} id - The ID of the order that the swap belongs to. - * @param {string} swapId - The swap's ID. - * @param {AdminPostOrdersOrderSwapsSwapShipmentsReq} payload - The shipment to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. You can access the swap under the `swaps` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.createSwapShipment(orderId, swapId, { - * fulfillment_id - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - createSwapShipment( - id: string, - swapId: string, - payload: AdminPostOrdersOrderSwapsSwapShipmentsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/swaps/${swapId}/shipments` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Process a swap's payment either by refunding or issuing a payment. This depends on the `difference_due` of the swap. If `difference_due` is negative, the amount is refunded. - * If `difference_due` is positive, the amount is captured. - * @param {string} id - The ID of the order that the swap belongs to. - * @param {string} swapId - The swap's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. You can access the swap under the `swaps` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.processSwapPayment(orderId, swapId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - processSwapPayment( - id: string, - swapId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/swaps/${swapId}/process-payment` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Create a claim for an order. If a return shipping method is specified, a return will also be created and associated with the claim. If the claim's type is `refund`, - * the refund is processed as well. - * @param {string} id - The order's ID. - * @param {AdminPostOrdersOrderClaimsReq} payload - The claim to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. You can access the claim under the `claims` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.createClaim(orderId, { - * type: 'refund', - * claim_items: [ - * { - * item_id, - * quantity: 1 - * } - * ] - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - createClaim( - id: string, - payload: AdminPostOrdersOrderClaimsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/claims` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Cancel a claim and change its status. A claim can't be canceled if it has a refund, if its fulfillments haven't been canceled, of if its associated return hasn't been canceled. - * @param {string} id - The ID of the order that the claim belongs to. - * @param {string} claimId - The claim's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. You can access the swap under the `claims` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.cancelClaim(orderId, claimId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - cancelClaim( - id: string, - claimId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/claims/${claimId}/cancel` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Update a claim's details. - * @param {string} id - The ID of the order that the claim belongs to. - * @param {string} claimId - The claim's ID. - * @param {AdminPostOrdersOrderClaimsClaimReq} payload - The attributes to update in the claim. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. You can access the claims under the `claims` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.updateClaim(orderId, claimId, { - * no_notification: true - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - updateClaim( - id: string, - claimId: string, - payload: AdminPostOrdersOrderClaimsClaimReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/claims/${claimId}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create a Fulfillment for a Claim, and change its fulfillment status to `partially_fulfilled` or `fulfilled` depending on whether all the items were fulfilled. - * It may also change the status to `requires_action` if any actions are required. - * @param {string} id - The ID of the order that the claim belongs to. - * @param {string} claimId - The claim's ID. - * @param {AdminPostOrdersOrderClaimsClaimFulfillmentsReq} payload - The fulfillment to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. You can access the swap under the `claims` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.fulfillClaim(orderId, claimId, { - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - fulfillClaim( - id: string, - claimId: string, - payload: AdminPostOrdersOrderClaimsClaimFulfillmentsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/claims/${claimId}/fulfillments` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create a shipment for the claim and mark its fulfillment as shipped. If the shipment is created successfully, this changes the claim's fulfillment status - * to either `partially_shipped` or `shipped`, depending on whether all the items were shipped. - * @param {string} id - The ID of the order that the claim belongs to. - * @param {string} claimId - The claim's ID. - * @param {AdminPostOrdersOrderClaimsClaimShipmentsReq} payload - The shipment to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order's details. You can access the swap under the `claims` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.createClaimShipment(orderId, claimId, { - * fulfillment_id - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - createClaimShipment( - id: string, - claimId: string, - payload: AdminPostOrdersOrderClaimsClaimShipmentsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/orders/${id}/claims/${claimId}/shipments` - return this.client.request("POST", path, payload, {}, customHeaders) - } -} - -export default AdminOrdersResource diff --git a/packages/medusa-js/src/resources/admin/payment-collections.ts b/packages/medusa-js/src/resources/admin/payment-collections.ts deleted file mode 100644 index 68a4060262..0000000000 --- a/packages/medusa-js/src/resources/admin/payment-collections.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { - AdminGetPaymentCollectionsParams, - AdminPaymentCollectionDeleteRes, - AdminPaymentCollectionsRes, - AdminUpdatePaymentCollectionsReq, -} from "@medusajs/medusa" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" -import qs from "qs" - -/** - * This class is used to send requests to [Admin Payment Collection API Routes](https://docs.medusajs.com/api/admin#payment-collections). All its method - * are available in the JS Client under the `medusa.admin.paymentCollections` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A payment collection is useful for managing additional payments, such as for Order Edits, or installment payments. - */ -class AdminPaymentCollectionsResource extends BaseResource { - /** - * Retrieve a Payment Collection's details. - * @param {string} id - The ID of the payment collection. - * @param {AdminGetPaymentCollectionsParams} query - Configurations to apply on the retrieved payment collection. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the payment collection's details. - * - * @example - * A simple example that retrieves a payment collection by its ID: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.paymentCollections.retrieve(paymentCollectionId) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id) - * }) - * ``` - * - * To specify relations that should be retrieved: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.paymentCollections.retrieve(paymentCollectionId, { - * expand: "currency" - * }) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id) - * }) - * ``` - */ - retrieve( - id: string, - query?: AdminGetPaymentCollectionsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/payment-collections/${id}` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Update a payment collection's details. - * @param {string} id - The ID of the payment collection. - * @param {AdminUpdatePaymentCollectionsReq} payload - The attributes to update in the payment collection. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the payment collection's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.paymentCollections.update(paymentCollectionId, { - * description - * }) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id) - * }) - */ - update( - id: string, - payload: AdminUpdatePaymentCollectionsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/payment-collections/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a payment collection. Only payment collections with the statuses `canceled` or `not_paid` can be deleted. - * @param {string} id - The ID of the payment collection. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.paymentCollections.delete(paymentCollectionId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/payment-collections/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Set the status of a payment collection as `authorized`. This will also change the `authorized_amount` of the payment collection. - * @param {string} id - The ID of the payment collection. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the payment collection's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.paymentCollections.markAsAuthorized(paymentCollectionId) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id) - * }) - */ - markAsAuthorized( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/payment-collections/${id}/authorize` - return this.client.request("POST", path, undefined, {}, customHeaders) - } -} - -export default AdminPaymentCollectionsResource diff --git a/packages/medusa-js/src/resources/admin/payments.ts b/packages/medusa-js/src/resources/admin/payments.ts deleted file mode 100644 index 6acfe68a89..0000000000 --- a/packages/medusa-js/src/resources/admin/payments.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { - AdminPaymentRes, - AdminPostPaymentRefundsReq, - AdminRefundRes, - GetPaymentsParams, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Payment API Routes](https://docs.medusajs.com/api/admin#payments). All its method - * are available in the JS Client under the `medusa.admin.payments` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A payment can be related to an order, swap, return, or more. It can be captured or refunded. - */ -class AdminPaymentsResource extends BaseResource { - /** - * Retrieve a payment's details. - * @param {string} id - The payment's ID. - * @param {GetPaymentsParams} query - Configurations to apply on the retrieved payment. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the payment's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.payments.retrieve(paymentId) - * .then(({ payment }) => { - * console.log(payment.id); - * }) - */ - retrieve( - id: string, - query?: GetPaymentsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/payments/${id}` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/payments/${id}?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Capture a payment. - * @param {string} id - The payment's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the payment's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.payments.capturePayment(paymentId) - * .then(({ payment }) => { - * console.log(payment.id); - * }) - */ - capturePayment( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/payments/${id}/capture` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Refund a payment. The payment must be captured first. - * @param {string} id - The payment's ID. - * @param {AdminPostPaymentRefundsReq} payload - The refund to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the refund's details. - * - * @example - * import { RefundReason } from "@medusajs/medusa"; - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.payments.refundPayment(paymentId, { - * amount: 1000, - * reason: RefundReason.RETURN, - * note: "Do not like it", - * }) - * .then(({ refund }) => { - * console.log(refund.amount); - * }) - */ - refundPayment( - id: string, - payload: AdminPostPaymentRefundsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/payments/${id}/refund` - return this.client.request("POST", path, payload, {}, customHeaders) - } -} - -export default AdminPaymentsResource diff --git a/packages/medusa-js/src/resources/admin/price-lists.ts b/packages/medusa-js/src/resources/admin/price-lists.ts deleted file mode 100644 index 4ed135b449..0000000000 --- a/packages/medusa-js/src/resources/admin/price-lists.ts +++ /dev/null @@ -1,407 +0,0 @@ -import { - AdminDeletePriceListPricesPricesReq, - AdminDeletePriceListsPriceListProductsPricesBatchReq, - AdminGetPriceListPaginationParams, - AdminGetPriceListsPriceListProductsParams, - AdminPostPriceListPricesPricesReq, - AdminPostPriceListsPriceListPriceListReq, - AdminPostPriceListsPriceListReq, - AdminPriceListDeleteBatchRes, - AdminPriceListDeleteProductPricesRes, - AdminPriceListDeleteRes, - AdminPriceListDeleteVariantPricesRes, - AdminPriceListRes, - AdminPriceListsListRes, - AdminPriceListsProductsListRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Price List API Routes](https://docs.medusajs.com/api/admin#price-lists). All its method - * are available in the JS Client under the `medusa.admin.priceLists` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A price list are special prices applied to products based on a set of conditions, such as customer group. - * - * Related Guide: [How to manage price lists](https://docs.medusajs.com/modules/price-lists/admin/manage-price-lists). - */ -class AdminPriceListResource extends BaseResource { - /** - * Create a price list. - * @param {AdminPostPriceListsPriceListReq} payload - The price list to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the price list details. - * - * @example - * medusa.admin.priceLists.create({ - * name: "New Price List", - * description: "A new price list", - * type: PriceListType.SALE, - * prices: [ - * { - * amount: 1000, - * variant_id, - * currency_code: "eur" - * } - * ] - * }) - * .then(({ price_list }) => { - * console.log(price_list.id); - * }) - */ - create( - payload: AdminPostPriceListsPriceListReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/price-lists` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a price list's details. - * @param {string} id - The ID of the price list. - * @param {AdminPostPriceListsPriceListPriceListReq} payload - The attributes to update in the price list. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the price list details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.update(priceListId, { - * name: "New Price List" - * }) - * .then(({ price_list }) => { - * console.log(price_list.id); - * }) - */ - update( - id: string, - payload: AdminPostPriceListsPriceListPriceListReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/price-lists/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a price list and its associated prices. - * @param {string} id - The ID of the price list. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.delete(priceListId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/price-lists/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a price list's details. - * @param {string} id - The ID of the price list. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the price list details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.retrieve(priceListId) - * .then(({ price_list }) => { - * console.log(price_list.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/price-lists/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of price lists. The price lists can be filtered by fields such as `q` or `status` passed in the `query` parameter. The price lists can also be sorted or paginated. - * @param {AdminGetPriceListPaginationParams} query - Filters and pagination configurations to apply on the retrieved price lists. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of price lists with pagination fields. - * - * @example - * To list price lists: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.list() - * .then(({ price_lists, limit, offset, count }) => { - * console.log(price_lists.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the price lists: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.list({ - * expand: "prices" - * }) - * .then(({ price_lists, limit, offset, count }) => { - * console.log(price_lists.length); - * }) - * ``` - * - * By default, only the first `10` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.list({ - * expand: "prices", - * limit, - * offset - * }) - * .then(({ price_lists, limit, offset, count }) => { - * console.log(price_lists.length); - * }) - * ``` - */ - list( - query?: AdminGetPriceListPaginationParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/price-lists/` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/price-lists?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a price list's products. The products can be filtered by fields such as `q` or `status` passed in the `query` parameter. The products can also be sorted or paginated. - * @param {string} id - The ID of the price list. - * @param {AdminGetPriceListsPriceListProductsParams} query - Filters and pagination configurations applied on the retrieved products. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of products with pagination fields. - * - * @example - * To list products in a price list: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.listProducts(priceListId) - * .then(({ products, limit, offset, count }) => { - * console.log(products.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the products: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.listProducts(priceListId, { - * expand: "variants" - * }) - * .then(({ products, limit, offset, count }) => { - * console.log(products.length); - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.listProducts(priceListId, { - * expand: "variants", - * limit, - * offset - * }) - * .then(({ products, limit, offset, count }) => { - * console.log(products.length); - * }) - * ``` - */ - listProducts( - id: string, - query?: AdminGetPriceListsPriceListProductsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/price-lists/${id}/products` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/price-lists/${id}/products?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Add or update a list of prices in a price list. - * @param {string} id - The ID of the price list. - * @param {AdminPostPriceListPricesPricesReq} payload - The details of prices to add or update. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the price list's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.addPrices(priceListId, { - * prices: [ - * { - * amount: 1000, - * variant_id, - * currency_code: "eur" - * } - * ] - * }) - * .then(({ price_list }) => { - * console.log(price_list.id); - * }) - */ - addPrices( - id: string, - payload: AdminPostPriceListPricesPricesReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/price-lists/${id}/prices/batch` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a list of prices in a price list - * @param {string} id - The ID of the price list. - * @param {AdminDeletePriceListPricesPricesReq} payload - The prices to delete. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.deletePrices(priceListId, { - * price_ids: [ - * price_id - * ] - * }) - * .then(({ ids, object, deleted }) => { - * console.log(ids.length); - * }) - */ - deletePrices( - id: string, - payload: AdminDeletePriceListPricesPricesReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/price-lists/${id}/prices/batch` - return this.client.request("DELETE", path, payload, {}, customHeaders) - } - - /** - * Delete all the prices related to a specific product in a price list. - * @param {string} priceListId - The ID of the price list. - * @param {string} productId - The product's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.deleteProductPrices(priceListId, productId) - * .then(({ ids, object, deleted }) => { - * console.log(ids.length); - * }) - */ - deleteProductPrices( - priceListId: string, - productId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/price-lists/${priceListId}/products/${productId}/prices` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Delete all the prices related to a specific product variant in a price list. - * @param {string} priceListId - The ID of the price list. - * @param {string} variantId - The ID of the product variant. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.deleteVariantPrices(priceListId, variantId) - * .then(({ ids, object, deleted }) => { - * console.log(ids); - * }) - */ - deleteVariantPrices( - priceListId: string, - variantId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/price-lists/${priceListId}/variants/${variantId}/prices` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Delete all the prices associated with multiple products in a price list. - * @param {string} priceListId - The ID of the price list. - * @param {AdminDeletePriceListsPriceListProductsPricesBatchReq} payload - The products whose prices should be deleted. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.deleteProductsPrices(priceListId, { - * product_ids: [ - * productId1, - * productId2, - * ] - * }) - * .then(({ ids, object, deleted }) => { - * console.log(ids.length); - * }) - */ - deleteProductsPrices( - priceListId: string, - payload: AdminDeletePriceListsPriceListProductsPricesBatchReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/price-lists/${priceListId}/products/prices/batch` - return this.client.request("DELETE", path, payload, {}, customHeaders) - } -} - -export default AdminPriceListResource diff --git a/packages/medusa-js/src/resources/admin/product-categories.ts b/packages/medusa-js/src/resources/admin/product-categories.ts deleted file mode 100644 index daad77449d..0000000000 --- a/packages/medusa-js/src/resources/admin/product-categories.ts +++ /dev/null @@ -1,281 +0,0 @@ -import { - AdminDeleteProductCategoriesCategoryProductsBatchReq, - AdminGetProductCategoriesParams, - AdminPostProductCategoriesCategoryProductsBatchReq, - AdminPostProductCategoriesReq, - AdminProductCategoriesCategoryDeleteRes, - AdminProductCategoriesListRes, - AdminProductCategoriesCategoryRes, - AdminGetProductCategoryParams, - AdminPostProductCategoriesCategoryReq, -} from "@medusajs/medusa" -import qs from "qs" - -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Product Category API Routes](https://docs.medusajs.com/api/admin#product-categories). All its method - * are available in the JS Client under the `medusa.admin.productCategories` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Products can be categoriezed into categories. A product can be added into more than one category. - * - * Related Guide: [How to manage product categories](https://docs.medusajs.com/modules/products/admin/manage-categories). - * - * @featureFlag product_categories - */ -class AdminProductCategoriesResource extends BaseResource { - /** - * Retrieve a product category's details. - * @param {string} productCategoryId - The ID of the product category. - * @param {AdminGetProductCategoryParams} query - Configurations to apply on the retrieved product category. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product category's details. - * - * @example - * A simple example that retrieves an order by its ID: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.retrieve(productCategoryId) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - * ``` - * - * To specify relations that should be retrieved: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.retrieve(productCategoryId, { - * expand: "category_children" - * }) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - * ``` - */ - retrieve( - productCategoryId: string, - query?: AdminGetProductCategoryParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/product-categories/${productCategoryId}` - - if (query) { - const queryString = qs.stringify(query) - path = `${path}?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Create a product category. - * @param {AdminPostProductCategoriesReq} payload - The product category's details. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product category's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.create({ - * name: "Skinny Jeans", - * }) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - */ - create( - payload: AdminPostProductCategoriesReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/product-categories` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Updates a product category. - * @param {string} productCategoryId - The ID of the product category. - * @param {AdminPostProductCategoriesCategoryReq} payload - The attributes to update in the product category. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product category's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.update(productCategoryId, { - * name: "Skinny Jeans" - * }) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - */ - update( - productCategoryId: string, - payload: AdminPostProductCategoriesCategoryReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/product-categories/${productCategoryId}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve a list of product categories. The product categories can be filtered by fields such as `q` or `handle` passed in the `query` parameter. - * The product categories can also be paginated. - * @param {AdminGetProductCategoriesParams} query - Filters and pagination configurations to apply on the retrieved product categories. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of product categories with pagination fields. - * - * @example - * To list product categories: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.list() - * .then(({ product_categories, limit, offset, count }) => { - * console.log(product_categories.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the product category: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.list({ - * expand: "category_children" - * }) - * .then(({ product_categories, limit, offset, count }) => { - * console.log(product_categories.length); - * }) - * ``` - * - * By default, only the first `100` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.list({ - * expand: "category_children", - * limit, - * offset - * }) - * .then(({ product_categories, limit, offset, count }) => { - * console.log(product_categories.length); - * }) - * ``` - */ - list( - query?: AdminGetProductCategoriesParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/product-categories` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Delete a product category. This does not delete associated products. - * @param {string} productCategoryId - The ID of the product category. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.delete(productCategoryId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - productCategoryId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/product-categories/${productCategoryId}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Remove a list of products from a product category. - * @param {string} productCategoryId - The ID of the product category. - * @param {AdminDeleteProductCategoriesCategoryProductsBatchReq} payload - The products to delete. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product category's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.removeProducts(productCategoryId, { - * product_ids: [ - * { - * id: productId - * } - * ] - * }) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - */ - removeProducts( - productCategoryId: string, - payload: AdminDeleteProductCategoriesCategoryProductsBatchReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/product-categories/${productCategoryId}/products/batch` - return this.client.request("DELETE", path, payload, {}, customHeaders) - } - - /** - * Add a list of products to a product category. - * @param {string} productCategoryId - The ID of the product category. - * @param {AdminPostProductCategoriesCategoryProductsBatchReq} payload - The products to add. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product category's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.addProducts(productCategoryId, { - * product_ids: [ - * { - * id: productId - * } - * ] - * }) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - */ - addProducts( - productCategoryId: string, - payload: AdminPostProductCategoriesCategoryProductsBatchReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/product-categories/${productCategoryId}/products/batch` - return this.client.request("POST", path, payload, {}, customHeaders) - } -} - -export default AdminProductCategoriesResource diff --git a/packages/medusa-js/src/resources/admin/product-tags.ts b/packages/medusa-js/src/resources/admin/product-tags.ts deleted file mode 100644 index c4ef68b047..0000000000 --- a/packages/medusa-js/src/resources/admin/product-tags.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { - AdminGetProductTagsParams, - AdminProductTagsListRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Product Tag API Routes](https://docs.medusajs.com/api/admin#product-tags). All its method - * are available in the JS Client under the `medusa.admin.productTags` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Product tags are string values created when you create or update a product with a new tag. - * Products can have more than one tag, and products can share tags. This allows admins to associate products to similar tags that can be used to filter products. - */ -class AdminProductTagsResource extends BaseResource { - /** - * Retrieve a list of product tags. The product tags can be filtered by fields such as `q` or `value` passed in the `query` parameter. The product tags can also be sorted or paginated. - * @param {AdminGetProductTagsParams} query - Filters and pagination configurations to apply on the retrieved product tags. - * @returns {ResponsePromise} Resolves to the list of product tags with pagination fields. - * - * @example - * To list product tags: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productTags.list() - * .then(({ product_tags }) => { - * console.log(product_tags.length); - * }) - * ``` - * - * By default, only the first `10` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productTags.list({ - * limit, - * offset - * }) - * .then(({ product_tags }) => { - * console.log(product_tags.length); - * }) - * ``` - */ - list( - query?: AdminGetProductTagsParams - ): ResponsePromise { - let path = `/admin/product-tags` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/product-tags?${queryString}` - } - - return this.client.request("GET", path) - } -} - -export default AdminProductTagsResource diff --git a/packages/medusa-js/src/resources/admin/product-types.ts b/packages/medusa-js/src/resources/admin/product-types.ts deleted file mode 100644 index 78463b47be..0000000000 --- a/packages/medusa-js/src/resources/admin/product-types.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { - AdminGetProductTypesParams, - AdminProductTypesListRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Product Type API Routes](https://docs.medusajs.com/api/admin#product-types). All its method - * are available in the JS Client under the `medusa.admin.productTypes` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Product types are string values created when you create or update a product with a new type. - * Products can have one type, and products can share types. This allows admins to associate products with a type that can be used to filter products. - */ -class AdminProductTypesResource extends BaseResource { - /** - * Retrieve a list of product types. The product types can be filtered by fields such as `q` or `value` passed in the `query` parameter. - * The product types can also be sorted or paginated. - * @param {AdminGetProductTypesParams} query - Filters and pagination configurations to apply on the retrieved product types. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of product types with pagination fields. - * - * @example - * To list product types: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productTypes.list() - * .then(({ product_types }) => { - * console.log(product_types.length); - * }) - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productTypes.list({ - * limit, - * offset - * }) - * .then(({ product_types }) => { - * console.log(product_types.length); - * }) - * ``` - */ - list( - query?: AdminGetProductTypesParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/product-types` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminProductTypesResource diff --git a/packages/medusa-js/src/resources/admin/products.ts b/packages/medusa-js/src/resources/admin/products.ts deleted file mode 100644 index 7bca1c143b..0000000000 --- a/packages/medusa-js/src/resources/admin/products.ts +++ /dev/null @@ -1,473 +0,0 @@ -import { - AdminGetProductsParams, - AdminGetProductsVariantsParams, - AdminPostProductsProductMetadataReq, - AdminPostProductsProductOptionsOption, - AdminPostProductsProductOptionsReq, - AdminPostProductsProductReq, - AdminPostProductsProductVariantsReq, - AdminPostProductsProductVariantsVariantReq, - AdminPostProductsReq, - AdminProductsDeleteOptionRes, - AdminProductsDeleteRes, - AdminProductsDeleteVariantRes, - AdminProductsListRes, - AdminProductsListTagsRes, - AdminProductsListTypesRes, - AdminProductsListVariantsRes, - AdminProductsRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Product API Routes](https://docs.medusajs.com/api/admin#products). All its method - * are available in the JS Client under the `medusa.admin.products` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Products are saleable items in a store. This also includes [saleable gift cards](https://docs.medusajs.com/modules/gift-cards/admin/manage-gift-cards#manage-gift-card-product) in a store. - * - * Related Guide: [How to manage products](https://docs.medusajs.com/modules/products/admin/manage-products). - */ -class AdminProductsResource extends BaseResource { - /** - * Create a new Product. This API Route can also be used to create a gift card if the `is_giftcard` field is set to `true`. - * @param {AdminPostProductsReq} payload - The product to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.create({ - * title: "Shirt", - * is_giftcard: false, - * discountable: true - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - */ - create( - payload: AdminPostProductsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve a product's details. - * @param {string} id - The product's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.retrieve(productId) - * .then(({ product }) => { - * console.log(product.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Update a Product's details. - * @param {string} id - The product's ID. - * @param {AdminPostProductsProductReq} payload - The attributes to update in a product. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.update(productId, { - * title: "Shirt", - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - */ - update( - id: string, - payload: AdminPostProductsProductReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a product and its associated product variants and options. - * @param {string} id - The product's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.delete(productId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of products. The products can be filtered by fields such as `q` or `status` passed in the `query` parameter. The products can also be sorted or paginated. - * @param {AdminGetProductsParams} query - Filters and pagination configurations to apply on the retrieved products. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of products with pagination fields. - * - * @example - * To list products: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.list() - * .then(({ products, limit, offset, count }) => { - * console.log(products.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the products: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.list({ - * expand: "images" - * }) - * .then(({ products, limit, offset, count }) => { - * console.log(products.length); - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.list({ - * expand: "images", - * limit, - * offset - * }) - * .then(({ products, limit, offset, count }) => { - * console.log(products.length); - * }) - * ``` - */ - list( - query?: AdminGetProductsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/products` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/products?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * @ignore - * - * @deprecated Use {@link AdminProductTypesResource.list} instead. - */ - listTypes( - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/types` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of Product Tags with how many times each is used in products. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of tags. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.listTags() - * .then(({ tags }) => { - * console.log(tags.length); - * }) - */ - listTags( - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/tag-usage` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Set the metadata of a product. It can be any key-value pair, which allows adding custom data to a product. Learn about how you can update and delete the metadata attribute - * [here](https://docs.medusajs.com/development/entities/overview#metadata-attribute). - * @param {string} id - The product's ID. - * @param {AdminPostProductsProductMetadataReq} payload - The metadata details to add, update, or delete. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.setMetadata(productId, { - * key: "test", - * value: "true" - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - */ - setMetadata( - id: string, - payload: AdminPostProductsProductMetadataReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/${id}/metadata` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create a product variant associated with a product. Each product variant must have a unique combination of product option values. - * @param {string} id - The ID of the product that the variant belongs to. - * @param {AdminPostProductsProductVariantsReq} payload - The product variant to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product's details. You can access the variant under the `variants` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.createVariant(productId, { - * title: "Color", - * prices: [ - * { - * amount: 1000, - * currency_code: "eur" - * } - * ], - * options: [ - * { - * option_id, - * value: "S" - * } - * ], - * inventory_quantity: 100 - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - */ - createVariant( - id: string, - payload: AdminPostProductsProductVariantsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/${id}/variants` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a product variant's details. - * @param {string} id - The ID of the product that the variant belongs to. - * @param {string} variantId - The ID of the product variant. - * @param {AdminPostProductsProductVariantsVariantReq} payload - The attributes to update in the product variant. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product's details. You can access the variant under the `variants` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.updateVariant(productId, variantId, { - * title: "Color", - * prices: [ - * { - * amount: 1000, - * currency_code: "eur" - * } - * ], - * options: [ - * { - * option_id, - * value: "S" - * } - * ], - * inventory_quantity: 100 - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - */ - updateVariant( - id: string, - variantId: string, - payload: AdminPostProductsProductVariantsVariantReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/${id}/variants/${variantId}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a product variant. - * @param {string} id - The ID of the product that the variant belongs to. - * @param {string} variantId - The ID of the product variant. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.deleteVariant(productId, variantId) - * .then(({ variant_id, object, deleted, product }) => { - * console.log(product.id); - * }) - */ - deleteVariant( - id: string, - variantId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/${id}/variants/${variantId}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * List the product variants associated with a product. The product variants can be filtered by fields such as `q` or `manage_inventory` passed in the `query` parameter. The product variants can also be sorted or paginated. - * @param {string} id - The ID of the product that the variants belongs to. - * @param {AdminGetProductsVariantsParams} query - Filters and pagination configurations to apply on the retrieved product variants. If undefined, the first 100 records are retrieved. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of product variants with pagination fields. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.listVariants(productId, { - * limit: 10, - * }) - * .then(({ variants, limit, offset, count }) => { - * console.log(variants.length); - * }) - */ - listVariants( - id: string, - query?: AdminGetProductsVariantsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/products/${id}/variants` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/products/${id}/variants?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Add a product option to a product. - * @param {string} id - The product's ID. - * @param {AdminPostProductsProductOptionsReq} payload - The option to add. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product's details. You can access the variant under the `options` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.addOption(productId, { - * title: "Size" - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - */ - addOption( - id: string, - payload: AdminPostProductsProductOptionsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/${id}/options` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a product option's details. - * @param {string} id - The ID of the product that the option belongs to. - * @param {string} optionId - The ID of the product option. - * @param {AdminPostProductsProductOptionsOption} payload - The attributes to update in the product option. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product's details. You can access the variant under the `options` property. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.updateOption(productId, optionId, { - * title: "Size" - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - */ - updateOption( - id: string, - optionId: string, - payload: AdminPostProductsProductOptionsOption, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/${id}/options/${optionId}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a product option. If there are product variants that use this product option, they must be deleted before deleting the product option. - * @param {string} id - The ID of the product that the option belongs to. - * @param {string} optionId - The ID of the product option. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - */ - deleteOption( - id: string, - optionId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/products/${id}/options/${optionId}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } -} - -export default AdminProductsResource diff --git a/packages/medusa-js/src/resources/admin/publishable-api-keys.ts b/packages/medusa-js/src/resources/admin/publishable-api-keys.ts deleted file mode 100644 index 0e2b33e89d..0000000000 --- a/packages/medusa-js/src/resources/admin/publishable-api-keys.ts +++ /dev/null @@ -1,297 +0,0 @@ -import qs from "qs" - -import { - AdminDeletePublishableApiKeySalesChannelsBatchReq, - AdminPostPublishableApiKeySalesChannelsBatchReq, - AdminPostPublishableApiKeysPublishableApiKeyReq, - AdminPostPublishableApiKeysReq, - AdminPublishableApiKeyDeleteRes, - AdminPublishableApiKeysListRes, - AdminPublishableApiKeysRes, - GetPublishableApiKeySalesChannelsParams, - GetPublishableApiKeysParams, -} from "@medusajs/medusa" - -import { AdminPublishableApiKeysListSalesChannelsRes } from "@medusajs/medusa" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Publishable API Key API Routes](https://docs.medusajs.com/api/admin#publishable-api-keys). All its method - * are available in the JS Client under the `medusa.admin.publishableApiKeys` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Publishable API Keys can be used to scope Store API calls with an API key, determining what resources are retrieved when querying the API. - * For example, a publishable API key can be associated with one or more sales channels. When it is passed in the header of a request to the List Product store API Route, - * the sales channels are inferred from the key and only products associated with those sales channels are retrieved. - * Admins can manage publishable API keys and their associated resources. Currently, only Sales Channels are supported as a resource. - * - * Related Guide: [How to manage publishable API keys](https://docs.medusajs.com/development/publishable-api-keys/admin/manage-publishable-api-keys). - */ -class AdminPublishableApiKeyResource extends BaseResource { - /** - * Retrieve a publishable API key's details. - * @param {string} id - The ID of the publishable API key. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the publishable API key's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.retrieve(publishableApiKeyId) - * .then(({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/publishable-api-keys/${id}` - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of publishable API keys. The publishable API keys can be filtered by fields such as `q` passed in `query`. The publishable API keys can also be paginated. - * @param {GetPublishableApiKeysParams} query - Filters and pagination configurations to apply on the retrieved publishable API keys. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of publishable API keys with pagination fields. - * - * @example - * To list publishable API keys: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.list() - * .then(({ publishable_api_keys, count, limit, offset }) => { - * console.log(publishable_api_keys) - * }) - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.list({ - * limit, - * offset - * }) - * .then(({ publishable_api_keys, count, limit, offset }) => { - * console.log(publishable_api_keys) - * }) - * ``` - */ - list( - query?: GetPublishableApiKeysParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/publishable-api-keys` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Create a publishable API key. - * @param {AdminPostPublishableApiKeysReq} payload - The publishable API key to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the publishbale API key's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.create({ - * title - * }) - * .then(({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * }) - */ - create( - payload: AdminPostPublishableApiKeysReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/publishable-api-keys` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a publishable API key's details. - * @param {string} id - The ID of the publishable API key. - * @param {AdminPostPublishableApiKeysPublishableApiKeyReq} payload - The attributes to update in the publishable API key. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the publishbale API key's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.update(publishableApiKeyId, { - * title: "new title" - * }) - * .then(({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * }) - */ - update( - id: string, - payload: AdminPostPublishableApiKeysPublishableApiKeyReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/publishable-api-keys/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a publishable API key. Associated resources, such as sales channels, are not deleted. - * @param {string} id - The ID of the publishable API key - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the delete operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.delete(publishableApiKeyId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/publishable-api-keys/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Revoke a publishable API key. Revoking the publishable API Key can't be undone, and the key can't be used in future requests. - * @param {string} id - The ID of the publishable API key. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the publishbale API key's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.revoke(publishableApiKeyId) - * .then(({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * }) - */ - revoke( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/publishable-api-keys/${id}/revoke` - return this.client.request("POST", path, {}, {}, customHeaders) - } - - /** - * Add a list of sales channels to a publishable API key. - * @param {string} id - The ID of the publishable API key. - * @param {AdminPostPublishableApiKeySalesChannelsBatchReq} payload - The sales channels to add. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the publishbale API key's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.addSalesChannelsBatch(publishableApiKeyId, { - * sales_channel_ids: [ - * { - * id: channelId - * } - * ] - * }) - * .then(({ publishable_api_key }) => { - * console.log(publishable_api_key.id); - * }) - */ - addSalesChannelsBatch( - id: string, - payload: AdminPostPublishableApiKeySalesChannelsBatchReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/publishable-api-keys/${id}/sales-channels/batch` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Remove a list of sales channels from a publishable API key. This doesn't delete the sales channels and only removes the association between them and the publishable API key. - * @param {string} id - The ID of the publishable API key. - * @param {AdminDeletePublishableApiKeySalesChannelsBatchReq} payload - The sales channels to delete from the publishable API key. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the publishbale API key's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.deleteSalesChannelsBatch(publishableApiKeyId, { - * sales_channel_ids: [ - * { - * id: channelId - * } - * ] - * }) - * .then(({ publishable_api_key }) => { - * console.log(publishable_api_key.id); - * }) - */ - deleteSalesChannelsBatch( - id: string, - payload: AdminDeletePublishableApiKeySalesChannelsBatchReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/publishable-api-keys/${id}/sales-channels/batch` - return this.client.request("DELETE", path, payload, {}, customHeaders) - } - - /** - * List the sales channels associated with a publishable API key. The sales channels can be filtered by fields such as `q` passed in the `query` parameter. - * @param {string} id - The ID of the publishable API key. - * @param {GetPublishableApiKeySalesChannelsParams} query - Filters to apply on the retrieved sales channels. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of sales channels. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.listSalesChannels() - * .then(({ sales_channels }) => { - * console.log(sales_channels.length) - * }) - */ - listSalesChannels( - id: string, - query?: GetPublishableApiKeySalesChannelsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/publishable-api-keys/${id}/sales-channels` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminPublishableApiKeyResource diff --git a/packages/medusa-js/src/resources/admin/regions.ts b/packages/medusa-js/src/resources/admin/regions.ts deleted file mode 100644 index 006a623e6b..0000000000 --- a/packages/medusa-js/src/resources/admin/regions.ts +++ /dev/null @@ -1,375 +0,0 @@ -import { - AdminPostRegionsReq, - AdminRegionsRes, - AdminPostRegionsRegionReq, - AdminRegionsDeleteRes, - AdminRegionsListRes, - AdminGetRegionsParams, - AdminPostRegionsRegionCountriesReq, - AdminPostRegionsRegionFulfillmentProvidersReq, - AdminPostRegionsRegionPaymentProvidersReq, - AdminGetRegionsRegionFulfillmentOptionsRes, - AdminGetRegionsRegionParams, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Region API Routes](https://docs.medusajs.com/api/admin#regions). All its method - * are available in the JS Client under the `medusa.admin.regions` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Regions are different countries or geographical regions that the commerce store serves customers in. - * Admins can manage these regions, their providers, and more. - * - * Related Guide: [How to manage regions](https://docs.medusajs.com/modules/regions-and-currencies/admin/manage-regions). - */ -class AdminRegionsResource extends BaseResource { - /** - * Create a region. - * @param {AdminPostRegionsReq} payload - The region to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the region's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.create({ - * name: "Europe", - * currency_code: "eur", - * tax_rate: 0, - * payment_providers: [ - * "manual" - * ], - * fulfillment_providers: [ - * "manual" - * ], - * countries: [ - * "DK" - * ] - * }) - * .then(({ region }) => { - * console.log(region.id); - * }) - */ - create( - payload: AdminPostRegionsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/regions` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a region's details. - * @param {string} id - The region's ID. - * @param {AdminPostRegionsRegionReq} payload - The attributes to update in the region. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the region's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.update(regionId, { - * name: "Europe" - * }) - * .then(({ region }) => { - * console.log(region.id); - * }) - */ - update( - id: string, - payload: AdminPostRegionsRegionReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/regions/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a region. Associated resources, such as providers or currencies are not deleted. Associated tax rates are deleted. - * @param {string} id - The region's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.delete(regionId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/regions/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a region's details. - * @param {string} id - The region's ID. - * @param query - Query params - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the region's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.retrieve(regionId) - * .then(({ region }) => { - * console.log(region.id); - * }) - */ - retrieve( - id: string, - query?: AdminGetRegionsRegionParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/regions/${id}` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/regions/${id}?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of Regions. The regions can be filtered by fields such as `created_at` passed in the `query` parameter. The regions can also be paginated. - * @param {AdminGetRegionsParams} query - Filters and pagination configurations to apply on the retrieved regions. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of regions with pagination fields. - * - * @example - * To list regions: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.list() - * .then(({ regions, limit, offset, count }) => { - * console.log(regions.length); - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.list({ - * limit, - * offset - * }) - * .then(({ regions, limit, offset, count }) => { - * console.log(regions.length); - * }) - * ``` - */ - list( - query?: AdminGetRegionsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/regions` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/regions?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Add a country to the list of countries in a region. - * @param {string} id - The region's ID. - * @param {AdminPostRegionsRegionCountriesReq} payload - The country to add. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the region's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.addCountry(regionId, { - * country_code: "dk" - * }) - * .then(({ region }) => { - * console.log(region.id); - * }) - */ - addCountry( - id: string, - payload: AdminPostRegionsRegionCountriesReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/regions/${id}/countries` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a country from the list of countries in a region. The country will still be available in the system, and it can be used in other regions. - * @param {string} id - The region's ID. - * @param {string} country_code - The code of the country to delete from the region. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the region's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.deleteCountry(regionId, "dk") - * .then(({ region }) => { - * console.log(region.id); - * }) - */ - deleteCountry( - id: string, - country_code: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/regions/${id}/countries/${country_code}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Add a fulfillment provider to the list of fulfullment providers in a region. - * @param {string} id - The region's ID. - * @param {AdminPostRegionsRegionFulfillmentProvidersReq} payload - The fulfillment provider to add. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the region's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.addFulfillmentProvider(regionId, { - * provider_id: "manual" - * }) - * .then(({ region }) => { - * console.log(region.id); - * }) - */ - addFulfillmentProvider( - id: string, - payload: AdminPostRegionsRegionFulfillmentProvidersReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/regions/${id}/fulfillment-providers` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a fulfillment provider from a region. The fulfillment provider will still be available for usage in other regions. - * @param {string} id - The region's ID. - * @param {string} provider_id - The ID of the fulfillment provider to delete from the region. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the region's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.deleteFulfillmentProvider(regionId, "manual") - * .then(({ region }) => { - * console.log(region.id); - * }) - */ - deleteFulfillmentProvider( - id: string, - provider_id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/regions/${id}/fulfillment-providers/${provider_id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of fulfillment options available in a region. - * @param {string} id - The region's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of fulfillment options. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.retrieveFulfillmentOptions(regionId) - * .then(({ fulfillment_options }) => { - * console.log(fulfillment_options.length); - * }) - */ - retrieveFulfillmentOptions( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/regions/${id}/fulfillment-options` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Add a payment provider to the list of payment providers in a region. - * @param {string} id - The region's ID. - * @param {AdminPostRegionsRegionPaymentProvidersReq} payload - The payment provider to add. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the region's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.addPaymentProvider(regionId, { - * provider_id: "manual" - * }) - * .then(({ region }) => { - * console.log(region.id); - * }) - */ - addPaymentProvider( - id: string, - payload: AdminPostRegionsRegionPaymentProvidersReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/regions/${id}/payment-providers` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a payment provider from a region. The payment provider will still be available for usage in other regions. - * @param {string} id - The region's ID. - * @param {string} provider_id - The ID of the payment provider to delete from the region. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the region's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.deletePaymentProvider(regionId, "manual") - * .then(({ region }) => { - * console.log(region.id); - * }) - */ - deletePaymentProvider( - id: string, - provider_id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/regions/${id}/payment-providers/${provider_id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } -} - -export default AdminRegionsResource diff --git a/packages/medusa-js/src/resources/admin/reservations.ts b/packages/medusa-js/src/resources/admin/reservations.ts deleted file mode 100644 index 27fc674a4a..0000000000 --- a/packages/medusa-js/src/resources/admin/reservations.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { - AdminPostReservationsReq, - AdminPostReservationsReservationReq, - AdminReservationsDeleteRes, - AdminReservationsRes, - AdminGetReservationsParams, - AdminReservationsListRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Reservation API Routes](https://docs.medusajs.com/api/admin#reservations). To use these API Routes, make sure to install the - * [@medusajs/inventory](https://docs.medusajs.com/modules/multiwarehouse/install-modules#inventory-module) module in your Medusa backend. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. The methods - * are available in the JS Client under the `medusa.admin.reservations` property. - * - * Reservations, provided by the [Inventory Module](https://docs.medusajs.com/modules/multiwarehouse/inventory-module), are quantities of an item that are reserved, typically when an order is placed but not yet fulfilled. - * Reservations can be associated with any resources, but commonly with line items of an order. - * - * Related Guide: [How to manage item allocations in orders](https://docs.medusajs.com/modules/multiwarehouse/admin/manage-item-allocations-in-orders). - */ -class AdminReservationsResource extends BaseResource { - /** - * Retrieve a reservation's details. - * @param {string} id - The reservation's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the reservation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.reservations.retrieve(reservationId) - * .then(({ reservation }) => { - * console.log(reservation.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/reservations/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of reservations. The reservations can be filtered by fields such as `location_id` or `quantity` passed in the `query` parameter. The reservations can also be paginated. - * @param {AdminGetReservationsParams} query - Filters and pagination parameters to apply on the retrieved reservations. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of reservations with pagination fields. - * - * @example - * To list reservations: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.reservations.list() - * .then(({ reservations, count, limit, offset }) => { - * console.log(reservations.length) - * }) - * ``` - * - * To specify relations that should be retrieved within the reservations: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.reservations.list({ - * expand: "location" - * }) - * .then(({ reservations, count, limit, offset }) => { - * console.log(reservations.length) - * }) - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.reservations.list({ - * expand: "location", - * limit, - * offset - * }) - * .then(({ reservations, count, limit, offset }) => { - * console.log(reservations.length) - * }) - * ``` - */ - list( - query?: AdminGetReservationsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/reservations` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Create a reservation which can be associated with any resource, such as an order's line item. - * @param {AdminPostReservationsReq} payload - The reservation to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the reservation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.reservations.create({ - * line_item_id: "item_123", - * location_id: "loc_123", - * inventory_item_id: "iitem_123", - * quantity: 1 - * }) - * .then(({ reservation }) => { - * console.log(reservation.id); - * }); - */ - create( - payload: AdminPostReservationsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/reservations` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a reservation's details. - * @param {string} id - The ID of the reservation. - * @param {AdminPostReservationsReservationReq} payload - The attributes to update in the reservation. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the reservation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.reservations.update(reservationId, { - * quantity: 3 - * }) - * .then(({ reservation }) => { - * console.log(reservation.id); - * }); - */ - update( - id: string, - payload: AdminPostReservationsReservationReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/reservations/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a reservation. Associated resources, such as the line item, will not be deleted. - * @param {string} id - The ID of the reservation. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.reservations.delete(reservationId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }); - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/reservations/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } -} - -export default AdminReservationsResource diff --git a/packages/medusa-js/src/resources/admin/return-reasons.ts b/packages/medusa-js/src/resources/admin/return-reasons.ts deleted file mode 100644 index ea965209a2..0000000000 --- a/packages/medusa-js/src/resources/admin/return-reasons.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { - AdminPostReturnReasonsReq, - AdminReturnReasonsRes, - AdminReturnReasonsDeleteRes, - AdminReturnReasonsListRes, - AdminPostReturnReasonsReasonReq, -} from "@medusajs/medusa" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Return Reason API Routes](https://docs.medusajs.com/api/admin#return-reasons). All its method - * are available in the JS Client under the `medusa.admin.returnReasons` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Return reasons are key-value pairs that are used to specify why an order return is being created. - * Admins can manage available return reasons, and they can be used by both admins and customers when creating a return. - * - * Related Guide: [How to manage return reasons](https://docs.medusajs.com/modules/orders/admin/manage-returns#manage-return-reasons). - */ -class AdminReturnReasonsResource extends BaseResource { - /** - * Create a return reason. - * @param {AdminPostReturnReasonsReq} payload - The return reason to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the return reason's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returnReasons.create({ - * label: "Damaged", - * value: "damaged" - * }) - * .then(({ return_reason }) => { - * console.log(return_reason.id); - * }); - */ - create( - payload: AdminPostReturnReasonsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/return-reasons` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a return reason's details. - * @param {string} id - The return reason's ID. - * @param {AdminPostReturnReasonsReasonReq} payload - The attributes to update in the return reason. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the return reason's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returnReasons.update(returnReasonId, { - * label: "Damaged" - * }) - * .then(({ return_reason }) => { - * console.log(return_reason.id); - * }); - */ - update( - id: string, - payload: AdminPostReturnReasonsReasonReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/return-reasons/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a return reason. - * @param {string} id - The ID of the return reason. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returnReasons.delete(returnReasonId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }); - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/return-reasons/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a return reason's details. - * @param {string} id - The return reason's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the return reason's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returnReasons.retrieve(returnReasonId) - * .then(({ return_reason }) => { - * console.log(return_reason.id); - * }); - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/return-reasons/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of return reasons. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of return reasons. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returnReasons.list() - * .then(({ return_reasons }) => { - * console.log(return_reasons.length); - * }); - */ - list( - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/return-reasons` - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminReturnReasonsResource diff --git a/packages/medusa-js/src/resources/admin/returns.ts b/packages/medusa-js/src/resources/admin/returns.ts deleted file mode 100644 index 97c2d31cb3..0000000000 --- a/packages/medusa-js/src/resources/admin/returns.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { - AdminGetReturnsParams, - AdminPostReturnsReturnReceiveReq, - AdminReturnsCancelRes, - AdminReturnsListRes, - AdminReturnsRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Return API Routes](https://docs.medusajs.com/api/admin#returns). All its method - * are available in the JS Client under the `medusa.admin.returns` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A return can be created by a customer or an admin to return items in an order. - * Admins can manage these returns and change their state. - * - * Related Guide: [How to manage returns](https://docs.medusajs.com/modules/orders/admin/manage-returns). - */ -class AdminReturnsResource extends BaseResource { - /** - * Register a return as canceled. The return can be associated with an order, claim, or swap. - * @param {string} id - The return's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the order associated with the return. If the return is associated with a claim or a swap, then it'll be the order - * that the claim or swap belongs to. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returns.cancel(returnId) - * .then(({ order }) => { - * console.log(order.id); - * }); - */ - cancel( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/returns/${id}/cancel` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Mark a return as received. This also updates the status of associated order, claim, or swap accordingly. - * @param {string} id - The return's ID. - * @param {AdminPostReturnsReturnReceiveReq} payload - The received return. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the return's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returns.receive(returnId, { - * items: [ - * { - * item_id, - * quantity: 1 - * } - * ] - * }) - * .then((data) => { - * console.log(data.return.id); - * }); - */ - receive( - id: string, - payload: AdminPostReturnsReturnReceiveReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/returns/${id}/receive` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve a list of Returns. The returns can be paginated. - * @param {AdminGetReturnsParams} query - Paignation configurations to be applied on the retrieved returns. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of returns with pagination fields. - * - * @example - * To list returns: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returns.list() - * .then(({ returns, limit, offset, count }) => { - * console.log(returns.length) - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returns.list({ - * limit, - * offset - * }) - * .then(({ returns, limit, offset, count }) => { - * console.log(returns.length) - * }) - * ``` - */ - list( - query?: AdminGetReturnsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/returns/` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/returns?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminReturnsResource diff --git a/packages/medusa-js/src/resources/admin/sales-channels.ts b/packages/medusa-js/src/resources/admin/sales-channels.ts deleted file mode 100644 index a904744c2d..0000000000 --- a/packages/medusa-js/src/resources/admin/sales-channels.ts +++ /dev/null @@ -1,310 +0,0 @@ -import { - AdminDeleteSalesChannelsChannelProductsBatchReq, - AdminDeleteSalesChannelsChannelStockLocationsReq, - AdminGetSalesChannelsParams, - AdminPostSalesChannelsChannelProductsBatchReq, - AdminPostSalesChannelsChannelStockLocationsReq, - AdminPostSalesChannelsReq, - AdminPostSalesChannelsSalesChannelReq, - AdminSalesChannelsDeleteRes, - AdminSalesChannelsListRes, - AdminSalesChannelsRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Sales Channel API Routes](https://docs.medusajs.com/api/admin#sales-channels). All its method - * are available in the JS Client under the `medusa.admin.salesChannels` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A sales channel indicates a channel where products can be sold in. For example, a webshop or a mobile app. - * Admins can manage sales channels and the products available in them. - * - * Related Guide: [How to manage sales channels](https://docs.medusajs.com/modules/sales-channels/admin/manage). - */ -class AdminSalesChannelsResource extends BaseResource { - /** - * Retrieve a sales channel's details. - * @param {string} salesChannelId - The sales channel's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the sales channel's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.retrieve(salesChannelId) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id) - * }) - */ - retrieve( - salesChannelId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/sales-channels/${salesChannelId}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Create a sales channel. - * @param {AdminPostSalesChannelsReq} payload - The sales channel to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the sales channel's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.create({ - * name: "App", - * description: "Mobile app" - * }) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id); - * }) - */ - create( - payload: AdminPostSalesChannelsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/sales-channels` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a sales channel's details. - * @param {string} salesChannelId - The sales channel's ID. - * @param {AdminPostSalesChannelsSalesChannelReq} payload - The attributes to update in the sales channel. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the sales channel's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.update(salesChannelId, { - * name: "App" - * }) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id) - * }) - */ - update( - salesChannelId: string, - payload: AdminPostSalesChannelsSalesChannelReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/sales-channels/${salesChannelId}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve a list of sales channels. The sales channels can be filtered by fields such as `q` or `name` passed in the `query` parameter. The sales channels can also be sorted or paginated. - * @param {AdminGetSalesChannelsParams} query - Filters and pagination configurations applied on the retrieved sales channels. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of sales channels with pagination fields. - * - * @example - * To list sales channels: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.list() - * .then(({ sales_channels, limit, offset, count }) => { - * console.log(sales_channels.length) - * }) - * ``` - * - * To specify relations that should be retrieved within the sales channels: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.list({ - * expand: "locations" - * }) - * .then(({ sales_channels, limit, offset, count }) => { - * console.log(sales_channels.length) - * }) - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.list({ - * expand: "locations", - * limit, - * offset - * }) - * .then(({ sales_channels, limit, offset, count }) => { - * console.log(sales_channels.length) - * }) - * ``` - */ - list( - query?: AdminGetSalesChannelsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/sales-channels` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Delete a sales channel. Associated products, stock locations, and other resources are not deleted. - * @param {string} salesChannelId - The sales channel's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.delete(salesChannelId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - */ - delete( - salesChannelId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/sales-channels/${salesChannelId}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Remove a list of products from a sales channel. This doesn't delete the product. It only removes the association between the product and the sales channel. - * @param {string} salesChannelId - The sales channel's ID. - * @param {AdminDeleteSalesChannelsChannelProductsBatchReq} payload - The products to remove from the sales channel. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the sales channel's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.removeProducts(salesChannelId, { - * product_ids: [ - * { - * id: productId - * } - * ] - * }) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id) - * }) - */ - removeProducts( - salesChannelId: string, - payload: AdminDeleteSalesChannelsChannelProductsBatchReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/sales-channels/${salesChannelId}/products/batch` - return this.client.request("DELETE", path, payload, {}, customHeaders) - } - - /** - * Add a list of products to a sales channel. - * @param {string} salesChannelId - The sales channel's ID. - * @param {AdminPostSalesChannelsChannelProductsBatchReq} payload - The products to add to the sales channel. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the sales channel's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.addProducts(salesChannelId, { - * product_ids: [ - * { - * id: productId - * } - * ] - * }) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id) - * }) - */ - addProducts( - salesChannelId: string, - payload: AdminPostSalesChannelsChannelProductsBatchReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/sales-channels/${salesChannelId}/products/batch` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Associate a stock location with a sales channel. It requires the - * [@medusajs/stock-location](https://docs.medusajs.com/modules/multiwarehouse/install-modules#stock-location-module) module to be installed in - * your Medusa backend. - * @param {string} salesChannelId - The sales channel's ID. - * @param {AdminPostSalesChannelsChannelStockLocationsReq} payload - The stock location to associate with the sales channel. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the sales channel's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.addLocation(salesChannelId, { - * location_id: "loc_123" - * }) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id) - * }) - */ - addLocation( - salesChannelId: string, - payload: AdminPostSalesChannelsChannelStockLocationsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/sales-channels/${salesChannelId}/stock-locations` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Remove a stock location from a sales channel. This only removes the association between the stock location and the sales channel. It does not delete the stock location. - * @param {string} salesChannelId - The sales channel's ID. - * @param {AdminDeleteSalesChannelsChannelStockLocationsReq} payload - The stock location to remove from the sales channel. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the sales channel's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.removeLocation(salesChannelId, { - * location_id: "loc_id" - * }) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id); - * }) - */ - removeLocation( - salesChannelId: string, - payload: AdminDeleteSalesChannelsChannelStockLocationsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/sales-channels/${salesChannelId}/stock-locations` - return this.client.request("DELETE", path, payload, {}, customHeaders) - } -} - -export default AdminSalesChannelsResource diff --git a/packages/medusa-js/src/resources/admin/shipping-options.ts b/packages/medusa-js/src/resources/admin/shipping-options.ts deleted file mode 100644 index bdcf14419a..0000000000 --- a/packages/medusa-js/src/resources/admin/shipping-options.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { - AdminPostShippingOptionsReq, - AdminShippingOptionsRes, - AdminPostShippingOptionsOptionReq, - AdminShippingOptionsDeleteRes, - AdminShippingOptionsListRes, - AdminGetShippingOptionsParams, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Shipping Option API Routes](https://docs.medusajs.com/api/admin#shipping-options). All its method - * are available in the JS Client under the `medusa.admin.shippingOptions` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A shipping option is used to define the available shipping methods during checkout or when creating a return. - * Admins can create an unlimited number of shipping options, each associated with a shipping profile and fulfillment provider, among other resources. - * - * Related Guide: [Shipping Option architecture](https://docs.medusajs.com/modules/carts-and-checkout/shipping#shipping-option). - */ -class AdminShippingOptionsResource extends BaseResource { - /** - * Create a shipping option. - * @param {AdminPostShippingOptionsReq} payload - The shipping option to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the shipping option's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingOptions.create({ - * name: "PostFake", - * region_id, - * provider_id, - * data: { - * }, - * price_type: "flat_rate" - * }) - * .then(({ shipping_option }) => { - * console.log(shipping_option.id) - * }) - */ - create( - payload: AdminPostShippingOptionsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/shipping-options` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a shipping option's details. - * @param {string} id - The shipping option's ID. - * @param {AdminPostShippingOptionsOptionReq} payload - The attributes to update in the shipping option. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the shipping option's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingOptions.update(optionId, { - * name: "PostFake", - * requirements: [ - * { - * id, - * type: "max_subtotal", - * amount: 1000 - * } - * ] - * }) - * .then(({ shipping_option }) => { - * console.log(shipping_option.id) - * }) - */ - update( - id: string, - payload: AdminPostShippingOptionsOptionReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/shipping-options/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a shipping option. Once deleted, it can't be used when creating orders or returns. - * @param {string} id - The shipping option's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingOptions.delete(optionId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/shipping-options/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a shipping option's details. - * @param {string} id - The shipping option's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the shipping option's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingOptions.retrieve(optionId) - * .then(({ shipping_option }) => { - * console.log(shipping_option.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/shipping-options/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of shipping options. The shipping options can be filtered by fields such as `region_id` or `is_return` passed in the `query` parameter. - * @param {AdminGetShippingOptionsParams} query - Filters to apply on the retrieved shipping options. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of shipping options. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingOptions.list() - * .then(({ shipping_options, count }) => { - * console.log(shipping_options.length); - * }) - */ - list( - query?: AdminGetShippingOptionsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/shipping-options` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/shipping-options?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminShippingOptionsResource diff --git a/packages/medusa-js/src/resources/admin/shipping-profiles.ts b/packages/medusa-js/src/resources/admin/shipping-profiles.ts deleted file mode 100644 index 3ada7ce428..0000000000 --- a/packages/medusa-js/src/resources/admin/shipping-profiles.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { - AdminDeleteShippingProfileRes, - AdminPostShippingProfilesProfileReq, - AdminPostShippingProfilesReq, - AdminShippingProfilesListRes, - AdminShippingProfilesRes, -} from "@medusajs/medusa" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Shipping Profile API Routes](https://docs.medusajs.com/api/admin#shipping-profiles). All its method - * are available in the JS Client under the `medusa.admin.shippingProfiles` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A shipping profile is used to group products that can be shipped in the same manner. - * They are created by the admin and they're not associated with a fulfillment provider. - * - * Related Guide: [Shipping Profile architecture](https://docs.medusajs.com/modules/carts-and-checkout/shipping#shipping-profile). - */ -class AdminShippingProfilesResource extends BaseResource { - /** - * Create a shipping profile. - * @param {AdminPostShippingProfilesReq} payload - The shipping profile to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the shipping profile's details. - * - * @example - * import { ShippingProfileType } from "@medusajs/medusa" - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingProfiles.create({ - * name: "Large Products", - * type: ShippingProfileType.DEFAULT - * }) - * .then(({ shipping_profile }) => { - * console.log(shipping_profile.id); - * }) - */ - create( - payload: AdminPostShippingProfilesReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/shipping-profiles/` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a shipping profile's details. - * @param {string} id - The shipping profile's ID. - * @param {AdminPostShippingProfilesProfileReq} payload - The attributes to update in the shipping profile. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the shipping profile's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingProfiles.update(shippingProfileId, { - * name: 'Large Products' - * }) - * .then(({ shipping_profile }) => { - * console.log(shipping_profile.id); - * }) - */ - update( - id: string, - payload: AdminPostShippingProfilesProfileReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/shipping-profiles/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a shipping profile. Associated shipping options are deleted as well. - * @param {string} id - The shipping profile's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingProfiles.delete(profileId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/shipping-profiles/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a shipping profile's details. - * @param {string} id - The shipping profile's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the shipping profile's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingProfiles.retrieve(profileId) - * .then(({ shipping_profile }) => { - * console.log(shipping_profile.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/shipping-profiles/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of shipping profiles. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of shipping profiles. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingProfiles.list() - * .then(({ shipping_profiles }) => { - * console.log(shipping_profiles.length); - * }) - */ - list( - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/shipping-profiles/` - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminShippingProfilesResource diff --git a/packages/medusa-js/src/resources/admin/stock-locations.ts b/packages/medusa-js/src/resources/admin/stock-locations.ts deleted file mode 100644 index cdc94cfb9b..0000000000 --- a/packages/medusa-js/src/resources/admin/stock-locations.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { - AdminGetStockLocationsParams, - AdminStockLocationsRes, - AdminPostStockLocationsLocationReq, - AdminPostStockLocationsReq, - AdminStockLocationsListRes, - AdminStockLocationsDeleteRes, - AdminGetStockLocationsLocationParams, -} from "@medusajs/medusa" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" -import qs from "qs" - -/** - * This class is used to send requests to [Admin Stock Location API Routes](https://docs.medusajs.com/api/admin#stock-locations). To use these API Routes, make sure to install the - * [@medusajs/stock-location](https://docs.medusajs.com/modules/multiwarehouse/install-modules#stock-location-module) module in your Medusa backend. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. The methods - * are available in the JS Client under the `medusa.admin.stockLocations` property. - * - * A stock location, provided by the [Stock Location module](https://docs.medusajs.com/modules/multiwarehouse/stock-location-module), indicates a physical address that stock-kept items, such as physical products, can be stored in. - * An admin can create and manage available stock locations. - * - * Related Guide: [How to manage stock locations](https://docs.medusajs.com/modules/multiwarehouse/admin/manage-stock-locations). - */ -class AdminStockLocationsResource extends BaseResource { - /** - * Create a stock location. - * @param {AdminPostStockLocationsReq} payload - The stock location to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the stock location's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.stockLocations.create({ - * name: "Main Warehouse", - * }) - * .then(({ stock_location }) => { - * console.log(stock_location.id); - * }) - */ - create( - payload: AdminPostStockLocationsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/stock-locations` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve a stock location's details. - * @param {string} itemId - The stock location's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the stock location's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.stockLocations.retrieve(stockLocationId) - * .then(({ stock_location }) => { - * console.log(stock_location.id); - * }) - */ - retrieve( - itemId: string, - query?: AdminGetStockLocationsLocationParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/stock-locations/${itemId}` - - if (query) { - const queryString = qs.stringify(query) - path = `${path}?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Update a stock location's details. - * @param {string} stockLocationId - The stock location's ID. - * @param {AdminPostStockLocationsLocationReq} payload - The attributes to be updated in the stock location. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the stock location's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.stockLocations.update(stockLocationId, { - * name: 'Main Warehouse' - * }) - * .then(({ stock_location }) => { - * console.log(stock_location.id); - * }) - */ - update( - stockLocationId: string, - payload: AdminPostStockLocationsLocationReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/stock-locations/${stockLocationId}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a stock location. - * @param {string} id - The stock location's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.stockLocations.delete(stockLocationId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/stock-locations/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of stock locations. The stock locations can be filtered by fields such as `name` or `created_at` passed in the `query` parameter. - * The stock locations can also be sorted or paginated. - * @param {AdminGetStockLocationsParams} query - Filters and pagination configurations to apply on the retrieved stock locations. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of stock locations with pagination fields. - * - * @example - * To list stock locations: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.stockLocations.list() - * .then(({ stock_locations, limit, offset, count }) => { - * console.log(stock_locations.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the stock locations: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.stockLocations.list({ - * expand: "address" - * }) - * .then(({ stock_locations, limit, offset, count }) => { - * console.log(stock_locations.length); - * }) - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.stockLocations.list({ - * expand: "address", - * limit, - * offset - * }) - * .then(({ stock_locations, limit, offset, count }) => { - * console.log(stock_locations.length); - * }) - * ``` - */ - list( - query?: AdminGetStockLocationsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/stock-locations` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminStockLocationsResource diff --git a/packages/medusa-js/src/resources/admin/store.ts b/packages/medusa-js/src/resources/admin/store.ts deleted file mode 100644 index 2c0f554432..0000000000 --- a/packages/medusa-js/src/resources/admin/store.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { - AdminExtendedStoresRes, - AdminPaymentProvidersList, - AdminPostStoreReq, - AdminStoresRes, - AdminTaxProvidersList, -} from "@medusajs/medusa" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Store API Routes](https://docs.medusajs.com/api/admin#store). All its method - * are available in the JS Client under the `medusa.admin.store` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A store indicates the general configurations and details about the commerce store. By default, there's only one store in the Medusa backend. - * Admins can manage the store and its details or configurations. - */ -class AdminStoresResource extends BaseResource { - /** - * Update the store's details. - * @param {AdminPostStoreReq} payload - The attributes to update in the store. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the store's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.store.update({ - * name: "Medusa Store" - * }) - * .then(({ store }) => { - * console.log(store.id); - * }) - */ - update( - payload: AdminPostStoreReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/store/` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Add a currency code to the available currencies in a store. This doesn't create new currencies, as currencies are defined within the Medusa backend. - * To create a currency, you can [create a migration](https://docs.medusajs.com/development/entities/migrations/create) that inserts the currency into the database. - * @param {string} currency_code - The code of the currency to add to the store. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the store's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.store.addCurrency("eur") - * .then(({ store }) => { - * console.log(store.currencies); - * }) - */ - addCurrency( - currency_code: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/store/${currency_code}` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Delete a currency code from the available currencies in a store. This doesn't completely delete the currency and it can be added again later to the store. - * @param {string} currency_code - The code of the currency to delete from the store. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the store's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.store.deleteCurrency("eur") - * .then(({ store }) => { - * console.log(store.currencies); - * }) - */ - deleteCurrency( - currency_code: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/store/currencies/${currency_code}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve the store's details. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the store's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.store.retrieve() - * .then(({ store }) => { - * console.log(store.id); - * }) - */ - retrieve( - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/store/` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of available payment providers in a store. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of payment providers. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.store.listPaymentProviders() - * .then(({ payment_providers }) => { - * console.log(payment_providers.length); - * }) - */ - listPaymentProviders( - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/store/payment-providers` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of available tax providers in a store. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of tax providers. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.store.listTaxProviders() - * .then(({ tax_providers }) => { - * console.log(tax_providers.length); - * }) - */ - listTaxProviders( - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/store/tax-providers` - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminStoresResource diff --git a/packages/medusa-js/src/resources/admin/swaps.ts b/packages/medusa-js/src/resources/admin/swaps.ts deleted file mode 100644 index a5df455055..0000000000 --- a/packages/medusa-js/src/resources/admin/swaps.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { - AdminSwapsRes, - AdminSwapsListRes, - AdminGetSwapsParams, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Swap API Routes](https://docs.medusajs.com/api/admin#swaps). All its method - * are available in the JS Client under the `medusa.admin.swaps` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A swap is created by a customer or an admin to exchange an item with a new one. - * Creating a swap implicitely includes creating a return for the item being exchanged. - * - * Related Guide: [How to manage swaps](https://docs.medusajs.com/modules/orders/admin/manage-swaps) - */ -class AdminSwapsResource extends BaseResource { - /** - * Retrieve a swap's details. - * @param {string} id - The swap's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the swap's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.swaps.retrieve(swapId) - * .then(({ swap }) => { - * console.log(swap.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/swaps/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of swaps. The swaps can be paginated. - * @param {AdminGetSwapsParams} query - Pagination configurations to apply on the retrieved swaps. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of swaps with pagination fields. - * - * @example - * To list swaps: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.swaps.list() - * .then(({ swaps }) => { - * console.log(swaps.length); - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.swaps.list({ - * limit, - * offset - * }) - * .then(({ swaps }) => { - * console.log(swaps.length); - * }) - * ``` - */ - list( - query?: AdminGetSwapsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/swaps/` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/swaps?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminSwapsResource diff --git a/packages/medusa-js/src/resources/admin/tax-rates.ts b/packages/medusa-js/src/resources/admin/tax-rates.ts deleted file mode 100644 index 66d54126ef..0000000000 --- a/packages/medusa-js/src/resources/admin/tax-rates.ts +++ /dev/null @@ -1,466 +0,0 @@ -import { - AdminTaxRatesRes, - AdminTaxRatesListRes, - AdminTaxRatesDeleteRes, - AdminGetTaxRatesParams, - AdminGetTaxRatesTaxRateParams, - AdminDeleteTaxRatesTaxRateProductsReq, - AdminDeleteTaxRatesTaxRateProductsParams, - AdminDeleteTaxRatesTaxRateProductTypesReq, - AdminDeleteTaxRatesTaxRateProductTypesParams, - AdminDeleteTaxRatesTaxRateShippingOptionsReq, - AdminDeleteTaxRatesTaxRateShippingOptionsParams, - AdminPostTaxRatesReq, - AdminPostTaxRatesTaxRateReq, - AdminPostTaxRatesTaxRateProductsReq, - AdminPostTaxRatesTaxRateProductTypesReq, - AdminPostTaxRatesTaxRateShippingOptionsReq, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../../typings" -import BaseResource from "../base" -import { AdminPostTaxRatesTaxRateProductsParams } from "@medusajs/medusa" -import { AdminPostTaxRatesTaxRateShippingOptionsParams } from "@medusajs/medusa" -import { AdminPostTaxRatesParams } from "@medusajs/medusa" -import { AdminPostTaxRatesTaxRateParams } from "@medusajs/medusa" - -/** - * This class is used to send requests to [Admin Tax Rate API Routes](https://docs.medusajs.com/api/admin#tax-rates). All its method - * are available in the JS Client under the `medusa.admin.taxRates` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Each region has at least a default tax rate. Admins can create and manage additional tax rates that can be applied for certain conditions, such as for specific product types. - * - * Related Guide: [How to manage tax rates](https://docs.medusajs.com/modules/taxes/admin/manage-tax-rates). - */ -class AdminTaxRatesResource extends BaseResource { - /** - * Retrieve a tax rate's details. - * @param {string} id - The tax rate's ID. - * @param {AdminGetTaxRatesTaxRateParams} query - Configurations to apply on retrieved tax rates. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the tax rate's details. - * - * @example - * A simple example that retrieves a tax rate by its ID: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.retrieve(taxRateId) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - * ``` - * - * To specify relations that should be retrieved: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.retrieve(taxRateId, { - * expand: "shipping_options" - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - * ``` - */ - retrieve( - id: string, - query?: AdminGetTaxRatesTaxRateParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/tax-rates/${id}` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/tax-rates/${id}?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of tax rates. The tax rates can be filtered by fields such as `name` or `rate` passed in the `query` parameter. The tax rates can also be paginated. - * @param {AdminGetTaxRatesParams} query - Filters and pagination configurations applied to the retrieved tax rates. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of tax rates with pagination fields. - * - * @example - * To list tax rates: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.list() - * .then(({ tax_rates, limit, offset, count }) => { - * console.log(tax_rates.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the tax rates: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.list({ - * expand: ["shipping_options"] - * }) - * .then(({ tax_rates, limit, offset, count }) => { - * console.log(tax_rates.length); - * }) - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.list({ - * expand: ["shipping_options"], - * limit, - * offset - * }) - * .then(({ tax_rates, limit, offset, count }) => { - * console.log(tax_rates.length); - * }) - * ``` - */ - list( - query?: AdminGetTaxRatesParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/tax-rates` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/tax-rates?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Create a tax rate. - * @param {AdminPostTaxRatesReq} payload - The tax rate to create. - * @param {AdminPostTaxRatesParams} query - Configurations to apply on the retrieved tax rate. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the tax rate's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.create({ - * code: "TEST", - * name: "New Tax Rate", - * region_id - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - */ - create( - payload: AdminPostTaxRatesReq, - query?: AdminPostTaxRatesParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/tax-rates` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/tax-rates?${queryString}` - } - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a tax rate's details. - * @param {string} id - The tax rate's ID. - * @param {AdminPostTaxRatesTaxRateReq} payload - The attributes to update in the tax rate. - * @param {AdminPostTaxRatesTaxRateParams} query - Configurations to apply on the retrieved tax rate. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the tax rate's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.update(taxRateId, { - * name: "New Tax Rate" - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - */ - update( - id: string, - payload: AdminPostTaxRatesTaxRateReq, - query?: AdminPostTaxRatesTaxRateParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/tax-rates/${id}` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/tax-rates/${id}?${queryString}` - } - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Add products to a tax rate. - * @param {string} id - The tax rate's ID. - * @param {AdminPostTaxRatesTaxRateProductsReq} payload - The products to add to the tax rate. - * @param {AdminPostTaxRatesTaxRateProductsParams} query - Configurations to apply on the retrieved tax rate. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the tax rate's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.addProducts(taxRateId, { - * products: [ - * productId - * ] - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - */ - addProducts( - id: string, - payload: AdminPostTaxRatesTaxRateProductsReq, - query?: AdminPostTaxRatesTaxRateProductsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/tax-rates/${id}/products/batch` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/tax-rates/${id}/products/batch?${queryString}` - } - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Add product types to a tax rate. - * @param {string} id - The tax rate's ID. - * @param {AdminPostTaxRatesTaxRateProductTypesReq} payload - The product types to add to the tax rate. - * @param {AdminGetTaxRatesTaxRateParams} query - Configurations to apply on the retrieved tax rate. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the tax rate's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.addProductTypes(taxRateId, { - * product_types: [ - * productTypeId - * ] - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - */ - addProductTypes( - id: string, - payload: AdminPostTaxRatesTaxRateProductTypesReq, - query?: AdminGetTaxRatesTaxRateParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/tax-rates/${id}/product-types/batch` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/tax-rates/${id}/product-types/batch?${queryString}` - } - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Add shipping options to a tax rate. - * @param {string} id - The tax rate's ID. - * @param {AdminPostTaxRatesTaxRateShippingOptionsReq} payload - The shipping options to add to the tax rate. - * @param {AdminPostTaxRatesTaxRateShippingOptionsParams} query - Configurations to apply on the retrieved tax rate. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the tax rate's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.addShippingOptions(taxRateId, { - * shipping_options: [ - * shippingOptionId - * ] - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - */ - addShippingOptions( - id: string, - payload: AdminPostTaxRatesTaxRateShippingOptionsReq, - query?: AdminPostTaxRatesTaxRateShippingOptionsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/tax-rates/${id}/shipping-options/batch` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/tax-rates/${id}/shipping-options/batch?${queryString}` - } - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Remove products from a tax rate. This only removes the association between the products and the tax rate. It does not delete the products. - * @param {string} id - The tax rate's ID. - * @param {AdminDeleteTaxRatesTaxRateProductsReq} payload - The products to remove from the tax rate. - * @param {AdminGetTaxRatesTaxRateParams} query - Configurations to apply on the retrieved tax rate. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the tax rate's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.removeProducts(taxRateId, { - * products: [ - * productId - * ] - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - */ - removeProducts( - id: string, - payload: AdminDeleteTaxRatesTaxRateProductsReq, - query?: AdminDeleteTaxRatesTaxRateProductsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/tax-rates/${id}/products/batch` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/tax-rates/${id}/products/batch?${queryString}` - } - - return this.client.request("DELETE", path, payload, {}, customHeaders) - } - - /** - * Remove product types from a tax rate. This only removes the association between the product types and the tax rate. It does not delete the product types. - * @param {string} id - The tax rate's ID. - * @param {AdminDeleteTaxRatesTaxRateProductTypesReq} payload - The product types to remove from the tax rate. - * @param {AdminGetTaxRatesTaxRateParams} query - Configurations to apply on the retrieved tax rate. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the tax rate's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.removeProductTypes(taxRateId, { - * product_types: [ - * productTypeId - * ] - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - */ - removeProductTypes( - id: string, - payload: AdminDeleteTaxRatesTaxRateProductTypesReq, - query?: AdminDeleteTaxRatesTaxRateProductTypesParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/tax-rates/${id}/product-types/batch` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/tax-rates/${id}/product-types/batch?${queryString}` - } - - return this.client.request("DELETE", path, payload, {}, customHeaders) - } - - /** - * Remove shipping options from a tax rate. This only removes the association between the shipping options and the tax rate. It does not delete the shipping options. - * @param {string} id - The tax rate's ID. - * @param {AdminDeleteTaxRatesTaxRateShippingOptionsReq} payload - The shipping options to remove from the tax rate. - * @param {AdminGetTaxRatesTaxRateParams} query - Configurations to apply on the retrieved tax rate. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the tax rate's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.removeShippingOptions(taxRateId, { - * shipping_options: [ - * shippingOptionId - * ] - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - */ - removeShippingOptions( - id: string, - payload: AdminDeleteTaxRatesTaxRateShippingOptionsReq, - query?: AdminDeleteTaxRatesTaxRateShippingOptionsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/tax-rates/${id}/shipping-options/batch` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/tax-rates/${id}/shipping-options/batch?${queryString}` - } - - return this.client.request("DELETE", path, payload, {}, customHeaders) - } - - /** - * Delete a tax rate. Resources associated with the tax rate, such as products or product types, are not deleted. - * @param {string} id - The tax rate's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.delete(taxRateId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/tax-rates/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } -} - -export default AdminTaxRatesResource diff --git a/packages/medusa-js/src/resources/admin/uploads.ts b/packages/medusa-js/src/resources/admin/uploads.ts deleted file mode 100644 index 6e2517ac69..0000000000 --- a/packages/medusa-js/src/resources/admin/uploads.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { - AdminDeleteUploadsReq, - AdminDeleteUploadsRes, - AdminPostUploadsDownloadUrlReq, - AdminUploadsDownloadUrlRes, - AdminUploadsRes, -} from "@medusajs/medusa" -import { AdminCreateUploadPayload, ResponsePromise } from "../../typings" -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Upload API Routes](https://docs.medusajs.com/api/admin#uploads). All its method - * are available in the JS Client under the `medusa.admin.uploads` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * The methods in this class are used to upload any type of resources. For example, they can be used to upload CSV files that are used to import products into the store. - * - * Related Guide: [How to upload CSV file when importing a product](https://docs.medusajs.com/modules/products/admin/import-products#1-upload-csv-file). - */ -class AdminUploadsResource extends BaseResource { - /** - * @ignore - * @privateRemarks No need to include this in the generated documentation. - */ - private headers = { - "Content-Type": "multipart/form-data", - } - - /** - * Upload a file or multiple files to a public bucket or storage. The file upload is handled by the file service installed on the Medusa backend. - * @param {AdminCreateUploadPayload} file - The file(s) to upload. - * @returns {ResponsePromise} Resolves to the uploaded file details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.uploads.create(file) - * .then(({ uploads }) => { - * console.log(uploads.length); - * }) - */ - create(file: AdminCreateUploadPayload): ResponsePromise { - const path = `/admin/uploads` - - const payload = this._createPayload(file) - - return this.client.request("POST", path, payload, {}, this.headers) - } - - /** - * Upload a file to an ACL or a non-public bucket. The file upload is handled by the file service installed on the Medusa backend. - * @param {AdminCreateUploadPayload} file - The file to upload. - * @returns {ResponsePromise} Resolves to the uploaded file details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.uploads.createProtected(file) - * .then(({ uploads }) => { - * console.log(uploads.length); - * }) - */ - createProtected( - file: AdminCreateUploadPayload - ): ResponsePromise { - const path = `/admin/uploads/protected` - - const payload = this._createPayload(file) - - return this.client.request("POST", path, payload, {}, this.headers) - } - - /** - * Delete an uploaded file from storage. The file is deleted using the installed file service on the Medusa backend. - * @param {AdminDeleteUploadsReq} payload - The uploaded file to delete. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.uploads.delete({ - * file_key - * }) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - payload: AdminDeleteUploadsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/uploads` - - return this.client.request("DELETE", path, payload, {}, customHeaders) - } - - /** - * Create and retrieve a presigned or public download URL for a file. The URL creation is handled by the file service installed on the Medusa backend. - * @param {AdminPostUploadsDownloadUrlReq} payload - The uploaded file to get a presigned download URL for. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the download URL details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.uploads.getPresignedDownloadUrl({ - * file_key - * }) - * .then(({ download_url }) => { - * console.log(download_url); - * }) - */ - getPresignedDownloadUrl( - payload: AdminPostUploadsDownloadUrlReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/uploads/download-url` - - return this.client.request("POST", path, payload, {}, customHeaders) - } - - private _createPayload(file: AdminCreateUploadPayload) { - const payload = new FormData() - - if (Array.isArray(file)) { - file.forEach((f) => payload.append("files", f)) - } else { - payload.append("files", file) - } - - return payload - } -} - -export default AdminUploadsResource diff --git a/packages/medusa-js/src/resources/admin/users.ts b/packages/medusa-js/src/resources/admin/users.ts deleted file mode 100644 index 9918bb044a..0000000000 --- a/packages/medusa-js/src/resources/admin/users.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { - AdminDeleteUserRes, - AdminGetUsersParams, - AdminResetPasswordRequest, - AdminResetPasswordTokenRequest, - AdminUserRes, - AdminUsersListRes, -} from "@medusajs/medusa" -import qs from "qs" -import { - AdminCreateUserPayload, - AdminUpdateUserPayload, - ResponsePromise, -} from "../.." -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin User API Routes](https://docs.medusajs.com/api/admin#users). All its method - * are available in the JS Client under the `medusa.admin.users` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * A store can have more than one user, each having the same privileges. Admins can manage users, their passwords, and more. - * - * Related Guide: [How to manage users](https://docs.medusajs.com/modules/users/admin/manage-users). - */ -class AdminUsersResource extends BaseResource { - /** - * Generate a password token for an admin user with a given email. This also triggers the `user.password_reset` event. So, if you have a Notification Service installed - * that can handle this event, a notification, such as an email, will be sent to the user. The token is triggered as part of the `user.password_reset` event's payload. - * That token must be used later to reset the password using the {@link resetPassword} method. - * @param {AdminResetPasswordTokenRequest} payload - The user's reset details. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves when the token is generated successfully. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.sendResetPasswordToken({ - * email: "user@example.com" - * }) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // error occurred - * }) - */ - sendResetPasswordToken( - payload: AdminResetPasswordTokenRequest, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/users/password-token` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Reset the password of an admin user using their reset password token. You must generate a reset password token first for the user using the {@link sendResetPasswordToken} method, - * then use that token to reset the password in this method. - * @param {AdminResetPasswordRequest} payload - The reset details. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the user's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.resetPassword({ - * token: "supersecrettoken", - * password: "supersecret" - * }) - * .then(({ user }) => { - * console.log(user.id); - * }) - */ - resetPassword( - payload: AdminResetPasswordRequest, - customHeaders: Record = {} - ): ResponsePromise { - const path = `admin/users/reset-password` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve an admin user's details. - * @param {string} id - The user's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the user's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.retrieve(userId) - * .then(({ user }) => { - * console.log(user.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/users/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Create an admin user. The user has the same privileges as all admin users, and will be able to authenticate and perform admin functionalities right after creation. - * @param {AdminCreateUserPayload} payload - The user to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the user's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.create({ - * email: "user@example.com", - * password: "supersecret" - * }) - * .then(({ user }) => { - * console.log(user.id); - * }) - */ - create( - payload: AdminCreateUserPayload, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/users` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update an admin user's details. - * @param {string} id - The user's ID. - * @param {AdminUpdateUserPayload} payload - The attributes to update in the user. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the user's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.update(userId, { - * first_name: "Marcellus" - * }) - * .then(({ user }) => { - * console.log(user.id); - * }) - */ - update( - id: string, - payload: AdminUpdateUserPayload, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/users/${id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a user. Once deleted, the user will not be able to authenticate or perform admin functionalities. - * @param {string} id - The user's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the deletion operation's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.delete(userId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - */ - delete( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/users/${id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Retrieve all admin users. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of users. - * - * @example - * To list users: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.list() - * .then(({ users }) => { - * console.log(users.length); - * }) - * ``` - * - * By default, only the first `20` users are returned. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.list({ - * limit, - * offset - * }) - * .then(({ users, limit, offset, count }) => { - * console.log(users.length); - * }) - * ``` - */ - list( - query?: AdminGetUsersParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/users` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminUsersResource diff --git a/packages/medusa-js/src/resources/admin/variants.ts b/packages/medusa-js/src/resources/admin/variants.ts deleted file mode 100644 index 77a9d28af4..0000000000 --- a/packages/medusa-js/src/resources/admin/variants.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { - AdminGetVariantParams, - AdminGetVariantsParams, - AdminGetVariantsVariantInventoryRes, - AdminVariantsListRes, - AdminVariantsRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../.." -import BaseResource from "../base" - -/** - * This class is used to send requests to [Admin Product Variant API Routes](https://docs.medusajs.com/api/admin#product-variants). All its method - * are available in the JS Client under the `medusa.admin.variants` property. - * - * All methods in this class require {@link AdminAuthResource.createSession | user authentication}. - * - * Product variants are the actual salable item in your store. Each variant is a combination of the different option values available on the product. - * Product variants can be managed through {@link AdminProductsResource}. - * - * Related Guide: [How to manage product variants](https://docs.medusajs.com/modules/products/admin/manage-products#manage-product-variants). - */ -class AdminVariantsResource extends BaseResource { - /** - * Retrieve a list of product variants. The product variant can be filtered by fields such as `id` or `title` passed in the `query` parameter. The product variant can also be paginated. - * @param {AdminGetVariantsParams} query - Filters and pagination configurations to apply on the retrieved product variants. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of product variants with pagination fields. - * - * @example - * To list product variants: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.variants.list() - * .then(({ variants, limit, offset, count }) => { - * console.log(variants.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the product variants: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.variants.list({ - * expand: "options" - * }) - * .then(({ variants, limit, offset, count }) => { - * console.log(variants.length); - * }) - * ``` - * - * By default, only the first `100` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.variants.list({ - * expand: "options", - * limit, - * offset - * }) - * .then(({ variants, limit, offset, count }) => { - * console.log(variants.length); - * }) - * ``` - */ - list( - query?: AdminGetVariantsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/variants` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/variants?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a product variant's details. - * @param {string} id - The product variant's ID. - * @param {AdminGetVariantParams} query - Configurations to apply on the retrieved product variant. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product variant's details. - * - * @example - * A simple example that retrieves a product variant by its ID: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.variants.retrieve(variantId) - * .then(({ variant }) => { - * console.log(variant.id); - * }) - * ``` - * - * To specify relations that should be retrieved: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.variants.retrieve(variantId, { - * expand: "options" - * }) - * .then(({ variant }) => { - * console.log(variant.id); - * }) - * ``` - */ - retrieve( - id: string, - query?: AdminGetVariantParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/admin/variants/${id}` - - if (query) { - const queryString = qs.stringify(query) - path = `/admin/variants?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve the available inventory of a product variant. - * @param {string} variantId - The product variant's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the inventory details of the product variant. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.variants.getInventory(variantId) - * .then(({ variant }) => { - * console.log(variant.inventory, variant.sales_channel_availability) - * }) - */ - getInventory( - variantId: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/admin/variants/${variantId}/inventory` - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default AdminVariantsResource diff --git a/packages/medusa-js/src/resources/auth.ts b/packages/medusa-js/src/resources/auth.ts deleted file mode 100644 index 0f381e553c..0000000000 --- a/packages/medusa-js/src/resources/auth.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { - StoreGetAuthEmailRes, - StorePostAuthReq, - StoreAuthRes, - StoreBearerAuthRes, -} from "@medusajs/medusa" -import { ResponsePromise } from "../typings" -import JwtTokenManager from "../jwt-token-manager" -import BaseResource from "./base" - -/** - * This class is used to send requests to [Store Auth API Routes](https://docs.medusajs.com/api/store#auth). All its method - * are available in the JS Client under the `medusa.auth` property. - * - * The methods in this class allows you to manage a customer's session, such as login or log out. - * You can send authenticated requests for a customer either using the Cookie header or using the JWT Token. - * When you log the customer in using the {@link authenticate} method, the JS client will automatically attach the - * cookie header in all subsequent requests. - * - * Related Guide: [How to implement customer profiles in your storefront](https://docs.medusajs.com/modules/customers/storefront/implement-customer-profiles). - */ -class AuthResource extends BaseResource { - /** - * Authenticate a customer using their email and password. If the customer is authenticated successfully, the cookie is automatically attached to subsequent requests sent with the JS Client. - * @param {StorePostAuthReq} payload - The credentials of the customer to authenticate. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.auth.authenticate({ - * email: "user@example.com", - * password: "user@example.com" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - */ - authenticate(payload: StorePostAuthReq, customHeaders: Record = {}): ResponsePromise { - const path = `/store/auth` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Log out the customer and remove their authentication session. This method requires {@link AuthResource.authenticate | customer authentication}. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves when customer is logged out successfully. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.auth.deleteSession() - * .then(() => { - * // customer logged out successfully - * }) - */ - deleteSession(customHeaders: Record = {}): ResponsePromise { - const path = `/store/auth` - return this.client.request("DELETE", path, {}, {}, customHeaders) - } - - /** - * Retrieve the details of the logged-in customer. Can also be used to check if there is an authenticated customer. - * This method requires {@link AuthResource.authenticate | customer authentication}. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.auth.getSession() - * .then(({ customer }) => { - * console.log(customer.id); - * }) - */ - getSession(customHeaders: Record = {}): ResponsePromise { - const path = `/store/auth` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Check if the email is already used by another registered customer. Can be used to validate a new customer's email. - * @param {string} email - The email to check. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the result of the check. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.auth.exists("user@example.com") - */ - exists(email: string, customHeaders: Record = {}): ResponsePromise { - const path = `/store/auth/${email}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Authenticate the customer and retrieve a JWT token to use for subsequent authenticated requests. - * @param {AdminPostAuthReq} payload - The credentials of the customer to authenticate. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the access token of the customer, if they're authenticated successfully. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.auth.getToken({ - * email: 'user@example.com', - * password: 'supersecret' - * }) - * .then(({ access_token }) => { - * console.log(access_token); - * }) - */ - getToken( - payload: StorePostAuthReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/auth/token` - return this.client.request("POST", path, payload, {}, customHeaders) - .then((res) => { - JwtTokenManager.registerJwt(res.access_token, "store"); - - return res - }); - } -} - -export default AuthResource diff --git a/packages/medusa-js/src/resources/base.ts b/packages/medusa-js/src/resources/base.ts deleted file mode 100644 index 877bcf788d..0000000000 --- a/packages/medusa-js/src/resources/base.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Client from "../request" - -export default class BaseResource { - public client: Client - - constructor(client: Client) { - this.client = client - } -} diff --git a/packages/medusa-js/src/resources/carts.ts b/packages/medusa-js/src/resources/carts.ts deleted file mode 100644 index 4cd8766abf..0000000000 --- a/packages/medusa-js/src/resources/carts.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { - StoreCartsRes, - StoreCompleteCartRes, - StorePostCartReq, - StorePostCartsCartPaymentSessionReq, - StorePostCartsCartPaymentSessionUpdateReq, - StorePostCartsCartReq, - StorePostCartsCartShippingMethodReq, -} from "@medusajs/medusa" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" -import LineItemsResource from "./line-items" - -/** - * This class is used to send requests to [Store Cart API Routes](https://docs.medusajs.com/api/store#carts). All its method - * are available in the JS Client under the `medusa.carts` property. - * - * A cart is a virtual shopping bag that customers can use to add items they want to purchase. - * A cart is then used to checkout and place an order. - * - * Related Guide: [How to implement cart functionality in your storefront](https://docs.medusajs.com/modules/carts-and-checkout/storefront/implement-cart). - */ -class CartsResource extends BaseResource { - /** - * An instance of {@link LineItemsResource} used to send requests to line-item-related routes part of the [Store Cart API Routes](https://docs.medusajs.com/api/store#carts). - */ - public lineItems = new LineItemsResource(this.client) - - /** - * Add a shipping method to the cart. The validation of the `data` field is handled by the fulfillment provider of the chosen shipping option. - * @param {string} cart_id - The ID of the cart to add the shipping method to. - * @param {StorePostCartsCartShippingMethodReq} payload - The shipping method to add. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.addShippingMethod(cartId, { - * option_id - * }) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - addShippingMethod( - cart_id: string, - payload: StorePostCartsCartShippingMethodReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/carts/${cart_id}/shipping-methods` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Complete a cart and place an order or create a swap, based on the cart's type. This includes attempting to authorize the cart's payment. - * If authorizing the payment requires more action, the cart will not be completed and the order will not be placed or the swap will not be created. - * An idempotency key will be generated if none is provided in the header `Idempotency-Key` and added to - * the response. If an error occurs during cart completion or the request is interrupted for any reason, the cart completion can be retried by passing the idempotency - * key in the `Idempotency-Key` header. - * @param {string} cart_id - The ID of the cart to complete. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the completion details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.complete(cartId) - * .then(({ data, type }) => { - * console.log(data.id, type); - * }) - */ - complete( - cart_id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/carts/${cart_id}/complete` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Create a Cart. Although optional, specifying the cart's region and sales channel can affect the cart's pricing and - * the products that can be added to the cart respectively. So, make sure to set those early on and change them if necessary, such as when the customer changes their region. - * If a customer is logged in, make sure to pass its ID or email within the cart's details so that the cart is attached to the customer. - * @param {StorePostCartReq} payload - The cart to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the created cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.create() - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - create( - payload?: StorePostCartReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/carts` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create Payment Sessions for each of the available Payment Providers in the Cart's Region. If there's only one payment session created, - * it will be selected by default. The creation of the payment session uses the payment provider and may require sending requests to third-party services. - * @param {string} cart_id - The ID of the cart to create the payment sessions for. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.createPaymentSessions(cartId) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - createPaymentSessions( - cart_id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/carts/${cart_id}/payment-sessions` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Remove a Discount from a Cart. This only removes the application of the discount, and not completely deletes it. The totals will be re-calculated and the payment sessions - * will be refreshed after the removal. - * @param {string} cart_id - the ID of the cart to remove the discount from. - * @param {string} code - The code of the discount to remove from the cart. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.deleteDiscount(cartId, code) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - deleteDiscount( - cart_id: string, - code: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/carts/${cart_id}/discounts/${code}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Delete a Payment Session in a Cart. May be useful if a payment has failed. The totals will be recalculated. - * @param {string} cart_id - The ID of the cart to delete the payment session from. - * @param {string} provider_id - The ID of the payment provider that the session is associated with. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.deletePaymentSession(cartId, "manual") - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - deletePaymentSession( - cart_id: string, - provider_id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/carts/${cart_id}/payment-sessions/${provider_id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } - - /** - * Refresh a Payment Session to ensure that it is in sync with the Cart. This is usually not necessary, but is provided for edge cases. - * @param {string} cart_id - The ID of the cart to refresh its payment session. - * @param {string} provider_id - The ID of the payment provider that's associated with the payment session. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.refreshPaymentSession(cartId, "manual") - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - refreshPaymentSession( - cart_id: string, - provider_id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/carts/${cart_id}/payment-sessions/${provider_id}/refresh` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a Cart's details. This includes recalculating its totals. - * @param {string} cart_id - The cart's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.retrieve(cartId) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - retrieve( - cart_id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/carts/${cart_id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Select the Payment Session that will be used to complete the cart. This is typically used when the customer chooses their preferred payment method during checkout. - * The totals of the cart will be recalculated. - * @param {string} cart_id - The cart's ID. - * @param {StorePostCartsCartPaymentSessionReq} payload - The associated payment provider. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.setPaymentSession(cartId, { - * provider_id: "manual" - * }) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - setPaymentSession( - cart_id: string, - payload: StorePostCartsCartPaymentSessionReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/carts/${cart_id}/payment-session` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a Cart's details. If the cart has payment sessions and the region was not changed, the payment sessions are updated. The cart's totals are also recalculated. - * @param {string} cart_id - The cart's ID. - * @param {StorePostCartsCartReq} payload - The attributes to update in the cart. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.update(cartId, { - * email: "user@example.com" - * }) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - update( - cart_id: string, - payload: StorePostCartsCartReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/carts/${cart_id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a Payment Session with additional data. This can be useful depending on the payment provider used. - * All payment sessions are updated and cart totals are recalculated afterwards. - * @param {string} cart_id - The cart's ID. - * @param {string} provider_id - The ID of the payment provider that the payment session is associated with. - * @param {StorePostCartsCartPaymentSessionUpdateReq} payload - The attributes to update in the payment session. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.updatePaymentSession(cartId, "manual", { - * data: { - * - * } - * }) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - updatePaymentSession( - cart_id: string, - provider_id: string, - payload: StorePostCartsCartPaymentSessionUpdateReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/carts/${cart_id}/payment-sessions/${provider_id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } -} - -export default CartsResource diff --git a/packages/medusa-js/src/resources/collections.ts b/packages/medusa-js/src/resources/collections.ts deleted file mode 100644 index f4fbcc9705..0000000000 --- a/packages/medusa-js/src/resources/collections.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { - StoreCollectionsRes, - StoreCollectionsListRes, - StoreGetCollectionsParams, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" - -/** - * This class is used to send requests to [Store Product Collection API Routes](https://docs.medusajs.com/api/store#product-collections). All its method - * are available in the JS Client under the `medusa.collections` property. - * - * A product collection is used to organize products for different purposes such as marketing or discount purposes. For example, you can create a Summer Collection. - * Using the methods in this class, you can list or retrieve a collection's details and products. - */ -class CollectionsResource extends BaseResource { - /** - * Retrieve a product collection's details. - * @param {string} id - The ID of the product collection. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the collection's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.collections.retrieve(collectionId) - * .then(({ collection }) => { - * console.log(collection.id); - * }) - */ - retrieve(id: string, customHeaders: Record = {}): ResponsePromise { - const path = `/store/collections/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of product collections. The product collections can be filtered by fields such as `handle` or `created_at` passed in the `query` parameter. - * The product collections can also be paginated. - * @param {StoreGetCollectionsParams} query - Filters and pagination configurations to apply on the retrieved product collections. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of product collections with pagination fields. - * - * @example - * To list product collections: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.collections.list() - * .then(({ collections, limit, offset, count }) => { - * console.log(collections.length); - * }) - * ``` - * - * By default, only the first `10` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.collections.list({ - * limit, - * offset - * }) - * .then(({ collections, limit, offset, count }) => { - * console.log(collections.length); - * }) - * ``` - */ - list( - query?: StoreGetCollectionsParams, - customHeaders: Record = {}): ResponsePromise { - let path = `/store/collections` - - if (query) { - const queryString = qs.stringify(query) - path = `/store/collections?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default CollectionsResource diff --git a/packages/medusa-js/src/resources/customers.ts b/packages/medusa-js/src/resources/customers.ts deleted file mode 100644 index ce5e8ba8db..0000000000 --- a/packages/medusa-js/src/resources/customers.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { - StoreCustomersListOrdersRes, - StoreCustomersRes, - StoreGetCustomersCustomerOrdersParams, - StorePostCustomersCustomerPasswordTokenReq, - StorePostCustomersCustomerReq, - StorePostCustomersReq, - StorePostCustomersResetPasswordReq, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../typings" -import AddressesResource from "./addresses" -import BaseResource from "./base" -import PaymentMethodsResource from "./payment-methods" - -/** - * This class is used to send requests to [Store Customer API Routes](https://docs.medusajs.com/api/store#customers_postcustomers). All its method - * are available in the JS Client under the `medusa.customers` property. - * - * A customer can register and manage their information such as addresses, orders, payment methods, and more. - * - * Related Guide: [How to implement customer profiles in your storefront](https://docs.medusajs.com/modules/customers/storefront/implement-customer-profiles). - */ -class CustomerResource extends BaseResource { - /** - * An instance of {@link PaymentMethodsResource} used to send requests to payment-related routes part of the [Store Customer API Routes](https://docs.medusajs.com/api/store#customers_postcustomers). - */ - public paymentMethods = new PaymentMethodsResource(this.client) - /** - * An instance of {@link AddressesResource} used to send requests to address-related routes part of the [Store Customer API Routes](https://docs.medusajs.com/api/store#customers_postcustomers). - */ - public addresses = new AddressesResource(this.client) - - /** - * Register a new customer. This will also automatically authenticate the customer and set their login session in the response Cookie header. - * Subsequent requests sent with the JS client are sent with the Cookie session automatically. - * @param {StorePostCustomersReq} payload - The details of the customer to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns { ResponsePromise} Resolves to the created customer's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.customers.create({ - * first_name: "Alec", - * last_name: "Reynolds", - * email: "user@example.com", - * password: "supersecret" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - */ - create( - payload: StorePostCustomersReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/customers` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve the logged-in customer's details. This method requires {@link AuthResource.authenticate | customer authentication}. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the logged-in customer's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.retrieve() - * .then(({ customer }) => { - * console.log(customer.id); - * }) - */ - retrieve( - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/customers/me` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Update the logged-in customer's details. This method requires {@link AuthResource.authenticate | customer authentication}. - * @param {StorePostCustomersCustomerReq} payload - The attributes to update in the logged-in customer. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the logged-in customer's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.update({ - * first_name: "Laury" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - */ - update( - payload: StorePostCustomersCustomerReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/customers/me` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve a list of the logged-in customer's orders. The orders can be filtered by fields such as `status` or `fulfillment_status`. The orders can also be paginated. - * This method requires {@link AuthResource.authenticate | customer authentication}. - * @param {StoreGetCustomersCustomerOrdersParams} params - Filters and pagination configurations to apply on the retrieved orders. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of orders with pagination fields. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.listOrders() - * .then(({ orders, limit, offset, count }) => { - * console.log(orders); - * }) - */ - listOrders( - params?: StoreGetCustomersCustomerOrdersParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/store/customers/me/orders` - if (params) { - const query = qs.stringify(params) - if (query) { - path += `?${query}` - } - } - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Reset a customer's password using a password token created by a previous request using the {@link generatePasswordToken} method. If the password token expired, - * you must create a new one. - * @param {StorePostCustomersResetPasswordReq} payload - The necessary details to reset the password. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the customer's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.customers.resetPassword({ - * email: "user@example.com", - * password: "supersecret", - * token: "supersecrettoken" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - */ - resetPassword( - payload: StorePostCustomersResetPasswordReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/customers/password-reset` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create a reset password token to be used when sending a request with the {@link resetPassword} method. This emits the event `customer.password_reset`. If a notification provider is - * installed in the Medusa backend and is configured to handle this event, a notification to the customer, such as an email, may be sent with reset instructions. - * @param {StorePostCustomersCustomerPasswordTokenReq} payload - The necessary details to create the reset password token. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves when reset password token is created successfully. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.customers.generatePasswordToken({ - * email: "user@example.com" - * }) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // failed - * }) - */ - generatePasswordToken( - payload: StorePostCustomersCustomerPasswordTokenReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/customers/password-token` - return this.client.request("POST", path, payload, {}, customHeaders) - } -} - -export default CustomerResource diff --git a/packages/medusa-js/src/resources/gift-cards.ts b/packages/medusa-js/src/resources/gift-cards.ts deleted file mode 100644 index 37a3b3f279..0000000000 --- a/packages/medusa-js/src/resources/gift-cards.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { StoreGiftCardsRes } from "@medusajs/medusa" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" - -/** - * This class is used to send requests to [Store Gift Card API Routes](https://docs.medusajs.com/api/store#gift-cards). All its method - * are available in the JS Client under the `medusa.giftCards` property. - * - * Customers can use gift cards during checkout to deduct the gift card's balance from the checkout total. - * The methods in this class allow retrieving a gift card's details by its code. A gift card can be applied to a cart using {@link CartsResource}. - * - * Related Guide: [How to use gift cards in a storefront](https://docs.medusajs.com/modules/gift-cards/storefront/use-gift-cards). - */ -class GiftCardsResource extends BaseResource { - /** - * Retrieve a Gift Card's details by its associated unique code. - * @param {string} code - The code of the gift card. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the gift card. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.giftCards.retrieve(code) - * .then(({ gift_card }) => { - * console.log(gift_card.id); - * }) - */ - retrieve(code: string, customHeaders: Record = {}): ResponsePromise { - const path = `/store/gift-cards/${code}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default GiftCardsResource diff --git a/packages/medusa-js/src/resources/index.ts b/packages/medusa-js/src/resources/index.ts deleted file mode 100644 index a6ab34acc3..0000000000 --- a/packages/medusa-js/src/resources/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import AddressesResource from "./addresses" -import AuthResource from "./auth" -import BaseResource from "./base" -import CartsResource from "./carts" -import CollectionsResource from "./collections" -import CustomersResource from "./customers" -import GiftCardsResource from "./gift-cards" -import LineItemsResource from "./line-items" -import OrderEditsResource from "./order-edits" -import OrdersResource from "./orders" -import PaymentCollectionsResource from "./payment-collections" -import PaymentMethodsResource from "./payment-methods" -import ProductCategoriesResource from "./product-categories" -import ProductTagsResource from "./product-tags" -import ProductTypesResource from "./product-types" -import ProductVariantsResource from "./product-variants" -import ProductsResource from "./products" -import RegionsResource from "./regions" -import ReturnReasonsResource from "./return-reasons" -import ReturnsResource from "./returns" -import ShippingOptionsResource from "./shipping-options" -import SwapsResource from "./swaps" - -export * from "./admin" -export { - AddressesResource, - AuthResource, - BaseResource, - CartsResource, - CollectionsResource, - CustomersResource, - GiftCardsResource, - LineItemsResource, - OrderEditsResource, - OrdersResource, - PaymentCollectionsResource, - PaymentMethodsResource, - ProductCategoriesResource, - ProductTagsResource, - ProductTypesResource, ProductVariantsResource, ProductsResource, - RegionsResource, - ReturnReasonsResource, - ReturnsResource, - ShippingOptionsResource, - SwapsResource -} - diff --git a/packages/medusa-js/src/resources/line-items.ts b/packages/medusa-js/src/resources/line-items.ts deleted file mode 100644 index afc639554c..0000000000 --- a/packages/medusa-js/src/resources/line-items.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { - StoreCartsRes, - StorePostCartsCartLineItemsItemReq, - StorePostCartsCartLineItemsReq, -} from "@medusajs/medusa" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" - -/** - * This class is used to send requests to Line Item API Routes part of the [Store Cart API Routes](https://docs.medusajs.com/api/store#carts). All its method - * are available in the JS Client under the `medusa.carts.lineItems` property. - */ -class LineItemsResource extends BaseResource { - /** - * Generate a Line Item with a given Product Variant and adds it to the Cart - * @param {string} cart_id - The cart's ID. - * @param {StorePostCartsCartLineItemsReq} payload - The line item to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the associated cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.lineItems.create(cart_id, { - * variant_id, - * quantity: 1 - * }) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - create( - cart_id: string, - payload: StorePostCartsCartLineItemsReq, - customHeaders: Record = {}): ResponsePromise { - const path = `/store/carts/${cart_id}/line-items` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Update a line item's data. - * @param {string} cart_id - The ID of the line item's cart. - * @param {string} line_id - The ID of the line item to update. - * @param {StorePostCartsCartLineItemsItemReq} payload - The data to update in the line item. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the associated cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.lineItems.update(cartId, lineId, { - * quantity: 1 - * }) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - update( - cart_id: string, - line_id: string, - payload: StorePostCartsCartLineItemsItemReq, - customHeaders: Record = {}): ResponsePromise { - const path = `/store/carts/${cart_id}/line-items/${line_id}` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Delete a line item from a cart. The payment sessions will be updated and the totals will be recalculated. - * @param {string} cart_id - The ID of the line item's cart. - * @param {string} line_id - The ID of the line item to delete. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the associated cart's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.lineItems.delete(cartId, lineId) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - */ - delete(cart_id: string, line_id: string, customHeaders: Record = {}): ResponsePromise { - const path = `/store/carts/${cart_id}/line-items/${line_id}` - return this.client.request("DELETE", path, undefined, {}, customHeaders) - } -} - -export default LineItemsResource diff --git a/packages/medusa-js/src/resources/order-edits.ts b/packages/medusa-js/src/resources/order-edits.ts deleted file mode 100644 index cca61fbc6e..0000000000 --- a/packages/medusa-js/src/resources/order-edits.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { - StoreOrderEditsRes, - StorePostOrderEditsOrderEditDecline, -} from "@medusajs/medusa" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" - -/** - * This class is used to send requests to [Store Order Edits API Routes](https://docs.medusajs.com/api/store#order-edits). All its method - * are available in the JS Client under the `medusa.orderEdits` property. - * - * Order edits are changes made to items in an order such as adding, updating their quantity, or deleting them. Order edits are created by the admin. - * A customer can review order edit requests created by an admin and confirm or decline them. - * - * Related Guide: [How to handle order edits in a storefront](https://docs.medusajs.com/modules/orders/storefront/handle-order-edits). - */ -class OrderEditsResource extends BaseResource { - /** - * Retrieve an Order Edit's details. - * @param {string} id - The ID of the order edit. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order edit's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.orderEdits.retrieve(orderEditId) - * .then(({ order_edit }) => { - * console.log(order_edit.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/order-edits/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Decline an Order Edit. The changes are not reflected on the original order. - * @param {string} id - The ID of the order edit. - * @param {StorePostOrderEditsOrderEditDecline} payload - The decline details. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order edit's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.orderEdits.decline(orderEditId) - * .then(({ order_edit }) => { - * console.log(order_edit.id); - * }) - */ - decline( - id: string, - payload: StorePostOrderEditsOrderEditDecline, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/order-edits/${id}/decline` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Complete and confirm an Order Edit and reflect its changes on the original order. Any additional payment required must be authorized first using the {@link PaymentCollectionsResource} routes. - * @param {string} id - The ID of the order edit. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the order edit's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.orderEdits.complete(orderEditId) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - */ - complete(id: string, customHeaders: Record = {}): ResponsePromise { - const path = `/store/order-edits/${id}/complete` - return this.client.request("POST", path, undefined, {}, customHeaders) - } -} - -export default OrderEditsResource diff --git a/packages/medusa-js/src/resources/orders.ts b/packages/medusa-js/src/resources/orders.ts deleted file mode 100644 index 475379349e..0000000000 --- a/packages/medusa-js/src/resources/orders.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { - StoreGetOrdersParams, - StoreOrdersRes, - StorePostCustomersCustomerAcceptClaimReq, - StorePostCustomersCustomerOrderClaimReq, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" - -/** - * This class is used to send requests to [Store Order API Routes](https://docs.medusajs.com/api/store#orders). All its method - * are available in the JS Client under the `medusa.orders` property. - * - * Orders are purchases made by customers, typically through a storefront. - * Orders are placed and created using {@link CartsResource}. The methods in this class allow retrieving and claiming orders. - * - * Related Guide: [How to retrieve order details in a storefront](https://docs.medusajs.com/modules/orders/storefront/retrieve-order-details). - */ -class OrdersResource extends BaseResource { - /** - * Retrieve an Order's details. - * @param {string} id - The order's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the order. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.orders.retrieve(orderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/orders/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve an order's details by the ID of the cart that was used to create the order. - * @param {string} cart_id - The cart's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the order. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.orders.retrieveByCartId(cartId) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - retrieveByCartId( - cart_id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/orders/cart/${cart_id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Look up an order using filters. If the filters don't narrow down the results to a single order, a `404` response is returned with no orders. - * @param {StoreGetOrdersParams} payload - Filters used to retrieve the order. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the details of the order. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.orders.lookupOrder({ - * display_id: 1, - * email: "user@example.com" - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - */ - lookupOrder( - payload: StoreGetOrdersParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/store/orders?` - - const queryString = qs.stringify(payload) - path = `/store/orders?${queryString}` - - return this.client.request("GET", path, payload, {}, customHeaders) - } - - /** - * Allow the logged-in customer to claim ownership of one or more orders. This generates a token that can be used later on to verify the claim using the {@link confirmRequest} method. - * This also emits the event `order-update-token.created`. So, if you have a notification provider installed that handles this event and sends the customer a notification, such as an email, - * the customer should receive instructions on how to finalize their claim ownership. - * @param {StorePostCustomersCustomerOrderClaimReq} payload - The orders to claim. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves when the request is created successfully. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.orders.requestCustomerOrders({ - * order_ids, - * }) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // an error occurred - * }) - */ - requestCustomerOrders( - payload: StorePostCustomersCustomerOrderClaimReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/orders/batch/customer/token` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Verify the claim order token provided to the customer when they request ownership of an order. - * @param {StorePostCustomersCustomerAcceptClaimReq} payload - The claim order to verify. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves when the claim order is verified successfully. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.orders.confirmRequest( - * token, - * ) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // an error occurred - * }) - */ - confirmRequest( - payload: StorePostCustomersCustomerAcceptClaimReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/orders/customer/confirm` - return this.client.request("POST", path, payload, {}, customHeaders) - } -} - -export default OrdersResource diff --git a/packages/medusa-js/src/resources/payment-collections.ts b/packages/medusa-js/src/resources/payment-collections.ts deleted file mode 100644 index a831860c82..0000000000 --- a/packages/medusa-js/src/resources/payment-collections.ts +++ /dev/null @@ -1,231 +0,0 @@ -import { - StoreGetPaymentCollectionsParams, - StorePaymentCollectionSessionsReq, - StorePaymentCollectionsRes, - StorePaymentCollectionsSessionRes, - StorePostPaymentCollectionsBatchSessionsAuthorizeReq, - StorePostPaymentCollectionsBatchSessionsReq, -} from "@medusajs/medusa" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" -import qs from "qs" - -/** - * This class is used to send requests to [Store Payment Collection API Routes](https://docs.medusajs.com/api/store#payment-collections). All its method - * are available in the JS Client under the `medusa.paymentCollections` property. - * - * A payment collection is useful for managing additional payments, such as for Order Edits, or installment payments. - */ -class PaymentCollectionsResource extends BaseResource { - - /** - * Retrieve a Payment Collection's details. - * @param {string} id - The ID of the payment collection. - * @param {StoreGetPaymentCollectionsParams} query - Configurations to apply on the retrieved payment collection. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the payment collection's details. - * - * @example - * A simple example that retrieves a payment collection by its ID: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.paymentCollections.retrieve(paymentCollectionId) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id) - * }) - * ``` - * - * To specify relations that should be retrieved: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.paymentCollections.retrieve(paymentCollectionId, { - * expand: "region" - * }) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id) - * }) - * ``` - */ - retrieve( - id: string, - query?: StoreGetPaymentCollectionsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/store/payment-collections/${id}` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Authorize a Payment Session of a Payment Collection. - * @param {string} id - The ID of the payment collection. - * @param {string} session_id - The ID of the payment session. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the payment collection's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.paymentCollections.authorize(paymentId, sessionId) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id); - * }) - */ - authorizePaymentSession( - id: string, - session_id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/payment-collections/${id}/sessions/${session_id}/authorize` - return this.client.request("POST", path, undefined, {}, customHeaders) - } - - /** - * Authorize the Payment Sessions of a Payment Collection. - * @param {string} id - The ID of the payment collection. - * @param {StorePostPaymentCollectionsBatchSessionsAuthorizeReq} payload - The list of payment session IDs to authorize. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the payment collection's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.paymentCollections.authorizePaymentSessionsBatch(paymentCollectionId, { - * session_ids: ["ps_123456"] - * }) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id); - * }) - */ - authorizePaymentSessionsBatch( - id: string, - payload: StorePostPaymentCollectionsBatchSessionsAuthorizeReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/payment-collections/${id}/sessions/batch/authorize` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create, update, or delete a list of payment sessions of a Payment Collections. If a payment session is not provided in the `sessions` array, it's deleted. - * @param {string} id - The ID of the payment collection. - * @param {StorePostPaymentCollectionsBatchSessionsReq} payload - The attributes of each session to update. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the payment collection's details. - * - * @example - * To add two new payment sessions: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * - * // Total amount = 10000 - * medusa.paymentCollections.managePaymentSessionsBatch(paymentId, { - * sessions: [ - * { - * provider_id: "stripe", - * amount: 5000, - * }, - * { - * provider_id: "manual", - * amount: 5000, - * }, - * ] - * }) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id); - * }) - * ``` - * - * To update a payment session and another one by not including it in the payload: - * - * ```ts - * medusa.paymentCollections.managePaymentSessionsBatch(paymentId, { - * sessions: [ - * { - * provider_id: "stripe", - * amount: 10000, - * session_id: "ps_123456" - * }, - * ] - * }) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id); - * }) - * ``` - */ - managePaymentSessionsBatch( - id: string, - payload: StorePostPaymentCollectionsBatchSessionsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/payment-collections/${id}/sessions/batch` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Create a Payment Session for a payment provider in a Payment Collection. - * @param {string} id - The ID of the payment collection. - * @param {StorePaymentCollectionSessionsReq} payload - The payment session to create. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the payment collection's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.paymentCollections.managePaymentSession(payment_id, { provider_id: "stripe" }) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id); - * }) - */ - managePaymentSession( - id: string, - payload: StorePaymentCollectionSessionsReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/payment-collections/${id}/sessions` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Refresh a Payment Session's data to ensure that it is in sync with the Payment Collection. - * @param {string} id - The ID of the payment collection. - * @param {string} session_id - The ID of the payment session. - * @param customHeaders - * @returns {ResponsePromise} Resolves to the refreshed payment session's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.paymentCollections.refreshPaymentSession(paymentCollectionId, sessionId) - * .then(({ payment_session }) => { - * console.log(payment_session.status); - * }) - */ - refreshPaymentSession( - id: string, - session_id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/payment-collections/${id}/sessions/${session_id}` - return this.client.request("POST", path, undefined, {}, customHeaders) - } -} - -export default PaymentCollectionsResource diff --git a/packages/medusa-js/src/resources/payment-methods.ts b/packages/medusa-js/src/resources/payment-methods.ts deleted file mode 100644 index 0af972903c..0000000000 --- a/packages/medusa-js/src/resources/payment-methods.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { StoreCustomersListPaymentMethodsRes } from "@medusajs/medusa" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" - -/** - * This class is used to send requests to Payment Method API Routes part of the [Store Customer API Routes](https://docs.medusajs.com/api/store#customers_postcustomers). All its method - * are available in the JS Client under the `medusa.customers.paymentMethods` property. - * - * All methods in this class require {@link AuthResource.authenticate | customer authentication}. - */ -class PaymentMethodsResource extends BaseResource { - /** - * Retrieve the logged-in customer's saved payment methods. This method only works with payment providers created with the deprecated Payment Service interface. - * The payment methods are saved using the Payment Service's third-party service, and not on the Medusa backend. So, they're retrieved from the third-party service. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {StoreCustomersListPaymentMethodsRes} Resolves to the customer's payment methods. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.paymentMethods.list() - * .then(({ payment_methods }) => { - * console.log(payment_methods.length); - * }) - */ - list( - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/customers/me/payment-methods` - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default PaymentMethodsResource diff --git a/packages/medusa-js/src/resources/product-categories.ts b/packages/medusa-js/src/resources/product-categories.ts deleted file mode 100644 index d09cfbe0a9..0000000000 --- a/packages/medusa-js/src/resources/product-categories.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { - StoreGetProductCategoriesParams, - StoreGetProductCategoriesRes, - StoreGetProductCategoriesCategoryParams, - StoreGetProductCategoriesCategoryRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" - -/** - * This class is used to send requests to [Store Product Category API Routes](https://docs.medusajs.com/api/store#product-categories_getproductcategories). All its method - * are available in the JS Client under the `medusa.productCategories` property. - * - * Products can be categoriezed into categories. A product can be associated more than one category. - * Using the methods in this class, you can list or retrieve a category's details and products. - * - * Related Guide: [How to use product categories in a storefront](https://docs.medusajs.com/modules/products/storefront/use-categories). - * - * @featureFlag product_categories - */ -class ProductCategoriesResource extends BaseResource { - /** - * Retrieve a Product Category's details. - * @param {string} id - The ID of the product category. - * @param {StoreGetProductCategoriesCategoryParams} query - Configurations to apply on the retrieved product categories. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product category's details. - * - * @example - * A simple example that retrieves a product category by its ID: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.productCategories.retrieve(productCategoryId) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - * ``` - * - * To specify relations that should be retrieved: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.productCategories.retrieve(productCategoryId, { - * expand: "products" - * }) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - * ``` - */ - retrieve( - id: string, - query?: StoreGetProductCategoriesCategoryParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/store/product-categories/${id}` - - if (query) { - const queryString = qs.stringify(query) - path = `${path}?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of product categories. The product categories can be filtered by fields such as `handle` or `q` passed in the `query` parameter. - * The product categories can also be paginated. This method can also be used to retrieve a product category by its handle. - * @param {StoreGetProductCategoriesParams} query - Filters and pagination configurations to apply on the retrieved product categories. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of product categories with pagination fields. - * - * @example - * To list product categories: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.productCategories.list() - * .then(({ product_categories, limit, offset, count }) => { - * console.log(product_categories.length); - * }) - * ``` - * - * To retrieve a product category by its handle: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.productCategories.list({ - * handle: "women", - * }) - * .then(({ product_categories, limit, offset, count }) => { - * if (!product_categories.length) { - * // category does not exist - * } - * const category = product_categories[0] - * }) - * ``` - * - * To specify relations that should be retrieved within the product categories: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.productCategories.list({ - * expand: "products" - * }) - * .then(({ product_categories, limit, offset, count }) => { - * console.log(product_categories.length); - * }) - * ``` - * - * By default, only the first `100` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.productCategories.list({ - * expand: "products", - * limit, - * offset - * }) - * .then(({ product_categories, limit, offset, count }) => { - * console.log(product_categories.length); - * }) - * ``` - */ - list( - query?: StoreGetProductCategoriesParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/store/product-categories` - - if (query) { - const queryString = qs.stringify(query) - path = `${path}?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default ProductCategoriesResource diff --git a/packages/medusa-js/src/resources/product-tags.ts b/packages/medusa-js/src/resources/product-tags.ts deleted file mode 100644 index 7b9fde8a5f..0000000000 --- a/packages/medusa-js/src/resources/product-tags.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { - StoreGetProductTagsParams, - StoreProductTagsListRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" - -/** - * This class is used to send requests to [Store Product Tag API Routes](https://docs.medusajs.com/api/store#product-tags). All its method - * are available in the JS Client under the `medusa.productTags` property. - * - * Product tags are string values that can be used to filter products by. - * Products can have more than one tag, and products can share tags. - */ -class ProductTagsResource extends BaseResource { - /** - * Retrieve a list of product tags. The product tags can be filtered by fields such as `id` or `q` passed in the `query` parameter. The product tags can also be sorted or paginated. - * @param {StoreGetProductTagsParams} query - Filters and pagination configurations to apply on the retrieved product tags. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of product tags with pagination fields. - * - * @example - * To list product tags: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.productTags.list() - * .then(({ product_tags }) => { - * console.log(product_tags.length); - * }) - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.productTags.list({ - * limit, - * offset - * }) - * .then(({ product_tags }) => { - * console.log(product_tags.length); - * }) - * ``` - */ - list( - query?: StoreGetProductTagsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/store/product-tags` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default ProductTagsResource diff --git a/packages/medusa-js/src/resources/product-types.ts b/packages/medusa-js/src/resources/product-types.ts deleted file mode 100644 index aab30f9e5e..0000000000 --- a/packages/medusa-js/src/resources/product-types.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { - StoreGetProductTypesParams, - StoreProductTypesListRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" - -/** - * This class is used to send requests to [Store Product Type API Routes](https://docs.medusajs.com/api/store#product-types). All its method - * are available in the JS Client under the `medusa.productTypes` property. - * - * Product types are string values that can be used to filter products by. - * Products can have more than one tag, and products can share types. - */ -class ProductTypesResource extends BaseResource { - /** - * Retrieve a list of product types. The product types can be filtered by fields such as `value` or `q` passed in the `query` parameter. The product types can also be sorted or paginated. - * @param {StoreGetProductTypesParams} query - Filters and pagination configurations to apply on retrieved product types. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of product types with pagination fields. - * - * @example - * To list product types: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.productTypes.list() - * .then(({ product_types }) => { - * console.log(product_types.length); - * }) - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.productTypes.list({ - * limit, - * offset - * }) - * .then(({ product_types }) => { - * console.log(product_types.length); - * }) - * ``` - */ - list( - query?: StoreGetProductTypesParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/store/product-types` - - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default ProductTypesResource diff --git a/packages/medusa-js/src/resources/product-variants.ts b/packages/medusa-js/src/resources/product-variants.ts deleted file mode 100644 index 373cc46509..0000000000 --- a/packages/medusa-js/src/resources/product-variants.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { - StoreGetVariantsParams, - StoreVariantsListRes, - StoreVariantsRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" - -/** - * This class is used to send requests to [Store Product Variant API Routes](https://docs.medusajs.com/api/store#product-variants). All its method - * are available in the JS Client under the `medusa.product.variants` property. - * - * Product variants are the actual salable item in your store. Each variant is a combination of the different option values available on the product. - */ -class ProductVariantsResource extends BaseResource { - /** - * Retrieve a Product Variant's details. For accurate and correct pricing of the product variant based on the customer's context, it's highly recommended to pass fields such as - * `region_id`, `currency_code`, and `cart_id` when available. - * - * Passing `sales_channel_id` ensures retrieving only variants of products available in the current sales channel. - * You can alternatively use a publishable API key in the request header instead of passing a `sales_channel_id`. - * @param {string} id - The ID of the product variant. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product variant's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.product.variants.retrieve(productVariantId) - * .then(({ variant }) => { - * console.log(variant.id); - * }) - */ - retrieve(id: string, customHeaders: Record = {}): ResponsePromise { - const path = `/store/variants/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieves a list of product variants. The product variants can be filtered by fields such as `id` or `title` passed in the `query` parameter. The product variants can also be paginated. - * - * For accurate and correct pricing of the product variants based on the customer's context, it's highly recommended to pass fields such as - * `region_id`, `currency_code`, and `cart_id` when available. - * - * Passing `sales_channel_id` ensures retrieving only variants of products available in the specified sales channel. - * You can alternatively use a publishable API key in the request header instead of passing a `sales_channel_id`. - * @param {StoreGetVariantsParams} query - Filters and pagination configurations applied on the retrieved product variants. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of product variants. - * - * @example - * To list product variants: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.product.variants.list() - * .then(({ variants }) => { - * console.log(variants.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the product variants: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.product.variants.list({ - * expand: "product" - * }) - * .then(({ variants }) => { - * console.log(variants.length); - * }) - * ``` - * - * By default, only the first `100` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.product.variants.list({ - * expand: "product", - * limit, - * offset - * }) - * .then(({ variants }) => { - * console.log(variants.length); - * }) - * ``` - */ - list(query?: StoreGetVariantsParams, customHeaders: Record = {}): ResponsePromise { - let path = `/store/variants` - if (query) { - const queryString = qs.stringify(query) - path += `?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default ProductVariantsResource diff --git a/packages/medusa-js/src/resources/products.ts b/packages/medusa-js/src/resources/products.ts deleted file mode 100644 index 16b706af4a..0000000000 --- a/packages/medusa-js/src/resources/products.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { - StoreGetProductsParams, - StorePostSearchReq, - StorePostSearchRes, - StoreProductsListRes, - StoreProductsRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" -import ProductVariantsResource from "./product-variants" - -/** - * This class is used to send requests to [Store Product API Routes](https://docs.medusajs.com/api/store#products). All its method - * are available in the JS Client under the `medusa.products` property. - * - * Products are saleable items in a store. This also includes [saleable gift cards](https://docs.medusajs.com/modules/gift-cards/storefront/use-gift-cards) in a store. - * Using the methods in this class, you can filter products by categories, collections, sales channels, and more. - * - * Related Guide: [How to show products in a storefront](https://docs.medusajs.com/modules/products/storefront/show-products). - */ -class ProductsResource extends BaseResource { - /** - * An instance of {@link ProductVariantsResource} used to send requests to [Store Product Variant API Routes](https://docs.medusajs.com/api/store#product-variants_getvariants). - */ - public variants = new ProductVariantsResource(this.client) - - /** - * Retrieve a Product's details. For accurate and correct pricing of the product based on the customer's context, it's highly recommended to pass fields such as - * `region_id`, `currency_code`, and `cart_id` when available. - * - * Passing `sales_channel_id` ensures retrieving only products available in the current sales channel. - * You can alternatively use a publishable API key in the request header instead of passing a `sales_channel_id`. - * @param {string} id - The product's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the product's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.products.retrieve(productId) - * .then(({ product }) => { - * console.log(product.id); - * }) - */ - retrieve( - id: string, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/products/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Run a search query on products using the search service installed on the Medusa backend. The searching is handled through the search service, so the returned data's - * format depends on the search service you're using. - * @param {StorePostSearchReq} searchOptions - Fields to search products. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of search results. The format of the items depends on the search engine installed on the Medusa backend. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.products.search({ - * q: "Shirt" - * }) - * .then(({ hits }) => { - * console.log(hits.length); - * }) - */ - search( - searchOptions: StorePostSearchReq, - customHeaders: Record = {} - ): ResponsePromise { - const path = `/store/products/search` - return this.client.request("POST", path, searchOptions, {}, customHeaders) - } - - /** - * Retrieve a list of products. The products can be filtered by fields such as `id` or `q` passed in the `query` parameter. The products can also be sorted or paginated. - * This method can also be used to retrieve a product by its handle. - * - * For accurate and correct pricing of the products based on the customer's context, it's highly recommended to pass fields such as - * `region_id`, `currency_code`, and `cart_id` when available. - * - * Passing `sales_channel_id` ensures retrieving only products available in the specified sales channel. - * You can alternatively use a publishable API key in the request header instead of passing a `sales_channel_id`. - * @param {StoreGetProductsParams} query - Filters and pagination configurations to apply on the retrieved products. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of products with pagination fields. - * - * @example - * To list products: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.products.list() - * .then(({ products, limit, offset, count }) => { - * console.log(products.length); - * }) - * ``` - * - * To specify relations that should be retrieved within the products: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.products.list({ - * expand: "variants" - * }) - * .then(({ products, limit, offset, count }) => { - * console.log(products.length); - * }) - * ``` - * - * By default, only the first `100` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.products.list({ - * expand: "variants", - * limit, - * offset - * }) - * .then(({ products, limit, offset, count }) => { - * console.log(products.length); - * }) - * ``` - */ - list( - query?: StoreGetProductsParams, - customHeaders: Record = {} - ): ResponsePromise { - let path = `/store/products` - - if (query) { - const queryString = qs.stringify(query) - path = `/store/products?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default ProductsResource diff --git a/packages/medusa-js/src/resources/regions.ts b/packages/medusa-js/src/resources/regions.ts deleted file mode 100644 index d723646e0b..0000000000 --- a/packages/medusa-js/src/resources/regions.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { ResponsePromise } from "../typings" -import { StoreRegionsListRes, StoreRegionsRes } from "@medusajs/medusa" -import BaseResource from "./base" - -/** - * This class is used to send requests to [Store Region API Routes](https://docs.medusajs.com/api/store#regions_getregions). All its method - * are available in the JS Client under the `medusa.regions` property. - * - * Regions are different countries or geographical regions that the commerce store serves customers in. - * Customers can choose what region they're in, which can be used to change the prices shown based on the region and its currency. - * - * Related Guide: [How to use regions in a storefront](https://docs.medusajs.com/modules/regions-and-currencies/storefront/use-regions). - */ -class RegionsResource extends BaseResource { - /** - * Retrieve a list of regions. This method is useful to show the customer all available regions to choose from. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of regions with pagination fields. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.regions.list() - * .then(({ regions, count, limit, offset }) => { - * console.log(regions.length); - * }) - */ - list(customHeaders: Record = {}): ResponsePromise { - const path = `/store/regions` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a Region's details. - * @param {string} id - The region's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the region's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.regions.retrieve(regionId) - * .then(({ region }) => { - * console.log(region.id); - * }) - */ - retrieve(id: string, customHeaders: Record = {}): ResponsePromise { - const path = `/store/regions/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default RegionsResource diff --git a/packages/medusa-js/src/resources/return-reasons.ts b/packages/medusa-js/src/resources/return-reasons.ts deleted file mode 100644 index 5e61ef157c..0000000000 --- a/packages/medusa-js/src/resources/return-reasons.ts +++ /dev/null @@ -1,53 +0,0 @@ -import BaseResource from "./base" -import { - StoreReturnReasonsListRes, - StoreReturnReasonsRes, -} from "@medusajs/medusa" -import { ResponsePromise } from "../typings" - -/** - * This class is used to send requests to [Store Return Reason API Routes](https://docs.medusajs.com/api/store#return-reasons). All its method - * are available in the JS Client under the `medusa.returnReasons` property. - * - * Return reasons are key-value pairs that are used to specify why an order return is being created. - */ -class ReturnReasonsResource extends BaseResource { - /** - * Retrieve a Return Reason's details. - * @param {string} id - The ID of the return reason. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the return reason's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.returnReasons.retrieve(reasonId) - * .then(({ return_reason }) => { - * console.log(return_reason.id); - * }) - */ - retrieve(id: string, customHeaders: Record = {}): ResponsePromise { - const path = `/store/return-reasons/${id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of Return Reasons. This is useful when implementing a Create Return flow in the storefront. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of return reasons. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.returnReasons.list() - * .then(({ return_reasons }) => { - * console.log(return_reasons.length); - * }) - */ - list(customHeaders: Record = {}): ResponsePromise { - const path = `/store/return-reasons` - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default ReturnReasonsResource diff --git a/packages/medusa-js/src/resources/returns.ts b/packages/medusa-js/src/resources/returns.ts deleted file mode 100644 index cbd4a05db9..0000000000 --- a/packages/medusa-js/src/resources/returns.ts +++ /dev/null @@ -1,42 +0,0 @@ -import BaseResource from "./base" -import { ResponsePromise } from "../typings" -import { StoreReturnsRes, StorePostReturnsReq } from "@medusajs/medusa" - -/** - * This class is used to send requests to [Store Return API Routes](https://docs.medusajs.com/api/store#returns). All its method - * are available in the JS Client under the `medusa.returns` property. - * - * A return can be created by a customer to return items in an order. - * - * Related Guide: [How to create a return in a storefront](https://docs.medusajs.com/modules/orders/storefront/create-return). - */ -class ReturnsResource extends BaseResource { - /** - * Create a return for an order. If a return shipping method is specified, the return is automatically fulfilled. - * @param {StorePostReturnsReq} payload - The data of the return to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the return's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.returns.create({ - * order_id, - * items: [ - * { - * item_id, - * quantity: 1 - * } - * ] - * }) - * .then((data) => { - * console.log(data.return.id); - * }) - */ - create(payload: StorePostReturnsReq, customHeaders: Record = {}): ResponsePromise { - const path = `/store/returns` - return this.client.request("POST", path, payload, {}, customHeaders) - } -} - -export default ReturnsResource diff --git a/packages/medusa-js/src/resources/shipping-options.ts b/packages/medusa-js/src/resources/shipping-options.ts deleted file mode 100644 index d3d6631db9..0000000000 --- a/packages/medusa-js/src/resources/shipping-options.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { - StoreGetShippingOptionsParams, - StoreShippingOptionsListRes, -} from "@medusajs/medusa" -import qs from "qs" -import { ResponsePromise } from "../typings" -import BaseResource from "./base" - -/** - * This class is used to send requests to [Store Shipping Option API Routes](https://docs.medusajs.com/api/store#shipping-options). All its method - * are available in the JS Client under the `medusa.shippingOptions` property. - * - * A shipping option is used to define the available shipping methods during checkout or when creating a return. - * - * Related Guide: [Shipping Option architecture](https://docs.medusajs.com/modules/carts-and-checkout/shipping#shipping-option). - */ -class ShippingOptionsResource extends BaseResource { - /** - * Retrieve a list of shipping options available for a cart. - * @param {string} cart_id - The cart's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of shipping options. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.shippingOptions.listCartOptions(cartId) - * .then(({ shipping_options }) => { - * console.log(shipping_options.length); - * }) - */ - listCartOptions(cart_id: string, customHeaders: Record = {}): ResponsePromise { - const path = `/store/shipping-options/${cart_id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } - - /** - * Retrieve a list of shipping options. The shipping options can be filtered using the `query` parameter. - * @param {StoreGetShippingOptionsParams} query - The filters to apply on the shipping options. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the list of shipping options. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.shippingOptions.list() - * .then(({ shipping_options }) => { - * console.log(shipping_options.length); - * }) - */ - list( - query?: StoreGetShippingOptionsParams, - customHeaders: Record = {}): ResponsePromise { - let path = `/store/shipping-options` - - if (query) { - const queryString = qs.stringify(query) - path = `/store/shipping-options?${queryString}` - } - - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default ShippingOptionsResource diff --git a/packages/medusa-js/src/resources/swaps.ts b/packages/medusa-js/src/resources/swaps.ts deleted file mode 100644 index a6a140a101..0000000000 --- a/packages/medusa-js/src/resources/swaps.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { ResponsePromise } from "../typings" -import { StoreSwapsRes, StorePostSwapsReq } from "@medusajs/medusa" -import BaseResource from "./base" - -/** - * This class is used to send requests to [Store Swap API Routes](https://docs.medusajs.com/api/store#swaps). All its method - * are available in the JS Client under the `medusa.swaps` property. - * - * A swap is created by a customer or an admin to exchange an item with a new one. - * Creating a swap implicitely includes creating a return for the item being exchanged. - * - * Related Guide: [How to create a swap in a storefront](https://docs.medusajs.com/modules/orders/storefront/create-swap) - */ -class SwapsResource extends BaseResource { - /** - * Create a Swap for an Order. This will also create a return and associate it with the swap. If a return shipping option is specified, the return will automatically be fulfilled. - * To complete the swap, you must use the {@link CartsResource.complete} method passing it the ID of the swap's cart. - * - * An idempotency key will be generated if none is provided in the header `Idempotency-Key` and added to - * the response. If an error occurs during swap creation or the request is interrupted for any reason, the swap creation can be retried by passing the idempotency - * key in the `Idempotency-Key` header. - * @param {StorePostSwapsReq} payload - The data of the swap to be created. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the swap's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.swaps.create({ - * order_id, - * return_items: [ - * { - * item_id, - * quantity: 1 - * } - * ], - * additional_items: [ - * { - * variant_id, - * quantity: 1 - * } - * ] - * }) - * .then(({ swap }) => { - * console.log(swap.id); - * }) - */ - create(payload: StorePostSwapsReq, customHeaders: Record = {}): ResponsePromise { - const path = `/store/swaps` - return this.client.request("POST", path, payload, {}, customHeaders) - } - - /** - * Retrieve a Swap's details by the ID of its cart. - * @param {string} cart_id - The cart's ID. - * @param {Record} customHeaders - Custom headers to attach to the request. - * @returns {ResponsePromise} Resolves to the swap's details. - * - * @example - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.swaps.retrieveByCartId(cartId) - * .then(({ swap }) => { - * console.log(swap.id); - * }) - */ - retrieveByCartId(cart_id: string, customHeaders: Record = {}): ResponsePromise { - const path = `/store/swaps/${cart_id}` - return this.client.request("GET", path, undefined, {}, customHeaders) - } -} - -export default SwapsResource diff --git a/packages/medusa-js/src/test/utils/utils.test.ts b/packages/medusa-js/src/test/utils/utils.test.ts deleted file mode 100644 index 1cdbee3ad6..0000000000 --- a/packages/medusa-js/src/test/utils/utils.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -const { stringifyNullProperties } = require("../../utils") - -describe("stringifyNullProperties", () => { - test("returns empty object on no props", () => { - const result = stringifyNullProperties({}) - expect(result).toEqual({}) - }) - - test("successfully stringifies null property", () => { - const result = stringifyNullProperties({ test: null }) - expect(result).toEqual({ test: "null" }) - }) - - test("successfully stringifies nested null property", () => { - const result = stringifyNullProperties({ - test: { test_2: { test_3: null } }, - another_test: "test", - }) - expect(result).toEqual({ - test: { test_2: { test_3: "null" } }, - another_test: "test", - }) - }) - - test("successfully stringifies string property", () => { - const result = stringifyNullProperties({ - test: "test", - }) - expect(result).toEqual({ test: "test" }) - }) -}) diff --git a/packages/medusa-js/src/typings.ts b/packages/medusa-js/src/typings.ts deleted file mode 100644 index 44e4d4e6cc..0000000000 --- a/packages/medusa-js/src/typings.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - AdminCreateUserRequest, - AdminPostInvitesReq, - AdminUpdateUserRequest, -} from "@medusajs/medusa" - -export interface HTTPResponse { - status: number - statusText: string - headers: Record & { - "set-cookie"?: string[] - } - config: any - request?: any -} - -export type Response = T & { - response: HTTPResponse -} - -export type ResponsePromise = Promise> - -type NoUndefined = T extends undefined ? never : T - -type CreateUserRolesEnum = NoUndefined - -// convert Enum type to union of string literals -export type CreateUserRoles = `${CreateUserRolesEnum}` - -/** - * The details of the user to create. - */ -export type AdminCreateUserPayload = - | Omit - | { - role?: CreateUserRoles - } - -type UpdateUserRolesEnum = NoUndefined - -export type UpdateUserRoles = `${UpdateUserRolesEnum}` - -/** - * The details to update of the user. - */ -export type AdminUpdateUserPayload = Omit & { - role?: UpdateUserRoles -} - -export type InviteUserRolesEnum = `${AdminPostInvitesReq["role"]}` - -export type AdminPostInvitesPayload = Omit & { - role: InviteUserRolesEnum -} - -/** - * The file(s) to upload. - */ -export type AdminCreateUploadPayload = File | File[] diff --git a/packages/medusa-js/src/utils.ts b/packages/medusa-js/src/utils.ts deleted file mode 100644 index ae199f4d68..0000000000 --- a/packages/medusa-js/src/utils.ts +++ /dev/null @@ -1,35 +0,0 @@ -export function stringifyNullProperties(input: T): T { - const convertProperties = (obj: T) => { - const res = {} as T - - Object.keys(obj).reduce((acc: T, key: string) => { - if (obj[key] === null) { - acc[key] = "null" - } else if (typeof obj[key] === "object") { - acc[key] = convertProperties(obj[key]) - } else { - acc[key] = obj[key] - } - - return acc - }, res) - - return res - } - - return convertProperties(input) -} - -export function createAdminPath(path: string) { - let formattedPath = path - - if (!formattedPath.startsWith("/")) { - formattedPath = `/${formattedPath}` - } - - if (!formattedPath.startsWith("/admin")) { - formattedPath = `/admin${formattedPath}` - } - - return formattedPath -} diff --git a/packages/medusa-js/tsconfig.json b/packages/medusa-js/tsconfig.json deleted file mode 100644 index 216e48c931..0000000000 --- a/packages/medusa-js/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "src", - "module": "esnext", - "target": "ES2015", - "outDir": "./dist", - "declarationDir": "./dist", - "esModuleInterop": true, - "declaration": true, - "moduleResolution": "node", - "sourceMap": true, - "noImplicitReturns": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "noImplicitThis": true, - "allowJs": true, - "skipLibCheck": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules", " **/tests/*"] -} diff --git a/packages/medusa-js/tsconfig.spec.json b/packages/medusa-js/tsconfig.spec.json deleted file mode 100644 index a108b800db..0000000000 --- a/packages/medusa-js/tsconfig.spec.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": [ - "./src/**/*", - "index.d.ts", - "./src/**/__tests__", - "./src/**/__mocks__" - ], - "exclude": ["node_modules"] -} diff --git a/packages/medusa-js/tsup.config.ts b/packages/medusa-js/tsup.config.ts deleted file mode 100644 index df703de84a..0000000000 --- a/packages/medusa-js/tsup.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { Options } from "tsup" - -const config: Options = { - entry: ["src/**/*.ts"], - dts: true, - clean: true, - minify: true, - bundle: true, - sourcemap: true, - format: ["cjs", "esm"], - target: "es2020", - skipNodeModulesBundle: true, - tsconfig: "./tsconfig.json", -} - -export default config diff --git a/packages/medusa-react/.github/workflows/main.yml b/packages/medusa-react/.github/workflows/main.yml deleted file mode 100644 index d441e3b513..0000000000 --- a/packages/medusa-react/.github/workflows/main.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: CI -on: [push] -jobs: - build: - name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }} - - runs-on: ${{ matrix.os }} - strategy: - matrix: - node: ["16.x"] - os: [ubuntu-latest, windows-latest, macOS-latest] - - steps: - - name: Checkout repo - uses: actions/checkout@v3 - - - name: Use Node ${{ matrix.node }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node }} - - - name: Install deps and build (with cache) - uses: bahmutov/npm-install@v1 - - - name: Lint - run: yarn lint - - - name: Test - run: yarn test --ci --coverage --maxWorkers=2 - - - name: Build - run: yarn build diff --git a/packages/medusa-react/.github/workflows/size.yml b/packages/medusa-react/.github/workflows/size.yml deleted file mode 100644 index bc80c4c094..0000000000 --- a/packages/medusa-react/.github/workflows/size.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: size -on: [pull_request] -jobs: - size: - runs-on: ubuntu-latest - env: - CI_JOB_NUMBER: 1 - steps: - - uses: actions/checkout@v3 - - uses: andresz1/size-limit-action@v1 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/packages/medusa-react/.gitignore b/packages/medusa-react/.gitignore deleted file mode 100644 index d4de8fc068..0000000000 --- a/packages/medusa-react/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.log -.DS_Store -node_modules -.cache -dist diff --git a/packages/medusa-react/.storybook/main.js b/packages/medusa-react/.storybook/main.js deleted file mode 100644 index cf1ac4a9f9..0000000000 --- a/packages/medusa-react/.storybook/main.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - stories: ['../stories/**/*.stories.@(ts|tsx|js|jsx)'], - addons: ['@storybook/addon-links', '@storybook/addon-essentials'], - // https://storybook.js.org/docs/react/configure/typescript#mainjs-configuration - typescript: { - check: true, // type-check stories during Storybook build - } -}; diff --git a/packages/medusa-react/.storybook/medusa-context.js b/packages/medusa-react/.storybook/medusa-context.js deleted file mode 100644 index 92aaf4f1e1..0000000000 --- a/packages/medusa-react/.storybook/medusa-context.js +++ /dev/null @@ -1,23 +0,0 @@ -import { QueryClient } from "@tanstack/react-query" -import React from "react" -import { MedusaProvider } from "../src" - -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - refetchOnWindowFocus: false, - staleTime: Infinity, - retry: 1, - }, - }, -}) - -const DefaultMedusaProvider = (props) => ( - -) - -export default DefaultMedusaProvider diff --git a/packages/medusa-react/.storybook/preview.js b/packages/medusa-react/.storybook/preview.js deleted file mode 100644 index 7c4b9646ce..0000000000 --- a/packages/medusa-react/.storybook/preview.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react" -import DefaultMedusaProvider from "./medusa-context" -import { initialize, mswDecorator } from "msw-storybook-addon" -import { adminHandlers, storeHandlers } from "../mocks/handlers" - -initialize() - -// https://storybook.js.org/docs/react/writing-stories/parameters#global-parameters -export const parameters = { - // https://storybook.js.org/docs/react/essentials/actions#automatically-matching-args - actions: { argTypesRegex: "^on.*" }, - msw: { - handlers: [...adminHandlers, ...storeHandlers], - }, -} - -export const decorators = [ - mswDecorator, - (Story) => ( - - - - ), -] diff --git a/packages/medusa-react/CHANGELOG.md b/packages/medusa-react/CHANGELOG.md deleted file mode 100644 index 255467972d..0000000000 --- a/packages/medusa-react/CHANGELOG.md +++ /dev/null @@ -1,631 +0,0 @@ -# Change Log - -## 9.0.17 - -### Patch Changes - -- [#6827](https://github.com/medusajs/medusa/pull/6827) [`0c0b425de7`](https://github.com/medusajs/medusa/commit/0c0b425de7b154b80b712ab17b16215cf62d1e83) Thanks [@riqwan](https://github.com/riqwan)! - feat(medusa-react,medusa,types,dashboard): added empty state for promotions list page - -- [#6883](https://github.com/medusajs/medusa/pull/6883) [`eadc5e8a79`](https://github.com/medusajs/medusa/commit/eadc5e8a794ec07f7b523808aa0fec2ac394c984) Thanks [@olivermrbl](https://github.com/olivermrbl)! - feat: Admin V2 API keys - -- [#6882](https://github.com/medusajs/medusa/pull/6882) [`5e30b8cce6`](https://github.com/medusajs/medusa/commit/5e30b8cce63524d939a5068050798b0d8fcb9a53) Thanks [@riqwan](https://github.com/riqwan)! - feat(dashboard): added details page for promotions - -## 9.0.16 - -### Patch Changes - -- [#6441](https://github.com/medusajs/medusa/pull/6441) [`8dad2b51a2`](https://github.com/medusajs/medusa/commit/8dad2b51a26c4c3c14a6c95f70424c8bef2ad63e) Thanks [@riqwan](https://github.com/riqwan)! - feat(medusa-react,medusa,utils): fix login for medusa v2 admin next dashboard - -- [#6700](https://github.com/medusajs/medusa/pull/6700) [`8f8a4f9b13`](https://github.com/medusajs/medusa/commit/8f8a4f9b1353087d98f6cc75346d43a7f49901a8) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Version all modules to allow for initial testing - -- [#6428](https://github.com/medusajs/medusa/pull/6428) [`44d43e8155`](https://github.com/medusajs/medusa/commit/44d43e8155d1b1ca0af5e900787411c7d0b027c0) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - feat(medusa,medusa-js,medusa-react,icons): Fixes GET /admin/products/:id/variants endpoint in the core, and medusa-js and medusa-react. Pulls latest icons from Figma into `@medusajs/icons`. - -- Updated dependencies [[`8f8a4f9b13`](https://github.com/medusajs/medusa/commit/8f8a4f9b1353087d98f6cc75346d43a7f49901a8), [`44d43e8155`](https://github.com/medusajs/medusa/commit/44d43e8155d1b1ca0af5e900787411c7d0b027c0)]: - - @medusajs/medusa-js@6.1.8 - -## 9.0.15 - -### Patch Changes - -- [`ef64f3740`](https://github.com/medusajs/medusa/commit/ef64f3740d90a8b8565ed10d33e8e35a640cd1ae) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Add missing changeset for medusa-react - -- Updated dependencies [[`20cefa033`](https://github.com/medusajs/medusa/commit/20cefa0335384e3c37f593c9698651895765234e)]: - - @medusajs/medusa-js@6.1.7 - -## 9.0.14 - -### Patch Changes - -- [#6190](https://github.com/medusajs/medusa/pull/6190) [`d68089b2a`](https://github.com/medusajs/medusa/commit/d68089b2aa2fb4ab52640424ed1a378cd649364f) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - fix(medusa): Implements `listAndCount` method for UserService, and updates list endpoint to accept the expected params. - fix(medusa-js): Update `admin.users.list` to accept query params. - fix(medusa-react): Update `useAdminUsers` hook to accept query params. -- Updated dependencies [[`db4da5602`](https://github.com/medusajs/medusa/commit/db4da56023c1c0563a545bffb2bec9cf0e1c4c4a), [`d68089b2a`](https://github.com/medusajs/medusa/commit/d68089b2aa2fb4ab52640424ed1a378cd649364f), [`4c4c0f655`](https://github.com/medusajs/medusa/commit/4c4c0f655bad4feb4c34848d195cac4fe8a902d4)]: - - @medusajs/medusa-js@6.1.6 - -## 9.0.13 - -### Patch Changes - -- [#6004](https://github.com/medusajs/medusa/pull/6004) [`7d650771d`](https://github.com/medusajs/medusa/commit/7d650771d1c1d3e5d77ff95c12e4970743b64303) Thanks [@shahednasser](https://github.com/shahednasser)! - fix(medusa-react): general type fixes related to generating reference documentation - -- [#5982](https://github.com/medusajs/medusa/pull/5982) [`925feea04`](https://github.com/medusajs/medusa/commit/925feea04a8222285175c33577548e50516069a7) Thanks [@olivermrbl](https://github.com/olivermrbl)! - feat(cart): Add cart module package - -- Updated dependencies [[`bfd10dada`](https://github.com/medusajs/medusa/commit/bfd10dadaf6286aa26dac96d7c0cc5bc24e43c9b), [`f25ca30b3`](https://github.com/medusajs/medusa/commit/f25ca30b3aec558094b1dffe70583fcbba64b29a)]: - - @medusajs/medusa-js@6.1.5 - -## 9.0.12 - -### Patch Changes - -- [#5765](https://github.com/medusajs/medusa/pull/5765) [`4e9d95454`](https://github.com/medusajs/medusa/commit/4e9d954549916ea260583a6b5e36f0c6c02d4d22) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - fix(medusa-react): Allow setting maxRetries on MedusaProvider - -## 9.0.11 - -### Patch Changes - -- [#5582](https://github.com/medusajs/medusa/pull/5582) [`91615f9c4`](https://github.com/medusajs/medusa/commit/91615f9c459a2d8cb842561c5edb335680d30298) Thanks [@shahednasser](https://github.com/shahednasser)! - fix(@medusajs/client-types): Fix types and TSDocs - fix(medusa-react): Fix response type of Publishable API Key's list sales channels. - fix(@medusajs/medusa-js): Fix incorrect parameter and response types. - fix(@medusajs/medusa): Fix incorrect types and add TSDocs - fix(@medusajs/types): Fix incorrect types and add TSDocs -- Updated dependencies [[`91615f9c4`](https://github.com/medusajs/medusa/commit/91615f9c459a2d8cb842561c5edb335680d30298)]: - - @medusajs/medusa-js@6.1.4 - -## 9.0.10 - -### Patch Changes - -- [#5480](https://github.com/medusajs/medusa/pull/5480) [`a780b92b8`](https://github.com/medusajs/medusa/commit/a780b92b8d590baa0e86682d1154f9e5b0869ea1) Thanks [@adrien2p](https://github.com/adrien2p)! - fix(medusa): admin get product should return prices when expected - -## 9.0.9 - -### Patch Changes - -- [`045d1b6a0`](https://github.com/medusajs/medusa/commit/045d1b6a0c2b0d03e5fa1db886d1f81c843059ce) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Bump @medusajs/medusa dep - -- Updated dependencies [[`045d1b6a0`](https://github.com/medusajs/medusa/commit/045d1b6a0c2b0d03e5fa1db886d1f81c843059ce)]: - - @medusajs/medusa-js@6.1.3 - -## 9.0.8 - -### Patch Changes - -- [#5400](https://github.com/medusajs/medusa/pull/5400) [`5a5c96e21`](https://github.com/medusajs/medusa/commit/5a5c96e2118e50a558d9d6dc340e505454d4c593) Thanks [@dwene](https://github.com/dwene)! - add types to exports to help projects using moduleResolution bundler - -- Updated dependencies [[`5a5c96e21`](https://github.com/medusajs/medusa/commit/5a5c96e2118e50a558d9d6dc340e505454d4c593), [`98e275551`](https://github.com/medusajs/medusa/commit/98e275551415583602763cf457c3f95400209d0a)]: - - @medusajs/medusa-js@6.1.2 - -## 9.0.7 - -### Patch Changes - -- [#5233](https://github.com/medusajs/medusa/pull/5233) [`0f34e0f38`](https://github.com/medusajs/medusa/commit/0f34e0f381833a4790ee590a9cbf93b7660634f3) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - feat(admin-ui, medusa, medusa-react, medusa-js): Price List UI revamp - -- Updated dependencies [[`0f34e0f38`](https://github.com/medusajs/medusa/commit/0f34e0f381833a4790ee590a9cbf93b7660634f3)]: - - @medusajs/medusa-js@6.1.1 - -## 9.0.6 - -### Patch Changes - -- [#5207](https://github.com/medusajs/medusa/pull/5207) [`a9972d7d6`](https://github.com/medusajs/medusa/commit/a9972d7d6fa5c9698318a55173440f635ebf0a11) Thanks [@olivermrbl](https://github.com/olivermrbl)! - fix(medusa-react): `@medusajs/medusa-js` import - -- Updated dependencies [[`2caff2efc`](https://github.com/medusajs/medusa/commit/2caff2efc757a3738ae8b7ee6fde77ee7100f995)]: - - @medusajs/medusa-js@6.1.0 - -## 9.0.5 - -### Patch Changes - -- [#5074](https://github.com/medusajs/medusa/pull/5074) [`7d3572302`](https://github.com/medusajs/medusa/commit/7d35723023ed5bcfaf06ff2480e97508527e8665) Thanks [@shahednasser](https://github.com/shahednasser)! - fix(medusa-react): fix `useAdminAddStoreCurrency` hook - -- Updated dependencies [[`7d3572302`](https://github.com/medusajs/medusa/commit/7d35723023ed5bcfaf06ff2480e97508527e8665)]: - - @medusajs/medusa-js@6.0.4 - -## 9.0.4 - -### Patch Changes - -- [#4747](https://github.com/medusajs/medusa/pull/4747) [`9469063f6`](https://github.com/medusajs/medusa/commit/9469063f643180002ede7a8e94c6de53d2770d04) Thanks [@olivermrbl](https://github.com/olivermrbl)! - fix(medusa-js): return type of collection hook + export - -- [#4761](https://github.com/medusajs/medusa/pull/4761) [`f1a05f472`](https://github.com/medusajs/medusa/commit/f1a05f4725dcc45150f014769562bd3dfbc0f1f8) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - feat(admin, admin-ui, medusa, medusa-js, medusa-react, stripe-plugin): Support admin extensions - -- Updated dependencies [[`9469063f6`](https://github.com/medusajs/medusa/commit/9469063f643180002ede7a8e94c6de53d2770d04), [`f1a05f472`](https://github.com/medusajs/medusa/commit/f1a05f4725dcc45150f014769562bd3dfbc0f1f8)]: - - @medusajs/medusa-js@6.0.3 - -## 9.0.3 - -### Patch Changes - -- [#4467](https://github.com/medusajs/medusa/pull/4467) [`3e6cee284`](https://github.com/medusajs/medusa/commit/3e6cee28469b5ce30687de5e5096266244f6b3a9) Thanks [@josetr](https://github.com/josetr)! - fix(medusa-react): add missing adminInventoryItemsKeys.lists() to inventory hooks - -- [#4538](https://github.com/medusajs/medusa/pull/4538) [`e3a856521`](https://github.com/medusajs/medusa/commit/e3a85652132c110e4dd81ae1120414121fbab0fd) Thanks [@josetr](https://github.com/josetr)! - fix(medusa-react): fix admin user mutation hooks invalidating wrong keys - -## 9.0.2 - -### Patch Changes - -- [#4409](https://github.com/medusajs/medusa/pull/4409) [`fe25c8a91`](https://github.com/medusajs/medusa/commit/fe25c8a91f4462c9ac5a15594fa71155df48c1eb) Thanks [@pevey](https://github.com/pevey)! - feat(medusa-react,medusa-js): Allow custom headers - -- [#4441](https://github.com/medusajs/medusa/pull/4441) [`417debfe7`](https://github.com/medusajs/medusa/commit/417debfe7db6edd6722929fe0f905a63548a0c9e) Thanks [@josetr](https://github.com/josetr)! - fix(medusa-react): fix wrong admin reservations query key - -- Updated dependencies [[`fe25c8a91`](https://github.com/medusajs/medusa/commit/fe25c8a91f4462c9ac5a15594fa71155df48c1eb), [`708a55199`](https://github.com/medusajs/medusa/commit/708a55199aeb23f5a75fd240ddd10af2c95f3957)]: - - @medusajs/medusa-js@6.0.2 - -## 9.0.1 - -### Patch Changes - -- [#4115](https://github.com/medusajs/medusa/pull/4115) [`79cca2ab8`](https://github.com/medusajs/medusa/commit/79cca2ab809b77606e65706c19f9fce37b174365) Thanks [@pKorsholm](https://github.com/pKorsholm)! - fix(medusa-react): update types to reflect api requests - -- Updated dependencies [[`afd1b67f1`](https://github.com/medusajs/medusa/commit/afd1b67f1c7de8cf07fd9fcbdde599a37914e9b5)]: - - @medusajs/medusa-js@6.0.1 - -## 9.0.0 - -### Patch Changes - -- [#4081](https://github.com/medusajs/medusa/pull/4081) [`4f3c8f5d7`](https://github.com/medusajs/medusa/commit/4f3c8f5d70b5ae4a11e9d4a2fea4a8410b2daf47) Thanks [@pKorsholm](https://github.com/pKorsholm)! - feat(medusa,client-types,medusa-js,admin-ui,medusa-react): add reservation table and creation - -- Updated dependencies [[`0a35f21af`](https://github.com/medusajs/medusa/commit/0a35f21af7ac8b6cdc1af12a403e95f9bf6142fe), [`4fb443c0e`](https://github.com/medusajs/medusa/commit/4fb443c0ea38bde3148bce059c0ee3b91dfff3d4), [`0476f5251`](https://github.com/medusajs/medusa/commit/0476f52519237c622b37d29de0718f9774b6add7), [`0f87d3d64`](https://github.com/medusajs/medusa/commit/0f87d3d642b56bf19de8136e1f5bfedf364c5193), [`ed382f2ee`](https://github.com/medusajs/medusa/commit/ed382f2ee510cbf96164991efa7ff75e3ce659ff), [`92f01cefb`](https://github.com/medusajs/medusa/commit/92f01cefbc4a190defce425fb237d2d68728fa9a), [`e3cfbcd4a`](https://github.com/medusajs/medusa/commit/e3cfbcd4a78073c63ecd9829bc531e50d3944f07), [`6998666c6`](https://github.com/medusajs/medusa/commit/6998666c6edd6617ca61a8d39c26435bad1273e3), [`81eeaa329`](https://github.com/medusajs/medusa/commit/81eeaa32942b1a7148126a7218ceb168ce8d6cac), [`e2d29d35c`](https://github.com/medusajs/medusa/commit/e2d29d35c4c477bc9b4a3ddce1279276fd072875), [`3a38c84f8`](https://github.com/medusajs/medusa/commit/3a38c84f88b05f74ee0a172af3e3f78b2ec8c2d2), [`4f3c8f5d7`](https://github.com/medusajs/medusa/commit/4f3c8f5d70b5ae4a11e9d4a2fea4a8410b2daf47), [`a91987fab`](https://github.com/medusajs/medusa/commit/a91987fab33745f9864eab21bd1c27e8e3e24571), [`bf18bd0c8`](https://github.com/medusajs/medusa/commit/bf18bd0c8a284dd0042d4c54d84acb2e7c10edd3), [`db4199530`](https://github.com/medusajs/medusa/commit/db419953075e0907b8c4d27ab5188e9bd3e3d72b)]: - - @medusajs/medusa@1.12.0 - - @medusajs/medusa-js@6.0.0 - -## 8.0.0 - -### Patch Changes - -- Updated dependencies [[`a66646233`](https://github.com/medusajs/medusa/commit/a666462333d20821a3e50e3fbc65bc8a511c726f), [`9518efcca`](https://github.com/medusajs/medusa/commit/9518efccae1961d9b3cd1e85148e293a3744eedb), [`a86f0e815`](https://github.com/medusajs/medusa/commit/a86f0e815a9e75d7d562fbe516c5bb7e0ab1f6ee), [`cdbac2c84`](https://github.com/medusajs/medusa/commit/cdbac2c8403a3c15c0e11993f6b7dab268fa5c08), [`26963acc0`](https://github.com/medusajs/medusa/commit/26963acc0a5caa1bca97cfe4cbcee113a8d75b84)]: - - @medusajs/medusa@1.11.0 - - @medusajs/medusa-js@5.0.0 - -## 7.0.1 - -### Patch Changes - -- Updated dependencies [[`3d6bcaaf6`](https://github.com/medusajs/medusa/commit/3d6bcaaf65b3a43dfb251460d73e448870b5105f), [`7fd22ecb4`](https://github.com/medusajs/medusa/commit/7fd22ecb4d5190e92c6750a9fbf2d8534bb9f4ab), [`bd53adb23`](https://github.com/medusajs/medusa/commit/bd53adb238a64640533698fbccb98a39a0346590), [`1ea57c3a6`](https://github.com/medusajs/medusa/commit/1ea57c3a69a5377a8dd0821df819743ded4a222b), [`0c58ead6d`](https://github.com/medusajs/medusa/commit/0c58ead6d869f5605cbd2b8aca129984b7493bcf), [`cff54d732`](https://github.com/medusajs/medusa/commit/cff54d73253a4c2d16a174a28f0f5d31c94bcebd), [`a8e73942e`](https://github.com/medusajs/medusa/commit/a8e73942e69662ca673ccc4300e270ff6ab523d1), [`ff37cd190`](https://github.com/medusajs/medusa/commit/ff37cd190fa455f4ba4f76cfb4d641b1611cc32e)]: - - @medusajs/medusa@1.10.1 - - @medusajs/medusa-js@4.0.1 - -## 7.0.0 - -### Patch Changes - -- Updated dependencies [[`0e488e71b`](https://github.com/medusajs/medusa/commit/0e488e71b186f7d08b18c4c6ba409ef3cadb8152), [`538c9874b`](https://github.com/medusajs/medusa/commit/538c9874ba18c1352284089a789d4a90652bc795), [`d539c6fee`](https://github.com/medusajs/medusa/commit/d539c6feeba8ee431f9a655b6cd4e9102cba2b25), [`b7a782639`](https://github.com/medusajs/medusa/commit/b7a7826394ecd621ca80e6d4ce445ea1c26804ac), [`983872319`](https://github.com/medusajs/medusa/commit/98387231927e9872f54c9e72597576f3273de506), [`284f1eed9`](https://github.com/medusajs/medusa/commit/284f1eed9a9fc7272df3fccdb162ea93750999de), [`4e8045a0a`](https://github.com/medusajs/medusa/commit/4e8045a0ac44b1541ee3cd846079f55d3e0dc957), [`d2443d83e`](https://github.com/medusajs/medusa/commit/d2443d83e60fee3c3f28b762d66378c3f07f1b5f), [`8b93bae8f`](https://github.com/medusajs/medusa/commit/8b93bae8f8ad1f6eb43931a7ba03bfa691475eca)]: - - @medusajs/medusa@1.10.0 - - @medusajs/medusa-js@4.0.0 - -## 6.0.0 - -### Patch Changes - -- Updated dependencies [[`440f900af`](https://github.com/medusajs/medusa/commit/440f900af03dd0af29c9b16f01576d3eff45cd04), [`366b12fce`](https://github.com/medusajs/medusa/commit/366b12fcea679551c55baaeeaaf41bbddf04b972), [`7e213f210`](https://github.com/medusajs/medusa/commit/7e213f2106ed76449fbdfa6eda5594b59522443a), [`d2826872f`](https://github.com/medusajs/medusa/commit/d2826872fe487a027b677aeb43704f761a6b4e80), [`0d0e9bf20`](https://github.com/medusajs/medusa/commit/0d0e9bf2069718ac54684efbe4d449942bb2ef32), [`2be144ff0`](https://github.com/medusajs/medusa/commit/2be144ff05e852a3541a9a972942cfc15ef3bd38), [`935abeae6`](https://github.com/medusajs/medusa/commit/935abeae68012a93d820789c743941c3c1a1b802), [`3a77e8a88`](https://github.com/medusajs/medusa/commit/3a77e8a88fd327aca579bcd09d767d9315a04d7f), [`af710f1b4`](https://github.com/medusajs/medusa/commit/af710f1b48a4545a5064029a557013af34c4c100), [`491566df6`](https://github.com/medusajs/medusa/commit/491566df6b7ced35f655f810961422945e10ecd0), [`966ddd2f1`](https://github.com/medusajs/medusa/commit/966ddd2f1648d5d3c1c68094f488f307e3186d92), [`3b3236cc0`](https://github.com/medusajs/medusa/commit/3b3236cc01fc8b7448c1bdbad066a19c2c3de2c3), [`4a8562743`](https://github.com/medusajs/medusa/commit/4a8562743569f5bbb7bd0894b025a74725726529)]: - - @medusajs/medusa@1.9.0 - - @medusajs/medusa-js@3.0.0 - -## 5.0.2 - -### Patch Changes - -- Updated dependencies [[`6bb1654b6`](https://github.com/medusajs/medusa/commit/6bb1654b61880f8658bf1395e4ccef860780aac4), [`95d338262`](https://github.com/medusajs/medusa/commit/95d338262b63e3daa6697bb23806980a8b5e5cdc), [`4f58ddee0`](https://github.com/medusajs/medusa/commit/4f58ddee03509a4c46af160e5824cba80d4c950a)]: - - @medusajs/medusa@1.8.2 - - @medusajs/medusa-js@2.0.2 - -## 5.0.1 - -### Patch Changes - -- [#3752](https://github.com/medusajs/medusa/pull/3752) [`c24c2a973`](https://github.com/medusajs/medusa/commit/c24c2a9732bb0d1aff481b723e421b7fcb49a1f0) Thanks [@fPolic](https://github.com/fPolic)! - fix(medusa-react): update customer hook payload type - -- [#3732](https://github.com/medusajs/medusa/pull/3732) [`30ee10fdd`](https://github.com/medusajs/medusa/commit/30ee10fddd7d8e2f7d742101aad10d2c688ac98e) Thanks [@StephixOne](https://github.com/StephixOne)! - fix(react): Fix input type on useAdminUpdateReservation mutation hook - -- Updated dependencies [[`78ff64e78`](https://github.com/medusajs/medusa/commit/78ff64e7837f6506c641a3c97ffdfa6ee17419ee), [`1a60c6f58`](https://github.com/medusajs/medusa/commit/1a60c6f58dd80d2d8cb8ee10c186975b39325d13), [`713d85a92`](https://github.com/medusajs/medusa/commit/713d85a92cf5249e3b75b96f8bf2c25e4f9b0c90), [`914d57336`](https://github.com/medusajs/medusa/commit/914d57336bc8355533d743745989f793ffd4d513), [`60abb91b7`](https://github.com/medusajs/medusa/commit/60abb91b7c568c6c4cce3b2da7cfb8d54b078299), [`089f1eb19`](https://github.com/medusajs/medusa/commit/089f1eb19e2bb43659c5b300fccb8163c1d60b5c), [`08f85fa33`](https://github.com/medusajs/medusa/commit/08f85fa33b35e15f944a833e1401c7ba2081d3ec), [`282e239df`](https://github.com/medusajs/medusa/commit/282e239dfc0a74f0eb72b17426c8c8bffd86064a), [`abdb74d99`](https://github.com/medusajs/medusa/commit/abdb74d997f49f994bff49787a396179982843b0), [`eab2d22f7`](https://github.com/medusajs/medusa/commit/eab2d22f7d22ec53c68398558ffda32d2a734983), [`08f85fa33`](https://github.com/medusajs/medusa/commit/08f85fa33b35e15f944a833e1401c7ba2081d3ec), [`085fedb1f`](https://github.com/medusajs/medusa/commit/085fedb1f7e982859cff3ef3f1d870dce3bcc8b6), [`4d69d8ef6`](https://github.com/medusajs/medusa/commit/4d69d8ef6aef0a05d0bbb00eed045c2de511be56), [`7f6dc44be`](https://github.com/medusajs/medusa/commit/7f6dc44beb9789088f6d6b796f7545beb3653094), [`d533caa4c`](https://github.com/medusajs/medusa/commit/d533caa4c2986c1c9e320cce97423b0cdc213b6c)]: - - @medusajs/medusa@1.8.1 - - @medusajs/medusa-js@2.0.1 - -## 5.0.0 - -### Minor Changes - -- [#3408](https://github.com/medusajs/medusa/pull/3408) [`54dcc1871`](https://github.com/medusajs/medusa/commit/54dcc1871c8f28bea962dbb9df6e79b038d56449) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Http Server Graceful Shutdown - -### Patch Changes - -- [#3689](https://github.com/medusajs/medusa/pull/3689) [`d06ab9299`](https://github.com/medusajs/medusa/commit/d06ab929946c9e3842dcf4299b2c7e4c85fcc116) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix(react): export product-categories store hooks - -- [#3676](https://github.com/medusajs/medusa/pull/3676) [`788ddc0f4`](https://github.com/medusajs/medusa/commit/788ddc0f43696df607f07133af15a04b29d5447d) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - fix(admin-ui, medusa-react, medusa): Minor fixes to GC domain in admin UI. Also fixes GC update payload type in medusa-react and medusa. - -- [#3435](https://github.com/medusajs/medusa/pull/3435) [`fe9eea4c1`](https://github.com/medusajs/medusa/commit/fe9eea4c18b7e04ba91660716c92b11a49840a3c) Thanks [@pKorsholm](https://github.com/pKorsholm)! - Add create-inventory-item endpoint - -- [#3686](https://github.com/medusajs/medusa/pull/3686) [`7f87c4f2c`](https://github.com/medusajs/medusa/commit/7f87c4f2c8abb876213a595005e67d770be9cbe4) Thanks [@pKorsholm](https://github.com/pKorsholm)! - fix(medusa-react): Query key invalidation - -- [#3685](https://github.com/medusajs/medusa/pull/3685) [`8ddb3952c`](https://github.com/medusajs/medusa/commit/8ddb3952c045e6c05c8d0f6922f0d4ba30cf3bd4) Thanks [@olivermrbl](https://github.com/olivermrbl)! - chore: Fix RC package versions - -- [#3436](https://github.com/medusajs/medusa/pull/3436) [`9ba09ba4d`](https://github.com/medusajs/medusa/commit/9ba09ba4d753f132537f0447097fe9f54922c074) Thanks [@riqwan](https://github.com/riqwan)! - feat(medusa, medusa-js, medusa-react): Add store queries to react medusa - -- [#3110](https://github.com/medusajs/medusa/pull/3110) [`12d304307`](https://github.com/medusajs/medusa/commit/12d304307af87ea9287a41869eb33ef09f273d85) Thanks [@StephixOne](https://github.com/StephixOne)! - feat(medusa,medusa-js,medusa-react): Add inventory module endpoints - -- [#3419](https://github.com/medusajs/medusa/pull/3419) [`80b95a230`](https://github.com/medusajs/medusa/commit/80b95a230056d9ed15f7302f248094f879516faf) Thanks [@pKorsholm](https://github.com/pKorsholm)! - fix(medusa-react): invalidate all reservations list queries - -- [#3416](https://github.com/medusajs/medusa/pull/3416) [`478d1af8d`](https://github.com/medusajs/medusa/commit/478d1af8d0df0af16baf4f130e19b0be34f5f295) Thanks [@riqwan](https://github.com/riqwan)! - feat(medusa, admin-ui, medusa-react): Improvements to product categories - - - Adds name as required in category create form - - Adds name and handle as required in category edit form - - Updates message on create/update forms - - Adds category indicators for is_internal and is_active fields in the tree list - - Fixes bug where tree is not reset when update fails - - allow appending all category descendants with a param in list endpoint - - fix rank order changing on category update - - invalidate products query on category delete - - adds category ui for tree/list, edit, create, delete - - add product category queries and mutations - - category list API can return all descendant - - added breadcrumbs for categories on create/edit modal - - add empty state for product categories - - increase tree depth + scope categories on store + allow categories relation in products API - - categories can be ranked based on position - - seed command can create product categories - - hide categories in products behind feature flag - - fixes bug for mpath incorrectly updated for nested categories - -- [#3478](https://github.com/medusajs/medusa/pull/3478) [`6748877c6`](https://github.com/medusajs/medusa/commit/6748877c694c1433f666c6987f20af76b201b495) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix(oas,js,react): use AdminExtendedStoresRes instead of AdminStoresRes - -- [#2599](https://github.com/medusajs/medusa/pull/2599) [`ef5ef9f5a`](https://github.com/medusajs/medusa/commit/ef5ef9f5a26febf0b64d9981606c1e59999ca76e) Thanks [@olivermrbl](https://github.com/olivermrbl)! - feat(medusa,event-bus-local,event-bus-redis): Event Bus module (Redis + Local) - -- [#3406](https://github.com/medusajs/medusa/pull/3406) [`2d2727f75`](https://github.com/medusajs/medusa/commit/2d2727f753dd9386160d7e677b927c4915e1fce7) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix(eslint): remove unused .eslintignore in medusa-react package - -- [#3401](https://github.com/medusajs/medusa/pull/3401) [`47d344076`](https://github.com/medusajs/medusa/commit/47d3440766efa26aba6638a05edec520a4e62828) Thanks [@riqwan](https://github.com/riqwan)! - feat(admin-ui, medusa-react): allow products to be categorized in product create/edit page - -- Updated dependencies [[`d6b1ad1cc`](https://github.com/medusajs/medusa/commit/d6b1ad1ccd9a8f91b169f30ff99492cf3adcccac), [`e143a8697`](https://github.com/medusajs/medusa/commit/e143a86976a5cc6a53b7a795e8486df4db1d1c09), [`121b42acf`](https://github.com/medusajs/medusa/commit/121b42acfe98c12dd593f9b1f2072ff0f3b61724), [`84e448968`](https://github.com/medusajs/medusa/commit/84e44896836b2c44017572ac5192ab1cd937048c), [`33c6ccf05`](https://github.com/medusajs/medusa/commit/33c6ccf0591b8ef527f3b10a70b51e29751b4998), [`788ddc0f4`](https://github.com/medusajs/medusa/commit/788ddc0f43696df607f07133af15a04b29d5447d), [`5fd74b38a`](https://github.com/medusajs/medusa/commit/5fd74b38ae1b4f7dced191983b78db83f7b1f71b), [`30a320364`](https://github.com/medusajs/medusa/commit/30a3203640be9993ba2f8447abfdecc0d3e2f9b6), [`240d0ea7b`](https://github.com/medusajs/medusa/commit/240d0ea7b88ff494d0fe28c7c5348e958c14571f), [`6c0462472`](https://github.com/medusajs/medusa/commit/6c046247275c46d934f03d53471bdd555a19a9ad), [`589d1c09b`](https://github.com/medusajs/medusa/commit/589d1c09b085dcaf9667061201ac9deff3047466), [`0695ff642`](https://github.com/medusajs/medusa/commit/0695ff642b5836e7c28d40118aafe7a769023d5a), [`530740889`](https://github.com/medusajs/medusa/commit/53074088941719ac7ca435e76e3e64ba23fac200), [`13f40d721`](https://github.com/medusajs/medusa/commit/13f40d721702fbcdf6c131354ec9a81322d4a662), [`4342ac884`](https://github.com/medusajs/medusa/commit/4342ac884bc3fe473576ef10d291f3547e0ffc62), [`fe9eea4c1`](https://github.com/medusajs/medusa/commit/fe9eea4c18b7e04ba91660716c92b11a49840a3c), [`a5ad6c054`](https://github.com/medusajs/medusa/commit/a5ad6c05428e1bb090bbc5a51345a00821781c06), [`748833383`](https://github.com/medusajs/medusa/commit/748833383f4bafd05109dac7afa1286fe851cba3), [`7f87c4f2c`](https://github.com/medusajs/medusa/commit/7f87c4f2c8abb876213a595005e67d770be9cbe4), [`e5a2e9c8d`](https://github.com/medusajs/medusa/commit/e5a2e9c8d237bbe4e3563f5a7a892ca41f01ba24), [`0a02b70e5`](https://github.com/medusajs/medusa/commit/0a02b70e59cfbd8888fb58c29ee9aaf96eb8099a), [`8ddb3952c`](https://github.com/medusajs/medusa/commit/8ddb3952c045e6c05c8d0f6922f0d4ba30cf3bd4), [`fe4b8feb7`](https://github.com/medusajs/medusa/commit/fe4b8feb7e0af2ffc436ca77a769ecb37e16e652), [`aa690beed`](https://github.com/medusajs/medusa/commit/aa690beed775646cbc86b445fb5dc90dcac087d5), [`5eb61fa0e`](https://github.com/medusajs/medusa/commit/5eb61fa0ef991b8a9fabb16c2c159e51b9541867), [`f033711ad`](https://github.com/medusajs/medusa/commit/f033711ad649466d72dd9f673d75848c97c0861f), [`eed784d7d`](https://github.com/medusajs/medusa/commit/eed784d7d0b58aeddc9f6f5ea56fe80c608b22f5), [`3171b0e51`](https://github.com/medusajs/medusa/commit/3171b0e518aebcaa31bbe5c6e914d65282873cda), [`a0c919a8d`](https://github.com/medusajs/medusa/commit/a0c919a8d01ca5edf62336de48e9a112e3822f38), [`522e306e2`](https://github.com/medusajs/medusa/commit/522e306e2e9abf4afce63f30714389eba32bef7f), [`80b95a230`](https://github.com/medusajs/medusa/commit/80b95a230056d9ed15f7302f248094f879516faf), [`a1e59313c`](https://github.com/medusajs/medusa/commit/a1e59313c964a944a287b54f6654d1d19ac8a59b), [`10bf05c14`](https://github.com/medusajs/medusa/commit/10bf05c147cb65a263465129790edd44a6d8948b), [`cbbf3ca05`](https://github.com/medusajs/medusa/commit/cbbf3ca054387a900c5777c2eb0218df2c72bae6), [`9ba09ba4d`](https://github.com/medusajs/medusa/commit/9ba09ba4d753f132537f0447097fe9f54922c074), [`12d304307`](https://github.com/medusajs/medusa/commit/12d304307af87ea9287a41869eb33ef09f273d85), [`693015fde`](https://github.com/medusajs/medusa/commit/693015fde3218d67fb9c07eebeaea9950bf3f1f1), [`287c829c9`](https://github.com/medusajs/medusa/commit/287c829c9c5a9797fb8cd118b7a6066ad1935898), [`74bc4b16a`](https://github.com/medusajs/medusa/commit/74bc4b16a07f78668003ca930bf2a0d928897ceb), [`0cca13779`](https://github.com/medusajs/medusa/commit/0cca13779d0e84683193ad82ab163a10a807e903), [`aed7805c0`](https://github.com/medusajs/medusa/commit/aed7805c0e64b884007148bde90cfce7bee8aad4), [`e359d3f85`](https://github.com/medusajs/medusa/commit/e359d3f85bc12fd3868fc4b563cd994366e899dd), [`0d1b63d77`](https://github.com/medusajs/medusa/commit/0d1b63d773ad91846757a6f0b81b78b0b97b3f2b), [`4042beb10`](https://github.com/medusajs/medusa/commit/4042beb1026b9ad8b381aaa6e1a5214cd92db00f), [`809ab2e0e`](https://github.com/medusajs/medusa/commit/809ab2e0eb2d62054481fa6491d3f7cafbadab4f), [`f43e9f0f2`](https://github.com/medusajs/medusa/commit/f43e9f0f20a8b0637252951b2bdfed4d42fb9f5e), [`842423679`](https://github.com/medusajs/medusa/commit/8424236799c3789f884285cd3c8a491e91aef2ca), [`935870e01`](https://github.com/medusajs/medusa/commit/935870e010af1ec884259b1f1328421e99acc3af), [`57d7728dd`](https://github.com/medusajs/medusa/commit/57d7728dd9d00df712e1a872899b8397955dfe46), [`15f47baf5`](https://github.com/medusajs/medusa/commit/15f47baf56e6722b7821cfaa2fb468e582dfa2c1), [`999aeb116`](https://github.com/medusajs/medusa/commit/999aeb116c4742e5b5e0d80793af23f7727276f0), [`55c5fba0d`](https://github.com/medusajs/medusa/commit/55c5fba0d3dbd015c3ffd74d645a8057892d0f52), [`38503fff5`](https://github.com/medusajs/medusa/commit/38503fff56bbceb092e396ac11432a56967b53e9), [`5e405be02`](https://github.com/medusajs/medusa/commit/5e405be02cc94779222dc3d930e747027496d918), [`40de54b01`](https://github.com/medusajs/medusa/commit/40de54b0101bdfd37f577d18c10ec9f1ab1ce8fe), [`54dcc1871`](https://github.com/medusajs/medusa/commit/54dcc1871c8f28bea962dbb9df6e79b038d56449), [`478d1af8d`](https://github.com/medusajs/medusa/commit/478d1af8d0df0af16baf4f130e19b0be34f5f295), [`77d46220c`](https://github.com/medusajs/medusa/commit/77d46220c23bfe19e575cbc445874eb6c22f3c73), [`6748877c6`](https://github.com/medusajs/medusa/commit/6748877c694c1433f666c6987f20af76b201b495), [`7e17e0ddc`](https://github.com/medusajs/medusa/commit/7e17e0ddc2e6b2891e9ee1420b04a541899d2a9d), [`bca1f80dd`](https://github.com/medusajs/medusa/commit/bca1f80dd501d878455e1ad4f5091cf20ef900ea), [`7f2223b65`](https://github.com/medusajs/medusa/commit/7f2223b6507b0a3c452977bfcdee92af2086fa29), [`7d585f5f8`](https://github.com/medusajs/medusa/commit/7d585f5f84a910c02d274df7a489dc3ff1ea273a), [`4e9d257d3`](https://github.com/medusajs/medusa/commit/4e9d257d3bf76703ef5be8ca054cc9f0f7339def), [`02c77d705`](https://github.com/medusajs/medusa/commit/02c77d7059b7e4cb9f6ebfa8cbec2b84e86118ec), [`ef5ef9f5a`](https://github.com/medusajs/medusa/commit/ef5ef9f5a26febf0b64d9981606c1e59999ca76e), [`feaf8d2e1`](https://github.com/medusajs/medusa/commit/feaf8d2e19715585d154464d003759c3a1f4f322), [`f97b3d7cc`](https://github.com/medusajs/medusa/commit/f97b3d7ccee381d3491337ab5144bb44520382a7), [`55a1f232a`](https://github.com/medusajs/medusa/commit/55a1f232a3746a22adb1fcd1844b2659077a59f9), [`966aea65c`](https://github.com/medusajs/medusa/commit/966aea65c221403bf316ae7665cc8f73bccd9c38), [`48ad2426a`](https://github.com/medusajs/medusa/commit/48ad2426aa7a604c226132e85ef3da5cce045f45)]: - - @medusajs/medusa@1.8.0 - - @medusajs/medusa-js@2.0.0 - -## 5.0.0-rc.8 - -### Patch Changes - -- Updated dependencies [[`4488ec685`](https://github.com/medusajs/medusa/commit/4488ec68524f95f367cbd352e9e5eb1957d1d0d6)]: - - @medusajs/medusa@1.8.0-rc.8 - - @medusajs/medusa-js@2.0.0-rc.8 - -## 5.0.0-rc.7 - -### Patch Changes - -- Updated dependencies [[`748833383`](https://github.com/medusajs/medusa/commit/748833383f4bafd05109dac7afa1286fe851cba3), [`e5a2e9c8d`](https://github.com/medusajs/medusa/commit/e5a2e9c8d237bbe4e3563f5a7a892ca41f01ba24)]: - - @medusajs/medusa@1.8.0-rc.7 - - @medusajs/medusa-js@2.0.0-rc.7 - -## 5.0.0-rc.6 - -### Patch Changes - -- [#3689](https://github.com/medusajs/medusa/pull/3689) [`d06ab9299`](https://github.com/medusajs/medusa/commit/d06ab929946c9e3842dcf4299b2c7e4c85fcc116) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix(react): export product-categories store hooks - -- [#3676](https://github.com/medusajs/medusa/pull/3676) [`788ddc0f4`](https://github.com/medusajs/medusa/commit/788ddc0f43696df607f07133af15a04b29d5447d) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - fix(admin-ui, medusa-react, medusa): Minor fixes to GC domain in admin UI. Also fixes GC update payload type in medusa-react and medusa. - -- [#3686](https://github.com/medusajs/medusa/pull/3686) [`7f87c4f2c`](https://github.com/medusajs/medusa/commit/7f87c4f2c8abb876213a595005e67d770be9cbe4) Thanks [@pKorsholm](https://github.com/pKorsholm)! - fix(medusa-react): Query key invalidation - -- Updated dependencies [[`788ddc0f4`](https://github.com/medusajs/medusa/commit/788ddc0f43696df607f07133af15a04b29d5447d), [`a5ad6c054`](https://github.com/medusajs/medusa/commit/a5ad6c05428e1bb090bbc5a51345a00821781c06), [`7f87c4f2c`](https://github.com/medusajs/medusa/commit/7f87c4f2c8abb876213a595005e67d770be9cbe4), [`eed784d7d`](https://github.com/medusajs/medusa/commit/eed784d7d0b58aeddc9f6f5ea56fe80c608b22f5), [`a0c919a8d`](https://github.com/medusajs/medusa/commit/a0c919a8d01ca5edf62336de48e9a112e3822f38), [`0cca13779`](https://github.com/medusajs/medusa/commit/0cca13779d0e84683193ad82ab163a10a807e903)]: - - @medusajs/medusa@1.8.0-rc.6 - - @medusajs/medusa-js@2.0.0-rc.6 - -## 5.0.0-rc.5 - -### Patch Changes - -- Updated dependencies [[`4342ac884`](https://github.com/medusajs/medusa/commit/4342ac884bc3fe473576ef10d291f3547e0ffc62), [`809ab2e0e`](https://github.com/medusajs/medusa/commit/809ab2e0eb2d62054481fa6491d3f7cafbadab4f)]: - - @medusajs/medusa@1.8.0-rc.5 - - @medusajs/medusa-js@2.0.0-rc.5 - -## 5.0.0-rc.4 - -### Patch Changes - -- Updated dependencies [[`5fd74b38a`](https://github.com/medusajs/medusa/commit/5fd74b38ae1b4f7dced191983b78db83f7b1f71b), [`999aeb116`](https://github.com/medusajs/medusa/commit/999aeb116c4742e5b5e0d80793af23f7727276f0), [`5e405be02`](https://github.com/medusajs/medusa/commit/5e405be02cc94779222dc3d930e747027496d918), [`a7e3f2d34`](https://github.com/medusajs/medusa/commit/a7e3f2d343c4059ba83022ec5c09f8101b251297)]: - - @medusajs/medusa@1.8.0-rc.4 - - @medusajs/medusa-js@2.0.0-rc.4 - -## 5.0.0-rc.3 - -### Patch Changes - -- Updated dependencies [[`0695ff642`](https://github.com/medusajs/medusa/commit/0695ff642b5836e7c28d40118aafe7a769023d5a), [`693015fde`](https://github.com/medusajs/medusa/commit/693015fde3218d67fb9c07eebeaea9950bf3f1f1)]: - - @medusajs/medusa@1.8.0-rc.3 - - @medusajs/medusa-js@2.0.0-rc.3 - -## 5.0.0-rc.2 - -### Patch Changes - -- chore: Fix RC package versions - -- Updated dependencies []: - - @medusajs/medusa-js@2.0.0-rc.2 - - @medusajs/medusa@1.8.0-rc.2 - -## 5.0.0-rc.1 - -### Patch Changes - -- Updated dependencies [[`530740889`](https://github.com/medusajs/medusa/commit/53074088941719ac7ca435e76e3e64ba23fac200), [`e359d3f85`](https://github.com/medusajs/medusa/commit/e359d3f85bc12fd3868fc4b563cd994366e899dd), [`bca1f80dd`](https://github.com/medusajs/medusa/commit/bca1f80dd501d878455e1ad4f5091cf20ef900ea), [`5f41cd9a6`](https://github.com/medusajs/medusa/commit/5f41cd9a67eb0962f999291594c0aac5e38eb916), [`1ce3cc5ae`](https://github.com/medusajs/medusa/commit/1ce3cc5ae4e4cb16eb03be49c9287503f759fc60), [`332a9b686`](https://github.com/medusajs/medusa/commit/332a9b686bd0d224855215213dd11b4704283f62), [`feaf8d2e1`](https://github.com/medusajs/medusa/commit/feaf8d2e19715585d154464d003759c3a1f4f322)]: - - @medusajs/medusa@1.8.0-rc.1 - - @medusajs/medusa-js@2.0.0-rc.1 - -## 5.0.0-rc.0 - -### Minor Changes - -- [#3408](https://github.com/medusajs/medusa/pull/3408) [`54dcc1871`](https://github.com/medusajs/medusa/commit/54dcc1871c8f28bea962dbb9df6e79b038d56449) Thanks [@carlos-r-l-rodrigues](https://github.com/carlos-r-l-rodrigues)! - Http Server Graceful Shutdown - -### Patch Changes - -- [#3435](https://github.com/medusajs/medusa/pull/3435) [`fe9eea4c1`](https://github.com/medusajs/medusa/commit/fe9eea4c18b7e04ba91660716c92b11a49840a3c) Thanks [@pKorsholm](https://github.com/pKorsholm)! - Add create-inventory-item endpoint - -- [#3436](https://github.com/medusajs/medusa/pull/3436) [`9ba09ba4d`](https://github.com/medusajs/medusa/commit/9ba09ba4d753f132537f0447097fe9f54922c074) Thanks [@riqwan](https://github.com/riqwan)! - feat(medusa, medusa-js, medusa-react): Add store queries to react medusa - -- [#3110](https://github.com/medusajs/medusa/pull/3110) [`12d304307`](https://github.com/medusajs/medusa/commit/12d304307af87ea9287a41869eb33ef09f273d85) Thanks [@StephixOne](https://github.com/StephixOne)! - feat(medusa,medusa-js,medusa-react): Add inventory module endpoints - -- [#3419](https://github.com/medusajs/medusa/pull/3419) [`80b95a230`](https://github.com/medusajs/medusa/commit/80b95a230056d9ed15f7302f248094f879516faf) Thanks [@pKorsholm](https://github.com/pKorsholm)! - fix(medusa-react): invalidate all reservations list queries - -- [#3416](https://github.com/medusajs/medusa/pull/3416) [`478d1af8d`](https://github.com/medusajs/medusa/commit/478d1af8d0df0af16baf4f130e19b0be34f5f295) Thanks [@riqwan](https://github.com/riqwan)! - feat(medusa, admin-ui, medusa-react): Improvements to product categories - - - Adds name as required in category create form - - Adds name and handle as required in category edit form - - Updates message on create/update forms - - Adds category indicators for is_internal and is_active fields in the tree list - - Fixes bug where tree is not reset when update fails - - allow appending all category descendants with a param in list endpoint - - fix rank order changing on category update - - invalidate products query on category delete - - adds category ui for tree/list, edit, create, delete - - add product category queries and mutations - - category list API can return all descendant - - added breadcrumbs for categories on create/edit modal - - add empty state for product categories - - increase tree depth + scope categories on store + allow categories relation in products API - - categories can be ranked based on position - - seed command can create product categories - - hide categories in products behind feature flag - - fixes bug for mpath incorrectly updated for nested categories - -- [#3478](https://github.com/medusajs/medusa/pull/3478) [`6748877c6`](https://github.com/medusajs/medusa/commit/6748877c694c1433f666c6987f20af76b201b495) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix(oas,js,react): use AdminExtendedStoresRes instead of AdminStoresRes - -- [#2599](https://github.com/medusajs/medusa/pull/2599) [`ef5ef9f5a`](https://github.com/medusajs/medusa/commit/ef5ef9f5a26febf0b64d9981606c1e59999ca76e) Thanks [@olivermrbl](https://github.com/olivermrbl)! - feat(medusa,event-bus-local,event-bus-redis): Event Bus module (Redis + Local) - -- [#3406](https://github.com/medusajs/medusa/pull/3406) [`2d2727f75`](https://github.com/medusajs/medusa/commit/2d2727f753dd9386160d7e677b927c4915e1fce7) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix(eslint): remove unused .eslintignore in medusa-react package - -- [#3401](https://github.com/medusajs/medusa/pull/3401) [`47d344076`](https://github.com/medusajs/medusa/commit/47d3440766efa26aba6638a05edec520a4e62828) Thanks [@riqwan](https://github.com/riqwan)! - feat(admin-ui, medusa-react): allow products to be categorized in product create/edit page - -- Updated dependencies [[`d6b1ad1cc`](https://github.com/medusajs/medusa/commit/d6b1ad1ccd9a8f91b169f30ff99492cf3adcccac), [`e143a8697`](https://github.com/medusajs/medusa/commit/e143a86976a5cc6a53b7a795e8486df4db1d1c09), [`121b42acf`](https://github.com/medusajs/medusa/commit/121b42acfe98c12dd593f9b1f2072ff0f3b61724), [`84e448968`](https://github.com/medusajs/medusa/commit/84e44896836b2c44017572ac5192ab1cd937048c), [`33c6ccf05`](https://github.com/medusajs/medusa/commit/33c6ccf0591b8ef527f3b10a70b51e29751b4998), [`30a320364`](https://github.com/medusajs/medusa/commit/30a3203640be9993ba2f8447abfdecc0d3e2f9b6), [`240d0ea7b`](https://github.com/medusajs/medusa/commit/240d0ea7b88ff494d0fe28c7c5348e958c14571f), [`6c0462472`](https://github.com/medusajs/medusa/commit/6c046247275c46d934f03d53471bdd555a19a9ad), [`589d1c09b`](https://github.com/medusajs/medusa/commit/589d1c09b085dcaf9667061201ac9deff3047466), [`13f40d721`](https://github.com/medusajs/medusa/commit/13f40d721702fbcdf6c131354ec9a81322d4a662), [`fe9eea4c1`](https://github.com/medusajs/medusa/commit/fe9eea4c18b7e04ba91660716c92b11a49840a3c), [`0a02b70e5`](https://github.com/medusajs/medusa/commit/0a02b70e59cfbd8888fb58c29ee9aaf96eb8099a), [`fe4b8feb7`](https://github.com/medusajs/medusa/commit/fe4b8feb7e0af2ffc436ca77a769ecb37e16e652), [`aa690beed`](https://github.com/medusajs/medusa/commit/aa690beed775646cbc86b445fb5dc90dcac087d5), [`5eb61fa0e`](https://github.com/medusajs/medusa/commit/5eb61fa0ef991b8a9fabb16c2c159e51b9541867), [`f033711ad`](https://github.com/medusajs/medusa/commit/f033711ad649466d72dd9f673d75848c97c0861f), [`3171b0e51`](https://github.com/medusajs/medusa/commit/3171b0e518aebcaa31bbe5c6e914d65282873cda), [`522e306e2`](https://github.com/medusajs/medusa/commit/522e306e2e9abf4afce63f30714389eba32bef7f), [`80b95a230`](https://github.com/medusajs/medusa/commit/80b95a230056d9ed15f7302f248094f879516faf), [`a1e59313c`](https://github.com/medusajs/medusa/commit/a1e59313c964a944a287b54f6654d1d19ac8a59b), [`10bf05c14`](https://github.com/medusajs/medusa/commit/10bf05c147cb65a263465129790edd44a6d8948b), [`cbbf3ca05`](https://github.com/medusajs/medusa/commit/cbbf3ca054387a900c5777c2eb0218df2c72bae6), [`9ba09ba4d`](https://github.com/medusajs/medusa/commit/9ba09ba4d753f132537f0447097fe9f54922c074), [`12d304307`](https://github.com/medusajs/medusa/commit/12d304307af87ea9287a41869eb33ef09f273d85), [`287c829c9`](https://github.com/medusajs/medusa/commit/287c829c9c5a9797fb8cd118b7a6066ad1935898), [`74bc4b16a`](https://github.com/medusajs/medusa/commit/74bc4b16a07f78668003ca930bf2a0d928897ceb), [`aed7805c0`](https://github.com/medusajs/medusa/commit/aed7805c0e64b884007148bde90cfce7bee8aad4), [`0d1b63d77`](https://github.com/medusajs/medusa/commit/0d1b63d773ad91846757a6f0b81b78b0b97b3f2b), [`4042beb10`](https://github.com/medusajs/medusa/commit/4042beb1026b9ad8b381aaa6e1a5214cd92db00f), [`f43e9f0f2`](https://github.com/medusajs/medusa/commit/f43e9f0f20a8b0637252951b2bdfed4d42fb9f5e), [`842423679`](https://github.com/medusajs/medusa/commit/8424236799c3789f884285cd3c8a491e91aef2ca), [`935870e01`](https://github.com/medusajs/medusa/commit/935870e010af1ec884259b1f1328421e99acc3af), [`57d7728dd`](https://github.com/medusajs/medusa/commit/57d7728dd9d00df712e1a872899b8397955dfe46), [`15f47baf5`](https://github.com/medusajs/medusa/commit/15f47baf56e6722b7821cfaa2fb468e582dfa2c1), [`55c5fba0d`](https://github.com/medusajs/medusa/commit/55c5fba0d3dbd015c3ffd74d645a8057892d0f52), [`38503fff5`](https://github.com/medusajs/medusa/commit/38503fff56bbceb092e396ac11432a56967b53e9), [`40de54b01`](https://github.com/medusajs/medusa/commit/40de54b0101bdfd37f577d18c10ec9f1ab1ce8fe), [`54dcc1871`](https://github.com/medusajs/medusa/commit/54dcc1871c8f28bea962dbb9df6e79b038d56449), [`478d1af8d`](https://github.com/medusajs/medusa/commit/478d1af8d0df0af16baf4f130e19b0be34f5f295), [`77d46220c`](https://github.com/medusajs/medusa/commit/77d46220c23bfe19e575cbc445874eb6c22f3c73), [`6748877c6`](https://github.com/medusajs/medusa/commit/6748877c694c1433f666c6987f20af76b201b495), [`7e17e0ddc`](https://github.com/medusajs/medusa/commit/7e17e0ddc2e6b2891e9ee1420b04a541899d2a9d), [`7f2223b65`](https://github.com/medusajs/medusa/commit/7f2223b6507b0a3c452977bfcdee92af2086fa29), [`7d585f5f8`](https://github.com/medusajs/medusa/commit/7d585f5f84a910c02d274df7a489dc3ff1ea273a), [`4e9d257d3`](https://github.com/medusajs/medusa/commit/4e9d257d3bf76703ef5be8ca054cc9f0f7339def), [`02c77d705`](https://github.com/medusajs/medusa/commit/02c77d7059b7e4cb9f6ebfa8cbec2b84e86118ec), [`ef5ef9f5a`](https://github.com/medusajs/medusa/commit/ef5ef9f5a26febf0b64d9981606c1e59999ca76e), [`46547f29c`](https://github.com/medusajs/medusa/commit/46547f29c755719e22d2977c5e5f8ab8a4a7fcae), [`f97b3d7cc`](https://github.com/medusajs/medusa/commit/f97b3d7ccee381d3491337ab5144bb44520382a7), [`f3bf351d2`](https://github.com/medusajs/medusa/commit/f3bf351d21d1c2a67ed2d603c8b7ed4ae5cbd366), [`d61d6c7b7`](https://github.com/medusajs/medusa/commit/d61d6c7b7f8549996090f5315597d22d2af968f9), [`55a1f232a`](https://github.com/medusajs/medusa/commit/55a1f232a3746a22adb1fcd1844b2659077a59f9), [`53eda215e`](https://github.com/medusajs/medusa/commit/53eda215e00509eb63e571f1b38b9c8884b8e6d5), [`026bdab05`](https://github.com/medusajs/medusa/commit/026bdab05d4da054d3ffd07b8cce8ccb1bded95d), [`aefe5aa13`](https://github.com/medusajs/medusa/commit/aefe5aa133ea3ab98eb3c1ecd0ba51fb76c173de), [`966aea65c`](https://github.com/medusajs/medusa/commit/966aea65c221403bf316ae7665cc8f73bccd9c38), [`48ad2426a`](https://github.com/medusajs/medusa/commit/48ad2426aa7a604c226132e85ef3da5cce045f45)]: - - @medusajs/medusa@1.8.0-rc.0 - - @medusajs/medusa-js@2.0.0-rc.0 - -## 4.0.4 - -### Patch Changes - -- [#3144](https://github.com/medusajs/medusa/pull/3144) [`4fbf6b7ad`](https://github.com/medusajs/medusa/commit/4fbf6b7ad3198d9ddb712e60f3111de18b277676) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - fix(medusa-react): Fix production.min.js causing invalid hook usage error in CJS environments - -- Updated dependencies [[`ce866475b`](https://github.com/medusajs/medusa/commit/ce866475b4b6c8b453638000f7b1df7a27daf45d), [`53532df8d`](https://github.com/medusajs/medusa/commit/53532df8d597ed5471c07296981b6959cba4ddc3), [`d8ffbe25b`](https://github.com/medusajs/medusa/commit/d8ffbe25b047fda0f644240c9f518f95e74f03cb), [`2d525237b`](https://github.com/medusajs/medusa/commit/2d525237b682e89495b6cc8e3aa677bfad4d0726), [`5b63533c7`](https://github.com/medusajs/medusa/commit/5b63533c77528cab31755cedab9e768f7461f373), [`09dc9c667`](https://github.com/medusajs/medusa/commit/09dc9c6677c0d64cf765b27290e707ea75edd4aa), [`4105405f2`](https://github.com/medusajs/medusa/commit/4105405f28c3f3e54a6077c95a575a268fb5569f), [`ee42b60a2`](https://github.com/medusajs/medusa/commit/ee42b60a20db2afc5e9b6b958502f9e86ec37d80), [`d0adaf57e`](https://github.com/medusajs/medusa/commit/d0adaf57ed1018f29bebf01e5cffde5f7192f89f), [`f65f590a2`](https://github.com/medusajs/medusa/commit/f65f590a2771d6e526d7dfc7ca721be74c8f79a9), [`5ec6d438f`](https://github.com/medusajs/medusa/commit/5ec6d438fb1f909be925461c788f3a3a958528e4), [`5c1d2a5e8`](https://github.com/medusajs/medusa/commit/5c1d2a5e83c3654ae468d17c900892c32ef76060), [`8e41c6996`](https://github.com/medusajs/medusa/commit/8e41c6996601142661bde877b9ee1d80b8325f5f), [`d50db84a3`](https://github.com/medusajs/medusa/commit/d50db84a336da2de9c06a59aa79f2a5e9aa558f1), [`82da3605f`](https://github.com/medusajs/medusa/commit/82da3605fb50cef182699900552109ad654f0df2), [`b242e2232`](https://github.com/medusajs/medusa/commit/b242e22326ce74d5437d0da6863f22facbb5964c), [`4339d47e1`](https://github.com/medusajs/medusa/commit/4339d47e1f6c9f6c8f100b3ac72c8a394b6dd44d), [`2e7e16b91`](https://github.com/medusajs/medusa/commit/2e7e16b9173e2779946776b9b07ce7232c683f36), [`9ebb50104`](https://github.com/medusajs/medusa/commit/9ebb50104cc1f6c8ef1cea446ae595fb2eb532a2), [`08324355a`](https://github.com/medusajs/medusa/commit/08324355a4466b017a0bc7ab1d333ee3cd27b8c4), [`e22a383f4`](https://github.com/medusajs/medusa/commit/e22a383f4738e8bc80394ccaba3ac9a4ae678955), [`dc156861d`](https://github.com/medusajs/medusa/commit/dc156861d413ecfe3fd264bcd5ad736d83d8a08e), [`8f4c84121`](https://github.com/medusajs/medusa/commit/8f4c84121bd9b8c7067d72f03125e13afe4d2571), [`bfa33f444`](https://github.com/medusajs/medusa/commit/bfa33f444cd225906149777c5c6e842685f3dd7c), [`f776ed234`](https://github.com/medusajs/medusa/commit/f776ed234fcfccf23041ffebecbae6c9a8b7e922), [`be0d36432`](https://github.com/medusajs/medusa/commit/be0d36432a552b7a559f15916c5d9141980c95d1), [`4d6e63d68`](https://github.com/medusajs/medusa/commit/4d6e63d68f4e64c365ecbba133876d95e6528763), [`fcba70570`](https://github.com/medusajs/medusa/commit/fcba705701b8013183fafb39e8dda4a85718080a), [`4f0d8992a`](https://github.com/medusajs/medusa/commit/4f0d8992a091a05e93dd5be3762dfa47f074610e), [`d25a53104`](https://github.com/medusajs/medusa/commit/d25a531045143d3be68d3cd3b5764bbbc792ee3a), [`86c87c7b1`](https://github.com/medusajs/medusa/commit/86c87c7b1020ab6bb02f931e1ee113f2857cf527), [`78650ea66`](https://github.com/medusajs/medusa/commit/78650ea66517b0a77100228615d8122f84ad235b), [`b9bda3bf4`](https://github.com/medusajs/medusa/commit/b9bda3bf4e0f95675041085cea5008268c37edd5), [`e581d3bd9`](https://github.com/medusajs/medusa/commit/e581d3bd90f9bc40105e7eaf34e0c94d4f657f7a), [`4d3210bfb`](https://github.com/medusajs/medusa/commit/4d3210bfbb84877d951f7319d2e87c1acbdd6aad)]: - - @medusajs/medusa@1.7.6 - - @medusajs/medusa-js@1.3.8 - -## 4.0.3 - -### Patch Changes - -- [#3099](https://github.com/medusajs/medusa/pull/3099) [`6293fccc6`](https://github.com/medusajs/medusa/commit/6293fccc650411d27a9823a5f63f286d08ff2174) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - hotfix(medusa-react): Fixes an issue where queries weren't properly invalidated on successful mutations - -## 4.0.2 - -### Patch Changes - -- [#2969](https://github.com/medusajs/medusa/pull/2969) [`8d1275c94`](https://github.com/medusajs/medusa/commit/8d1275c94204e71986cb89a1273876662776939b) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - Udates the required version of the peer dependency `react-query` to `@tanstack/react-query` (v4). Also fixes ´react-query´ being defined as both a dependency and peer dependency. - -- [#3051](https://github.com/medusajs/medusa/pull/3051) [`150696de9`](https://github.com/medusajs/medusa/commit/150696de99fc852c5d72a746f168b6f62b2086ed) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - feat(medusa, medusa-js, medusa-react): Add endpoint to retrieve Product Tags through the Storefront API - -- [#3038](https://github.com/medusajs/medusa/pull/3038) [`cb2524400`](https://github.com/medusajs/medusa/commit/cb252440079f34ddfdfff1b891f6f73b98db9d59) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - hotfix: Fixes bundling error making JS client unable to run in Node enviornments. Also fixes wrong payload type of admin file uploads. - -- Updated dependencies [[`9dbccd9ca`](https://github.com/medusajs/medusa/commit/9dbccd9ca78b8b66f9a21947bb863622e7ff326b), [`542daeead`](https://github.com/medusajs/medusa/commit/542daeeadd78d939f5144c690e8907374da6d085), [`8c08d0031`](https://github.com/medusajs/medusa/commit/8c08d003198b94c00f8428a51c0e79d2ca9d1dc7), [`017538883`](https://github.com/medusajs/medusa/commit/017538883588792e1ff37abcab0fd2872c9af932), [`b2839e2e4`](https://github.com/medusajs/medusa/commit/b2839e2e4dc0d9344fa2ac8d4d16b796def4c56d), [`76d175231`](https://github.com/medusajs/medusa/commit/76d17523105d3860028a90a45b6038a64040e5ce), [`9e3beaf53`](https://github.com/medusajs/medusa/commit/9e3beaf5319dc785cf84b856cfcc8193df90c3a4), [`7d4b8b9cc`](https://github.com/medusajs/medusa/commit/7d4b8b9cc59672d01cdf0c6f331bc3d1eeec9bee), [`aab163bab`](https://github.com/medusajs/medusa/commit/aab163babb91759a05b852d34c299cdfac96d800), [`a0c4cfe0f`](https://github.com/medusajs/medusa/commit/a0c4cfe0f74cf30c45956c32c2fb22bf833bea68), [`27a29ef24`](https://github.com/medusajs/medusa/commit/27a29ef24e5ea1ba2bc0be8ecb7dd747d4c7c65b), [`aef842123`](https://github.com/medusajs/medusa/commit/aef8421235d8fff68d7d4f8b73f77484073311a5), [`1dc79590b`](https://github.com/medusajs/medusa/commit/1dc79590b3539af09dbc8fbf931d9b5ee225fb0d), [`9c4647383`](https://github.com/medusajs/medusa/commit/9c4647383ebf0a183ccc566636bcf7af06409060), [`a0c4cfe0f`](https://github.com/medusajs/medusa/commit/a0c4cfe0f74cf30c45956c32c2fb22bf833bea68), [`b80124d32`](https://github.com/medusajs/medusa/commit/b80124d32d950790c2a01b49e8c34d562b1d57f4), [`cb1ec0076`](https://github.com/medusajs/medusa/commit/cb1ec0076b4fd932c686d6027e8b060ceded3a64), [`142c8aa70`](https://github.com/medusajs/medusa/commit/142c8aa70f583d9b11a6add2b8f988e9ba4cf979), [`1547dd814`](https://github.com/medusajs/medusa/commit/1547dd8143889fc30045fc3d0241de8e69acb76e), [`d2c692aa9`](https://github.com/medusajs/medusa/commit/d2c692aa96ea89c053f9a694a9ae6dba77e89b14), [`150696de9`](https://github.com/medusajs/medusa/commit/150696de99fc852c5d72a746f168b6f62b2086ed), [`93d0dc1bd`](https://github.com/medusajs/medusa/commit/93d0dc1bdcb54cf6e87428a7bb9b0dac196b4de2), [`b3e4be720`](https://github.com/medusajs/medusa/commit/b3e4be72087d0b528c3cce322edf9325b855c8ae), [`cb2524400`](https://github.com/medusajs/medusa/commit/cb252440079f34ddfdfff1b891f6f73b98db9d59)]: - - @medusajs/medusa@1.7.4 - - @medusajs/medusa-js@1.3.7 - -## 4.0.1 - -### Patch Changes - -- [#2808](https://github.com/medusajs/medusa/pull/2808) [`0a9c89185`](https://github.com/medusajs/medusa/commit/0a9c891853c4d16b553d38268a3408ca1daa71f0) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - chore: explicitly add devDependencies for monorepo peerDependencies - -- Updated dependencies [[`7cced6006`](https://github.com/medusajs/medusa/commit/7cced6006a9a6f9108009e9f3e191e9f3ba1b168), [`463f83ffd`](https://github.com/medusajs/medusa/commit/463f83ffdd450d5325a57fe742b68bfb32ef1a42), [`17c3f34e3`](https://github.com/medusajs/medusa/commit/17c3f34e3df0a4c3656ad8909608331e207155f1), [`c16522d6c`](https://github.com/medusajs/medusa/commit/c16522d6ce806aa6289d626b868818409f41c66e), [`2e5ceb795`](https://github.com/medusajs/medusa/commit/2e5ceb795008fbf53d19bb79ac561561dd11311e), [`71b536e01`](https://github.com/medusajs/medusa/commit/71b536e01e32e3ab3fb5d295df9d67497a8bbe6d), [`9e05fef4b`](https://github.com/medusajs/medusa/commit/9e05fef4b973ceb60a2b975c839de96ca743597b), [`7bb9cd6af`](https://github.com/medusajs/medusa/commit/7bb9cd6aff1d832e6e159f2c878be88a054eddaa), [`3113d8024`](https://github.com/medusajs/medusa/commit/3113d8024fdeb09230675c2053fcefe811e575fd), [`e27b1940c`](https://github.com/medusajs/medusa/commit/e27b1940c7249e835404ac5490cf39e93053d2bb), [`5e4decbc1`](https://github.com/medusajs/medusa/commit/5e4decbc1c4cc25cb1adb1f63b2f8ea8669d352e), [`b700c6ba5`](https://github.com/medusajs/medusa/commit/b700c6ba5b323c7c5e200f721f0335f40b3e357a), [`8a60a7338`](https://github.com/medusajs/medusa/commit/8a60a73389c1b5c8abf96fbbcc7be7c4d427041d), [`ba6bb3e54`](https://github.com/medusajs/medusa/commit/ba6bb3e54b9989cecf476c7411c406a43562efe1), [`ea460b4e0`](https://github.com/medusajs/medusa/commit/ea460b4e0b1a9aa0fe1ab66bc21a8c40f76a65b3), [`c8724da50`](https://github.com/medusajs/medusa/commit/c8724da50300b94255c5fb4ffe9904be279b5923), [`8dcc805cc`](https://github.com/medusajs/medusa/commit/8dcc805ccf8da619549e77f009d6c4d7b2b6c99a), [`a027d5ff9`](https://github.com/medusajs/medusa/commit/a027d5ff9eb821a1c8728476e4f8bf5f4dd102c8)]: - - @medusajs/medusa@1.7.1 - - @medusajs/medusa-js@1.3.5 - -## 4.0.0 - -### Patch Changes - -- [#2771](https://github.com/medusajs/medusa/pull/2771) [`c2c38dd09`](https://github.com/medusajs/medusa/commit/c2c38dd091dd0938c8be63e515ccbc3158f72378) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - Adds appropriate optional type to several endpoint fields related to products. Also fixes the use of wrong payload type for `useAdminUpdateVariant` hook in `medusa-react`. - -- Updated dependencies [[`198fe78c1`](https://github.com/medusajs/medusa/commit/198fe78c138455f16d02406234fcfb05c4581372), [`72f70bc78`](https://github.com/medusajs/medusa/commit/72f70bc789e7c4a9df512745f7fc809595a3b503), [`e63777e3c`](https://github.com/medusajs/medusa/commit/e63777e3c52fe34ed502c3b0ceb82e3e1e993474), [`70a8d3450`](https://github.com/medusajs/medusa/commit/70a8d3450fb8551bb25a3e50be4ef74dc361c946), [`1b21af87a`](https://github.com/medusajs/medusa/commit/1b21af87ab80c18013f0f44434e59b873c2313aa), [`ed121922b`](https://github.com/medusajs/medusa/commit/ed121922b04e2e2af672fa6ab5ad69cd3cf17040), [`346461755`](https://github.com/medusajs/medusa/commit/3464617553770353a5d781caea8bdf880c72909f), [`e18b59de6`](https://github.com/medusajs/medusa/commit/e18b59de66ef52698d3f6b5ebec9f212a52fce02), [`42d9c7222`](https://github.com/medusajs/medusa/commit/42d9c7222b05ea231a920ea0694f6be8c13a956a), [`33aa3edb8`](https://github.com/medusajs/medusa/commit/33aa3edb805c217cf8e024af4c5be1835eb397dd), [`1dc816039`](https://github.com/medusajs/medusa/commit/1dc816039cdd332d50e3d979f78c5ee0f820db97), [`a6243618f`](https://github.com/medusajs/medusa/commit/a6243618fef5f9dd51ccba9e07e7849dd177202c), [`cb2a32a82`](https://github.com/medusajs/medusa/commit/cb2a32a82b2a4d89e57a120262a9eee002ee29a9), [`c2c38dd09`](https://github.com/medusajs/medusa/commit/c2c38dd091dd0938c8be63e515ccbc3158f72378), [`424efff91`](https://github.com/medusajs/medusa/commit/424efff91943dad3982b44a8549e828678c3e1b4), [`b2ea8b7d4`](https://github.com/medusajs/medusa/commit/b2ea8b7d45e91f671cd8c20fe9270c0e9c5f94cc), [`b5d6682db`](https://github.com/medusajs/medusa/commit/b5d6682db66a7e4f6729c24fbec075a2faef87c4), [`d68e81fb3`](https://github.com/medusajs/medusa/commit/d68e81fb3df116af70738eef93e227f41b72d80b)]: - - @medusajs/medusa@1.7.0 - -## 3.0.1 - -### Patch Changes - -- [#2552](https://github.com/medusajs/medusa/pull/2552) [`7b0ceeffb`](https://github.com/medusajs/medusa/commit/7b0ceeffb4616c3f4e0cf51aba2ab381c61ea5d7) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(medusa, medusa-js, medusa-react): /store api product types - -- Updated dependencies [[`2d095a0ce`](https://github.com/medusajs/medusa/commit/2d095a0ce14ab7f24b4e6856cb4850cea18af21c), [`8069ed5e9`](https://github.com/medusajs/medusa/commit/8069ed5e99dc53a912df9bb860114d2258044108), [`7b0ceeffb`](https://github.com/medusajs/medusa/commit/7b0ceeffb4616c3f4e0cf51aba2ab381c61ea5d7), [`5ea4b728e`](https://github.com/medusajs/medusa/commit/5ea4b728e728a7e6d4d6fe7255ea80395ab75bd3)]: - - @medusajs/medusa@1.6.2 - - @medusajs/medusa-js@1.3.3 - -## 3.0.0 - -### Patch Changes - -- [#2433](https://github.com/medusajs/medusa/pull/2433) [`3c5e31c64`](https://github.com/medusajs/medusa/commit/3c5e31c6455695f854e9df7a3592c12b899fa1e1) Thanks [@pKorsholm](https://github.com/pKorsholm)! - Add protected uploads to fileservices - -* [#2430](https://github.com/medusajs/medusa/pull/2430) [`765a2cccd`](https://github.com/medusajs/medusa/commit/765a2cccda2c4c552ede9ec23e0c1e3dd4ea44fc) Thanks [@adrien2p](https://github.com/adrien2p)! - Feat(medusa, medusa-js, medusa-react): add resources to discount condition by batch - -- [#2444](https://github.com/medusajs/medusa/pull/2444) [`48411157b`](https://github.com/medusajs/medusa/commit/48411157b1cdec0a67f91e06de8ac547af89d7af) Thanks [@adrien2p](https://github.com/adrien2p)! - feat(medusa): Support batch remove resources on discount condition - -- Updated dependencies [[`211720f24`](https://github.com/medusajs/medusa/commit/211720f24cbcb1f01c36aa35660e1ff0c4518ebd), [`c71744245`](https://github.com/medusajs/medusa/commit/c717442451cf9fc2e0961edded5b49ea5a78760e), [`3c5e31c64`](https://github.com/medusajs/medusa/commit/3c5e31c6455695f854e9df7a3592c12b899fa1e1), [`13611e3e5`](https://github.com/medusajs/medusa/commit/13611e3e53d449fbfab7a88f848f6652a360bd14), [`765a2cccd`](https://github.com/medusajs/medusa/commit/765a2cccda2c4c552ede9ec23e0c1e3dd4ea44fc), [`69e579758`](https://github.com/medusajs/medusa/commit/69e579758f81332094d6f0dfa6fbcbc359b0d92c), [`05f921711`](https://github.com/medusajs/medusa/commit/05f921711fb0ac3603d29955648d8ba563a7da7d), [`19ca18e71`](https://github.com/medusajs/medusa/commit/19ca18e71c8feea7277e09db3c5e9e6316adb6ab), [`a9c703d56`](https://github.com/medusajs/medusa/commit/a9c703d56c2678fb509af7f9e1fe2cb65f95ba9d), [`58c7ffdc6`](https://github.com/medusajs/medusa/commit/58c7ffdc6ec1d06f76aaa9427505dc452398770f), [`9deec0fc3`](https://github.com/medusajs/medusa/commit/9deec0fc3c3ff9d89ca194b8b05948141799a412), [`299c4ae7f`](https://github.com/medusajs/medusa/commit/299c4ae7f55b0586f283d7f21792b7b204df421a), [`48411157b`](https://github.com/medusajs/medusa/commit/48411157b1cdec0a67f91e06de8ac547af89d7af), [`144ce0e42`](https://github.com/medusajs/medusa/commit/144ce0e42cd894a2cd5b40b68c095fd1eda851a9), [`8be67c734`](https://github.com/medusajs/medusa/commit/8be67c734c970ef03bf0afaf74cc3818e305466d)]: - - @medusajs/medusa@1.6.0 - - @medusajs/medusa-js@1.3.2 - -## 2.0.0 - -### Patch Changes - -- [#2276](https://github.com/medusajs/medusa/pull/2276) [`678a06752`](https://github.com/medusajs/medusa/commit/678a06752a03f71d77265a874fd7d07361337862) Thanks [@adrien2p](https://github.com/adrien2p)! - Finalise service migration and fix super constructor arguments - -* [#2353](https://github.com/medusajs/medusa/pull/2353) [`642902aae`](https://github.com/medusajs/medusa/commit/642902aaeb25144e59177c178f09fb8398951357) Thanks [@pKorsholm](https://github.com/pKorsholm)! - feat(medusa-js, medusa-react): add expand fields to get order - -* Updated dependencies [[`6132711ee`](https://github.com/medusajs/medusa/commit/6132711eef797219f1b93e4bc4bdb1dd47655308), [`d2b272fab`](https://github.com/medusajs/medusa/commit/d2b272fab649bb272b8af4f2f00aafe89965995e), [`7dc8d3a0c`](https://github.com/medusajs/medusa/commit/7dc8d3a0c90ce06e3f11a6a46dec1f9ec3f26e81), [`3d255302b`](https://github.com/medusajs/medusa/commit/3d255302b022a06b492807774412b1db05fa8d06), [`678a06752`](https://github.com/medusajs/medusa/commit/678a06752a03f71d77265a874fd7d07361337862), [`d8a5942d3`](https://github.com/medusajs/medusa/commit/d8a5942d3d85671e2923668bdbf2867957f5554b), [`edd35631f`](https://github.com/medusajs/medusa/commit/edd35631f722009bdcb2439ff8c2326025425d33), [`df62e618b`](https://github.com/medusajs/medusa/commit/df62e618bcc365ef376b96705d63b465b48b0191), [`3f7317028`](https://github.com/medusajs/medusa/commit/3f7317028808cd3c1b44cb7b66694501a7c706c4), [`642902aae`](https://github.com/medusajs/medusa/commit/642902aaeb25144e59177c178f09fb8398951357)]: - - @medusajs/medusa-js@1.3.1 - - @medusajs/medusa@1.5.0 - -## 1.0.0 - -### Minor Changes - -- [#2185](https://github.com/medusajs/medusa/pull/2185) [`64949dc72`](https://github.com/medusajs/medusa/commit/64949dc721a6c697e3eb7091db9f2d261111a766) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - Adds missing response types for currency endpoints and exports route. Adds currency endpoints to medusa-js and medusa-react. - -### Patch Changes - -- Updated dependencies [[`64949dc72`](https://github.com/medusajs/medusa/commit/64949dc721a6c697e3eb7091db9f2d261111a766), [`b6161d240`](https://github.com/medusajs/medusa/commit/b6161d24043b8b910320475b8616b7e29a96f6cd), [`af80e0fd2`](https://github.com/medusajs/medusa/commit/af80e0fd2ed75cd3c15282ddcbfb949060dfdd33)]: - - @medusajs/medusa@1.4.0 - - @medusajs/medusa-js@1.3.0 - -## 0.3.6 - -### Patch Changes - -- [#1959](https://github.com/medusajs/medusa/pull/1959) [`2a723dcd4`](https://github.com/medusajs/medusa/commit/2a723dcd4fb0074e7d34286c231ef248e907b1c4) Thanks [@richardwardza](https://github.com/richardwardza)! - Add Collection batch (remove, add) endpoints to medusa-react - -- Updated dependencies [[`15a5b029a`](https://github.com/medusajs/medusa/commit/15a5b029ae3bd954481c558beeac87ace7ab945d), [`900260c5b`](https://github.com/medusajs/medusa/commit/900260c5b9df4f4f927db5bb6921e5e139ff269a), [`42ed20951`](https://github.com/medusajs/medusa/commit/42ed209518bf0278d1bef3c4c47d0ee21cae84c8), [`8cbebef40`](https://github.com/medusajs/medusa/commit/8cbebef403a5ac5def1f95b2e591991cfa90b7fb), [`a54dc68db`](https://github.com/medusajs/medusa/commit/a54dc68db7a7d476cf4bf8d36c122c7f34629c90), [`aaebb38ea`](https://github.com/medusajs/medusa/commit/aaebb38eae883a225779b03556900ea813c991d2), [`9e0cb1212`](https://github.com/medusajs/medusa/commit/9e0cb1212023d7035165ddd269edab3efc7ebe29), [`c97ccd3fb`](https://github.com/medusajs/medusa/commit/c97ccd3fb5dbe796b0e4fbf37def5bb6e8201557), [`152934f8b`](https://github.com/medusajs/medusa/commit/152934f8b07cb3095788091df6823f9665fdf43d), [`8c4be3353`](https://github.com/medusajs/medusa/commit/8c4be3353630efd18759eb893666e44b1b49e2b7), [`bda83a84b`](https://github.com/medusajs/medusa/commit/bda83a84bc99a4741da2076f59071c177bc5534f), [`11fab121f`](https://github.com/medusajs/medusa/commit/11fab121f4c4b5ec3b6a3afccd4c44844bc5e3d9), [`40ae53567`](https://github.com/medusajs/medusa/commit/40ae53567a23ebe562e571fa22f1721eed174c82), [`80e02130b`](https://github.com/medusajs/medusa/commit/80e02130b4a444287920989654b607f07dd8d4f8), [`c31290c91`](https://github.com/medusajs/medusa/commit/c31290c911450a06d5e4da3dc5e4e3977071a6ea), [`4b663cca3`](https://github.com/medusajs/medusa/commit/4b663cca3acf43b0e02a1fb94b8d4f14913bfe45), [`a88bf3c76`](https://github.com/medusajs/medusa/commit/a88bf3c76ea801d2b17227fb2eb8b8d8dbfe1262)]: - - @medusajs/medusa@1.3.6 - - @medusajs/medusa-js@1.2.6 - -## 0.3.5 - -### Patch Changes - -- [#1914](https://github.com/medusajs/medusa/pull/1914) [`1dec44287`](https://github.com/medusajs/medusa/commit/1dec44287df5ac69b4c5769b59f9ebef58d3da68) Thanks [@fPolic](https://github.com/fPolic)! - Version bump due to missing changesets in merged PRs - -- Updated dependencies [[`1dec44287`](https://github.com/medusajs/medusa/commit/1dec44287df5ac69b4c5769b59f9ebef58d3da68), [`8c283ac3b`](https://github.com/medusajs/medusa/commit/8c283ac3b03dea09203ac1b4c8d806efbc092290), [`b8ddb31f6`](https://github.com/medusajs/medusa/commit/b8ddb31f6fe296a11d2d988276ba8e991c37fa9b), [`dafbfa779`](https://github.com/medusajs/medusa/commit/dafbfa7799410a95f9a1ca02d1db718d1f8693eb), [`df6637853`](https://github.com/medusajs/medusa/commit/df66378535727152bb329c71c38d614e5b642599), [`716297231`](https://github.com/medusajs/medusa/commit/71629723185739a97fc2cf8eaa9029f7963bb120), [`0e0b13148`](https://github.com/medusajs/medusa/commit/0e0b13148892b073a1b46900c6eb1b0d8e05cc37), [`c148064b4`](https://github.com/medusajs/medusa/commit/c148064b4abdc4447d8216a6de0a6ce84e3a061c)]: - - @medusajs/medusa@1.3.5 - - @medusajs/medusa-js@1.2.4 - -## 0.3.4 - -### Patch Changes - -- [#1832](https://github.com/medusajs/medusa/pull/1832) [`fb4cfc3c`](https://github.com/medusajs/medusa/commit/fb4cfc3c3c190d54202a3719017e67a895870a4d) Thanks [@kasperkristensen](https://github.com/kasperkristensen)! - Fixes useAdminCreateDraftOrder so it uses the correct payload type, and updates relevant test. - -- Updated dependencies [[`3e197e3a`](https://github.com/medusajs/medusa/commit/3e197e3adf0bcd39cdcf30c7dda381cc4b7ac779), [`39f2c0c1`](https://github.com/medusajs/medusa/commit/39f2c0c15ee05b5b6941ea2ef16f0b4b1512ce4f), [`4d15e01c`](https://github.com/medusajs/medusa/commit/4d15e01c3ebbc341113505d3c2f60c0e082943ae), [`fb82d3dd`](https://github.com/medusajs/medusa/commit/fb82d3dd221efeba5b0110bd00908faecbdb30d7)]: - - @medusajs/medusa@1.3.4 - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [0.3.3](https://github.com/medusajs/medusa/compare/medusa-react@0.3.2...medusa-react@0.3.3) (2022-07-05) - -### Bug Fixes - -- **medusa-react:** Allow to not invalidate any cache ([#1756](https://github.com/medusajs/medusa/issues/1756)) ([9e0f65d](https://github.com/medusajs/medusa/commit/9e0f65dee3b3329eb4eabe093f44a8e3b7d6e820)) - -### Features - -- **medusa,medusa-js,medusa-react:** Add BatchJob API support in `medusa-js` + `medusa-react` ([#1704](https://github.com/medusajs/medusa/issues/1704)) ([7302d76](https://github.com/medusajs/medusa/commit/7302d76e12683c989f340d2fcfaf4338dca6554a)) - -## [0.3.2](https://github.com/medusajs/medusa/compare/medusa-react@0.3.0...medusa-react@0.3.2) (2022-06-19) - -### Bug Fixes - -- **medusa-react:** Invalidate price list product cache on various price list updates ([#1503](https://github.com/medusajs/medusa/issues/1503)) ([79345d2](https://github.com/medusajs/medusa/commit/79345d27ec9a56fac3d49197ee9a785f24bfbad7)) -- **medusa-react:** useUpdatePaymentSession mutation ([#1522](https://github.com/medusajs/medusa/issues/1522)) ([b02f265](https://github.com/medusajs/medusa/commit/b02f2652be494b63e55b3720cdafa0d934737f72)) - -### Features - -- **medusa:** Add endpoint for retrieving a DiscountCondition ([#1525](https://github.com/medusajs/medusa/issues/1525)) ([a87e1cd](https://github.com/medusajs/medusa/commit/a87e1cdf6558fd56bd91540853ca0bb715eda46e)) -- **medusa:** Add endpoints specific to DiscountConditions ([#1355](https://github.com/medusajs/medusa/issues/1355)) ([9ca45ea](https://github.com/medusajs/medusa/commit/9ca45ea492e755a88737322f900d60abdfa64024)) -- **medusa:** Support deleting prices from a price list by product or variant ([#1555](https://github.com/medusajs/medusa/issues/1555)) ([fa031fd](https://github.com/medusajs/medusa/commit/fa031fd28be8b12ff38eaec6e56c373324e0beed)) - -## [0.3.1](https://github.com/medusajs/medusa/compare/medusa-react@0.3.0...medusa-react@0.3.1) (2022-05-31) - -### Bug Fixes - -- **medusa-react:** Invalidate price list product cache on various price list updates ([#1503](https://github.com/medusajs/medusa/issues/1503)) ([79345d2](https://github.com/medusajs/medusa/commit/79345d27ec9a56fac3d49197ee9a785f24bfbad7)) -- **medusa-react:** useUpdatePaymentSession mutation ([#1522](https://github.com/medusajs/medusa/issues/1522)) ([b02f265](https://github.com/medusajs/medusa/commit/b02f2652be494b63e55b3720cdafa0d934737f72)) - -### Features - -- **medusa:** Add endpoint for retrieving a DiscountCondition ([#1525](https://github.com/medusajs/medusa/issues/1525)) ([a87e1cd](https://github.com/medusajs/medusa/commit/a87e1cdf6558fd56bd91540853ca0bb715eda46e)) -- **medusa:** Add endpoints specific to DiscountConditions ([#1355](https://github.com/medusajs/medusa/issues/1355)) ([9ca45ea](https://github.com/medusajs/medusa/commit/9ca45ea492e755a88737322f900d60abdfa64024)) -- **medusa:** Support deleting prices from a price list by product or variant ([#1555](https://github.com/medusajs/medusa/issues/1555)) ([fa031fd](https://github.com/medusajs/medusa/commit/fa031fd28be8b12ff38eaec6e56c373324e0beed)) - -# [0.3.0](https://github.com/medusajs/medusa/compare/medusa-react@0.2.1...medusa-react@0.3.0) (2022-05-01) - -### Bug Fixes - -- **medusa:** Remove unsupported Discount endpoints ([#1367](https://github.com/medusajs/medusa/issues/1367)) ([9acee27](https://github.com/medusajs/medusa/commit/9acee2799ead683575edd0f7172f336878569dfe)) -- `CustomerGroups` missing features in the clients ([#1159](https://github.com/medusajs/medusa/issues/1159)) ([218b20b](https://github.com/medusajs/medusa/commit/218b20b26db46f0a91736ece2530a83fa94aed97)) -- query key ([#1350](https://github.com/medusajs/medusa/issues/1350)) ([95ea8fa](https://github.com/medusajs/medusa/commit/95ea8fa38526b64989a1b22c015a9f129fb64b4c)) - -### Features - -- customer group customers client endpoints ([#1221](https://github.com/medusajs/medusa/issues/1221)) ([b7f6996](https://github.com/medusajs/medusa/commit/b7f699654bd8c5b08919667d4e29c835901e1af9)) -- customer groups react hooks ([#1153](https://github.com/medusajs/medusa/issues/1153)) ([daf49bc](https://github.com/medusajs/medusa/commit/daf49bcaf31e6e86cfd13a24efd5b3de626617a4)) - -## [0.2.1](https://github.com/medusajs/medusa/compare/medusa-react@0.1.5...medusa-react@0.2.1) (2022-02-28) - -### Bug Fixes - -- use /admin/returns/:id/receive for swap returns ([#1041](https://github.com/medusajs/medusa/issues/1041)) ([7a3a183](https://github.com/medusajs/medusa/commit/7a3a1837a1db067c3629f1dfd7c6a95a56d649ca)) - -### Features - -- new tax api ([#979](https://github.com/medusajs/medusa/issues/979)) ([47588e7](https://github.com/medusajs/medusa/commit/47588e7a8d3b2ae2fed0c1e87fdf1ee2db6bcdc2)), closes [#885](https://github.com/medusajs/medusa/issues/885) [#896](https://github.com/medusajs/medusa/issues/896) [#911](https://github.com/medusajs/medusa/issues/911) [#945](https://github.com/medusajs/medusa/issues/945) [#950](https://github.com/medusajs/medusa/issues/950) [#951](https://github.com/medusajs/medusa/issues/951) [#954](https://github.com/medusajs/medusa/issues/954) [#969](https://github.com/medusajs/medusa/issues/969) [#998](https://github.com/medusajs/medusa/issues/998) [#1017](https://github.com/medusajs/medusa/issues/1017) [#1110](https://github.com/medusajs/medusa/issues/1110) - -# [0.2.0](https://github.com/medusajs/medusa/compare/medusa-react@0.1.5...medusa-react@0.2.0) (2022-02-25) - -### Bug Fixes - -- use /admin/returns/:id/receive for swap returns ([#1041](https://github.com/medusajs/medusa/issues/1041)) ([7ae754b](https://github.com/medusajs/medusa/commit/7ae754bb6187db17c45b2cfadc625df8f997f5ab)) - -### Features - -- new tax api ([#979](https://github.com/medusajs/medusa/issues/979)) ([c56660f](https://github.com/medusajs/medusa/commit/c56660fca9921a3f3637bc137d9794781c5b090f)), closes [#885](https://github.com/medusajs/medusa/issues/885) [#896](https://github.com/medusajs/medusa/issues/896) [#911](https://github.com/medusajs/medusa/issues/911) [#945](https://github.com/medusajs/medusa/issues/945) [#950](https://github.com/medusajs/medusa/issues/950) [#951](https://github.com/medusajs/medusa/issues/951) [#954](https://github.com/medusajs/medusa/issues/954) [#969](https://github.com/medusajs/medusa/issues/969) [#998](https://github.com/medusajs/medusa/issues/998) [#1017](https://github.com/medusajs/medusa/issues/1017) [#1110](https://github.com/medusajs/medusa/issues/1110) - -## [0.1.5](https://github.com/medusajs/medusa/compare/medusa-react@0.1.4...medusa-react@0.1.5) (2022-02-06) - -### Bug Fixes - -- release ([fc3fbc8](https://github.com/medusajs/medusa/commit/fc3fbc897fad5c8a5d3eea828ac7277fba9d70af)) - -## [0.1.4](https://github.com/medusajs/medusa/compare/medusa-react@0.1.3...medusa-react@0.1.4) (2022-02-06) - -### Bug Fixes - -- adds order by functionality to products ([#1021](https://github.com/medusajs/medusa/issues/1021)) ([3bf32e5](https://github.com/medusajs/medusa/commit/3bf32e5dc9ad3150762b9bb744b0453d3640e204)) - -### Features - -- medusa-react admin hooks ([#978](https://github.com/medusajs/medusa/issues/978)) ([2e38484](https://github.com/medusajs/medusa/commit/2e384842d5b2e9742a86b96f28a8f00357795b86)), closes [#1019](https://github.com/medusajs/medusa/issues/1019) - -## [0.1.3](https://github.com/medusajs/medusa/compare/medusa-react@0.1.2...medusa-react@0.1.3) (2022-01-11) - -**Note:** Version bump only for package medusa-react - -## [0.1.2](https://github.com/medusajs/medusa/compare/medusa-react@0.1.1...medusa-react@0.1.2) (2021-12-29) - -**Note:** Version bump only for package medusa-react - -## 0.1.1 (2021-12-17) - -### Features - -- add medusa-react ([#913](https://github.com/medusajs/medusa/issues/913)) ([d0d8dd7](https://github.com/medusajs/medusa/commit/d0d8dd7bf62eaac71df8714c2dfb4f204d192f51)) -- medusa-js admin return reasons ([#931](https://github.com/medusajs/medusa/issues/931)) ([0acc462](https://github.com/medusajs/medusa/commit/0acc462e1ebe51368ceedeea85d6f51c6fc3bfc4)) diff --git a/packages/medusa-react/LICENSE b/packages/medusa-react/LICENSE deleted file mode 100644 index b48e847983..0000000000 --- a/packages/medusa-react/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Zakaria S. El Asri - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/packages/medusa-react/README.md b/packages/medusa-react/README.md deleted file mode 100644 index 62e88b9c86..0000000000 --- a/packages/medusa-react/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Medusa React - -A React library providing a set of components, utilities, and hooks for interacting seamlessly with a Medusa backend and building custom React storefronts. - -Learn how to install and use it in [this documentation](https://docs.medusajs.com/medusa-react/overview). diff --git a/packages/medusa-react/jest.config.js b/packages/medusa-react/jest.config.js deleted file mode 100644 index edff5a3d01..0000000000 --- a/packages/medusa-react/jest.config.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - globals: { - "ts-jest": { - diagnostics: false, - isolatedModules: true, - }, - }, - transform: { - ".(ts|tsx)$": require.resolve("ts-jest/dist/"), - }, - setupFilesAfterEnv: ["./jest.setup.js"], - testEnvironment: "jsdom", - moduleNameMapper: { - // Force module uuid to resolve with the CJS entry point, because Jest does not support package.json.exports. See https://github.com/uuidjs/uuid/issues/451 - // Issue is fixed in newer versions of UUID, but since it's a transitive dependency, we need to force it here. - "^uuid$": "uuid", - }, -} diff --git a/packages/medusa-react/jest.setup.js b/packages/medusa-react/jest.setup.js deleted file mode 100644 index 897487523f..0000000000 --- a/packages/medusa-react/jest.setup.js +++ /dev/null @@ -1,45 +0,0 @@ -const { server } = require("./mocks/server") - -const originalError = console.error - -beforeAll(() => { - server.listen({ - onUnhandledRequest: (req) => { - console.log("found an error") - console.log(req) - }, - }) - - /** - * We are currently using a deprecated library for testing - `@testing-library/react-hooks`. - * This library uses `ReactDOM.render` which is deprecated in React 18. This is a temporary - * fix to silence the warning. - * - * TODO: Replace the usage of `@testing-library/react-hooks` with - * the latest `@testing-library/react` and remove this fix. - */ - console.error = (...args) => { - if ( - /Warning: ReactDOM.render is no longer supported in React 18./.test( - args[0] - ) - ) { - return - } - originalError.call(console, ...args) - } -}) - -beforeEach(() => { - window.localStorage.clear() -}) - -afterEach(() => { - server.resetHandlers() - window.localStorage.clear() -}) - -afterAll(() => { - server.close() - console.error = originalError -}) diff --git a/packages/medusa-react/mocks/data/fixtures.json b/packages/medusa-react/mocks/data/fixtures.json deleted file mode 100644 index 41f9eab163..0000000000 --- a/packages/medusa-react/mocks/data/fixtures.json +++ /dev/null @@ -1,1447 +0,0 @@ -{ - "resources": { - "currency": { - "symbol": "$", - "name": "US Dollar", - "symbol_native": "$", - "code": "USD", - "includes_tax": false - }, - "region": { - "id": "reg_01F0YES4R67TXXC1QBQ8P54A8Y", - "name": "Test Region", - "currency_code": "usd", - "tax_rate": 0, - "tax_code": null, - "countries": [ - { - "id": 236, - "iso_2": "us", - "iso_3": "usa", - "num_code": 840, - "name": "UNITED STATES", - "display_name": "United States", - "region_id": "region" - } - ], - "payment_providers": [], - "fulfillment_providers": [ - { - "id": "test-ful", - "is_installed": true - } - ], - "created_at": "2021-03-16T21:24:00.389Z", - "updated_at": "2021-03-16T21:24:00.389Z", - "deleted_at": null, - "metadata": null - }, - "shipping_option": { - "id": "so_01F0YES4T6ZHH52Z4KZEDT1312", - "name": "Free Shipping", - "region_id": "reg_01F0YES4R67TXXC1QBQ8P54A8Y", - "region": { - "id": "reg_01F0YES4R67TXXC1QBQ8P54A8Y", - "name": "Test Region", - "currency_code": "usd", - "tax_rate": "0", - "tax_code": null, - "payment_providers": [], - "fulfillment_providers": [ - { - "id": "test-ful", - "is_installed": true - } - ], - "created_at": "2021-03-16T21:24:00.389Z", - "updated_at": "2021-03-16T21:24:00.389Z", - "deleted_at": null, - "metadata": null - }, - "profile_id": "sp_01F0YES4Q77FGG18GPFWW5BZP9", - "profile": { - "id": "sp_01F0YES4Q77FGG18GPFWW5BZP9", - "name": "Default Shipping Profile", - "type": "default", - "created_at": "2021-03-16T21:24:00.307Z", - "updated_at": "2021-03-16T21:24:00.307Z", - "deleted_at": null, - "metadata": null - }, - "provider_id": "test-ful", - "price_type": "flat_rate", - "amount": 100, - "is_return": false, - "requirements": [], - "data": {}, - "created_at": "2021-03-16T21:24:00.439Z", - "updated_at": "2021-03-16T21:24:00.439Z", - "deleted_at": null, - "metadata": null - }, - "cart": { - "id": "cart_01F0YES82DA12W88KQ90EY6W4C", - "email": null, - "type": "default", - "payment_session": null, - "customer": null, - "billing_address_id": null, - "billing_address": null, - "payment_authorized_at": null, - "shipping_address_id": "addr_01F0YES82D4Y16JKGF0NFSSS3P", - "shipping_address": { - "id": "addr_01F0YES82D4Y16JKGF0NFSSS3P", - "customer_id": null, - "company": null, - "first_name": null, - "last_name": null, - "address_1": null, - "address_2": null, - "city": null, - "country_code": "us", - "province": null, - "postal_code": null, - "phone": null, - "created_at": "2021-03-16T21:24:03.766Z", - "updated_at": "2021-03-16T21:24:03.766Z", - "deleted_at": null, - "metadata": null - }, - "items": [], - "region_id": "region", - "region": { - "id": "region", - "name": "Test Region", - "currency_code": "usd", - "tax_rate": "0", - "tax_code": null, - "countries": [ - { - "id": 236, - "iso_2": "us", - "iso_3": "usa", - "num_code": 840, - "name": "UNITED STATES", - "display_name": "United States", - "region_id": "region" - } - ], - "payment_providers": [], - "fulfillment_providers": [], - "created_at": "2021-03-16T21:24:03.743Z", - "updated_at": "2021-03-16T21:24:03.743Z", - "deleted_at": null, - "metadata": null - }, - "discounts": [], - "gift_cards": [], - "customer_id": null, - "payment_sessions": [], - "payment_id": null, - "payment": null, - "shipping_methods": [], - "completed_at": null, - "created_at": "2021-03-16T21:24:03.766Z", - "updated_at": "2021-03-16T21:24:03.857Z", - "deleted_at": null, - "metadata": null, - "idempotency_key": null, - "context": { - "ip": "::ffff:127.0.0.1", - "user_agent": "axios/0.21.1" - }, - "shipping_total": 0, - "discount_total": 0, - "tax_total": 0, - "gift_card_total": 0, - "subtotal": 0, - "total": 0 - }, - "product_collection": { - "id": "pcol_01F0YESBFAZ0DV6V831JXWH0BG", - "title": "Summer Collection", - "handle": "summer-collection", - "created_at": "2021-03-16T21:24:07.273Z", - "updated_at": "2021-03-16T21:24:07.273Z", - "deleted_at": null, - "metadata": null - }, - "gift_card": { - "id": "gift_01F0YESEKYJ5578VCAPV4XYFDP", - "code": "1J3U-WXO0-SZ0H-O5QU", - "value": 1000, - "balance": 1000, - "region_id": "reg_01F0YESEJP4H8Q517XSPGK6TD6", - "region": { - "id": "reg_01F0YESEJP4H8Q517XSPGK6TD6", - "name": "Test Region", - "currency_code": "usd", - "tax_rate": "0", - "tax_code": null, - "payment_providers": [], - "fulfillment_providers": [], - "created_at": "2021-03-16T21:24:10.454Z", - "updated_at": "2021-03-16T21:24:10.454Z", - "deleted_at": null, - "metadata": null - }, - "is_disabled": false, - "ends_at": null, - "created_at": "2021-03-16T21:24:10.484Z", - "updated_at": "2021-03-16T21:24:10.484Z", - "deleted_at": null, - "metadata": null - }, - "product": { - "id": "prod_01F0YESHQ27Y31CAMD0NV6W9YP", - "title": "Test product", - "subtitle": null, - "description": "test-product-description", - "handle": "test-product", - "is_giftcard": false, - "images": [], - "thumbnail": null, - "options": [ - { - "id": "opt_01F0YESHQBZVKCEXJ24BS6PCX3", - "title": "size", - "product_id": "prod_01F0YESHQ27Y31CAMD0NV6W9YP", - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - }, - { - "id": "opt_01F0YESHQBV8MMNN4V7WSDMH6G", - "title": "color", - "product_id": "prod_01F0YESHQ27Y31CAMD0NV6W9YP", - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - } - ], - "variants": [ - { - "id": "variant_01F0YESHR7P2YAYBDBY5B6X3PK", - "title": "Test variant", - "product_id": "prod_01F0YESHQ27Y31CAMD0NV6W9YP", - "product": { - "id": "prod_01F0YESHQ27Y31CAMD0NV6W9YP", - "title": "Test product", - "subtitle": null, - "description": "test-product-description", - "handle": "test-product", - "is_giftcard": false, - "thumbnail": null, - "profile_id": "sp_01F0YESHMKRB4V3B7F6MVQHGNN", - "weight": null, - "length": null, - "height": null, - "width": null, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "collection_id": "test-collection", - "type_id": "test-type", - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - }, - "prices": [ - { - "id": "ma_01F0YESHRFQNH5S8Q0PK84YYZN", - "currency_code": "usd", - "amount": 100, - "sale_amount": null, - "variant_id": "variant_01F0YESHR7P2YAYBDBY5B6X3PK", - "region_id": null, - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null - } - ], - "sku": null, - "barcode": null, - "ean": null, - "upc": null, - "inventory_quantity": 10, - "allow_backorder": false, - "manage_inventory": true, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "weight": null, - "length": null, - "height": null, - "width": null, - "options": [ - { - "id": "optval_01F0YESHR7S6ECD03RF6W12DSJ", - "value": "large", - "option_id": "opt_01F0YESHQBZVKCEXJ24BS6PCX3", - "variant_id": "variant_01F0YESHR7P2YAYBDBY5B6X3PK", - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - }, - { - "id": "optval_01F0YESHR7N2GHM1RN3GKYPN6P", - "value": "green", - "option_id": "opt_01F0YESHQBV8MMNN4V7WSDMH6G", - "variant_id": "variant_01F0YESHR7P2YAYBDBY5B6X3PK", - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - } - ], - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - } - ], - "profile_id": "sp_01F0YESHMKRB4V3B7F6MVQHGNN", - "weight": null, - "length": null, - "height": null, - "width": null, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "collection_id": "test-collection", - "collection": { - "id": "test-collection", - "title": "Test collection", - "handle": null, - "created_at": "2021-03-16T21:24:13.603Z", - "updated_at": "2021-03-16T21:24:13.603Z", - "deleted_at": null, - "metadata": null - }, - "type_id": "test-type", - "type": { - "id": "test-type", - "value": "test-type", - "created_at": "2021-03-16T21:24:13.613Z", - "updated_at": "2021-03-16T21:24:13.613Z", - "deleted_at": null, - "metadata": null - }, - "tags": [ - { - "id": "tag1", - "value": "123", - "created_at": "2021-03-16T21:24:13.609Z", - "updated_at": "2021-03-16T21:24:13.609Z", - "deleted_at": null, - "metadata": null - }, - { - "id": "ptag_01F0YESHPZYY3H4SJ3A5918SBN", - "value": "456", - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - } - ], - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "metadata": null - }, - "product_category": { - "id": "pcat_01F0YESBFAZ0DV6V831JXWH0BG", - "name": "Skinny Jeans", - "handle": "skinny-jeans", - "created_at": "2021-03-16T21:24:07.273Z", - "updated_at": "2021-03-16T21:24:07.273Z", - "deleted_at": null - }, - "product_variant": { - "id": "variant_01F0YESHR7P2YAYBDBY5B6X3PK", - "title": "Test variant", - "product_id": "prod_01F0YESHQ27Y31CAMD0NV6W9YP", - "variant_rank": 0, - "product": { - "id": "prod_01F0YESHQ27Y31CAMD0NV6W9YP", - "title": "Test product", - "subtitle": null, - "description": "test-product-description", - "handle": "test-product", - "is_giftcard": false, - "thumbnail": null, - "profile_id": "sp_01F0YESHMKRB4V3B7F6MVQHGNN", - "weight": null, - "length": null, - "height": null, - "width": null, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "collection_id": "test-collection", - "type_id": "test-type", - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - }, - "prices": [ - { - "id": "ma_01F0YESHRFQNH5S8Q0PK84YYZN", - "currency_code": "usd", - "amount": 1000, - "sale_amount": null, - "variant_id": "variant_01F0YESHR7P2YAYBDBY5B6X3PK", - "region_id": null, - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null - } - ], - "sku": null, - "barcode": null, - "ean": null, - "upc": null, - "inventory_quantity": 10, - "allow_backorder": false, - "manage_inventory": true, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "weight": null, - "length": null, - "height": null, - "width": null, - "options": [ - { - "id": "optval_01F0YESHR7S6ECD03RF6W12DSJ", - "value": "large", - "option_id": "opt_01F0YESHQBZVKCEXJ24BS6PCX3", - "variant_id": "variant_01F0YESHR7P2YAYBDBY5B6X3PK", - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - }, - { - "id": "optval_01F0YESHR7N2GHM1RN3GKYPN6P", - "value": "green", - "option_id": "opt_01F0YESHQBV8MMNN4V7WSDMH6G", - "variant_id": "variant_01F0YESHR7P2YAYBDBY5B6X3PK", - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - } - ], - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - }, - "product_option": { - "id": "opt_01F0YESHQBZVKCEXJ24BS6PCX3", - "title": "size", - "product_id": "prod_01F0YESHQ27Y31CAMD0NV6W9YP", - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - }, - "product_option_value": { - "id": "optval_01F0YESHR7S6ECD03RF6W12DSJ", - "value": "large", - "option_id": "opt_01F0YESHQBZVKCEXJ24BS6PCX3", - "variant_id": "variant_01F0YESHR7P2YAYBDBY5B6X3PK", - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null, - "metadata": null - }, - "money_amount": { - "id": "ma_01F0YESHRFQNH5S8Q0PK84YYZN", - "currency_code": "usd", - "amount": 100, - "sale_amount": null, - "variant_id": "variant_01F0YESHR7P2YAYBDBY5B6X3PK", - "region_id": null, - "created_at": "2021-03-16T21:24:13.657Z", - "updated_at": "2021-03-16T21:24:13.657Z", - "deleted_at": null - }, - "discount": { - "id": "disc_01F0YESMW10MGHWJKZSDDMN0VN", - "code": "10DISC", - "is_dynamic": false, - "rule_id": "dru_01F0YESMVK96HVX7N419E3CJ7C", - "rule": { - "id": "dru_01F0YESMVK96HVX7N419E3CJ7C", - "description": "10 Percent", - "type": "percentage", - "value": 10, - "allocation": "total", - "usage_limit": null, - "created_at": "2021-03-16T21:24:16.872Z", - "updated_at": "2021-03-16T21:24:16.872Z", - "deleted_at": null, - "metadata": null, - "conditions": [ - { - "id": "cnd_01F0YESMVJXKX8XZ6Q9Z6Q6Z6", - "type": "products", - "operator": "in" - } - ] - }, - "is_disabled": false, - "parent_discount_id": null, - "starts_at": "2021-03-16T21:24:16.872Z", - "ends_at": null, - "created_at": "2021-03-16T21:24:16.872Z", - "updated_at": "2021-03-16T21:24:16.872Z", - "deleted_at": null, - "metadata": null - }, - "discount_rule": { - "id": "dru_01F0YESMVK96HVX7N419E3CJ7C", - "description": "10 Percent", - "type": "percentage", - "value": 10, - "allocation": "total", - "usage_limit": null, - "created_at": "2021-03-16T21:24:16.872Z", - "updated_at": "2021-03-16T21:24:16.872Z", - "deleted_at": null, - "metadata": null - }, - "customer": { - "id": "cus_01F0YESQXFZ5WKMHTXJ4JDPBDZ", - "email": "test1@email.com", - "first_name": null, - "last_name": null, - "billing_address_id": null, - "password_hash": null, - "phone": null, - "has_account": false, - "orders": [], - "created_at": "2021-03-16T21:24:20.015Z", - "updated_at": "2021-03-16T21:24:20.015Z", - "deleted_at": null, - "metadata": null - }, - "customer_group": { - "name": "test group", - "id": "cgrp_01FX8NJYPPDEH7YK9NYM6BXPHV", - "deleted_at": null, - "metadata": null, - "created_at": "2022-03-03T19:54:53.014Z", - "updated_at": "2022-03-03T19:54:53.014Z" - }, - "shipping_profile": { - "id": "sp_01F0YESTZQFW15SFEZSS29EZ5R", - "name": "Default Shipping Profile", - "type": "default", - "created_at": "2021-03-16T21:24:23.116Z", - "updated_at": "2021-03-16T21:24:23.116Z", - "deleted_at": null, - "metadata": null - }, - "store": { - "id": "store_01F0YESXYNJNTJJY5G5Z26KHKJ", - "name": "Medusa Store", - "default_currency_code": "usd", - "default_currency": { - "code": "usd", - "symbol": "$", - "symbol_native": "$", - "name": "US Dollar" - }, - "currencies": [], - "swap_link_template": null, - "created_at": "2021-03-16T21:24:26.191Z", - "updated_at": "2021-03-16T21:24:26.191Z", - "metadata": null, - "payment_providers": [ - { - "id": "test-pay", - "is_installed": true - } - ], - "fulfillment_providers": [ - { - "id": "test-ful", - "is_installed": true - } - ] - }, - "user": { - "id": "admin_user", - "email": "admin@medusa.js", - "role": "admin", - "first_name": null, - "last_name": null, - "api_token": "test_token", - "created_at": "2021-03-16T21:24:29.411Z", - "updated_at": "2021-03-16T21:24:29.411Z", - "deleted_at": null, - "metadata": null - }, - "notification": { - "id": "noti_01F0YET45G9NHP08Z66CE4QKBS", - "resource_type": "order", - "resource_id": "order_01F0BF66ZBXNJ98WDQ9SCWH8Y7", - "event_name": "order.placed", - "to": "test@email.com", - "provider_id": "test-not", - "created_at": "2021-03-16T21:24:32.560Z", - "updated_at": "2021-03-16T21:24:32.560Z", - "resends": [] - }, - "order": { - "id": "order_01F0YET7CZ741ECWG1J3N34RXF", - "status": "pending", - "fulfillment_status": "not_fulfilled", - "payment_status": "not_paid", - "display_id": 1, - "cart_id": null, - "customer_id": "cus_01F0YET7C3H3D5M8QPNPP5CDAX", - "customer": { - "id": "cus_01F0YET7C3H3D5M8QPNPP5CDAX", - "email": "test@email.com", - "first_name": null, - "last_name": null, - "billing_address_id": null, - "password_hash": null, - "phone": null, - "has_account": false, - "created_at": "2021-03-16T21:24:35.843Z", - "updated_at": "2021-03-16T21:24:35.843Z", - "deleted_at": null, - "metadata": null - }, - "email": "test@email.com", - "billing_address": { - "id": "addr_01F0YET7CZZX0842X5AHQYAZ80", - "customer_id": null, - "company": null, - "first_name": "lebron", - "last_name": null, - "address_1": null, - "address_2": null, - "city": null, - "country_code": null, - "province": null, - "postal_code": null, - "phone": null, - "created_at": "2021-03-16T21:24:35.871Z", - "updated_at": "2021-03-16T21:24:35.871Z", - "deleted_at": null, - "metadata": null - }, - "shipping_address": { - "id": "addr_01F0YET7CZDHXHXYJ3JTXPH4T7", - "customer_id": null, - "company": null, - "first_name": "lebron", - "last_name": null, - "address_1": null, - "address_2": null, - "city": null, - "country_code": "us", - "province": null, - "postal_code": null, - "phone": null, - "created_at": "2021-03-16T21:24:35.871Z", - "updated_at": "2021-03-16T21:24:35.871Z", - "deleted_at": null, - "metadata": null - }, - "region_id": "reg_01F0YET7BZTARY9MKN1SJ7AAXF", - "region": { - "id": "reg_01F0YET7BZTARY9MKN1SJ7AAXF", - "name": "Test Region", - "currency_code": "usd", - "tax_rate": "0", - "tax_code": null, - "payment_providers": [], - "fulfillment_providers": [], - "created_at": "2021-03-16T21:24:35.839Z", - "updated_at": "2021-03-16T21:24:35.839Z", - "deleted_at": null, - "metadata": null - }, - "currency_code": "usd", - "tax_rate": 0, - "discounts": [ - { - "id": "test-discount", - "code": "TEST134", - "is_dynamic": false, - "rule_id": "dru_01F0YET7CZQDGWTFQYY8T4KYRZ", - "rule": { - "id": "dru_01F0YET7CZQDGWTFQYY8T4KYRZ", - "description": "Test Discount", - "type": "percentage", - "value": 10, - "allocation": "total", - "usage_limit": null, - "created_at": "2021-03-16T21:24:35.871Z", - "updated_at": "2021-03-16T21:24:35.871Z", - "deleted_at": null, - "metadata": null - }, - "is_disabled": false, - "parent_discount_id": null, - "starts_at": "2021-03-16T21:24:35.871Z", - "ends_at": null, - "created_at": "2021-03-16T21:24:35.871Z", - "updated_at": "2021-03-16T21:24:35.871Z", - "deleted_at": null, - "metadata": null - } - ], - "gift_cards": [], - "shipping_methods": [ - { - "id": "sm_01F0YET7DR2E7CYVSDHM593QG2", - "shipping_option_id": "so_01F0YET7C758MMXF1WNVCPGKZJ", - "order_id": "order_01F0YET7CZ741ECWG1J3N34RXF", - "claim_order_id": null, - "cart_id": null, - "swap_id": null, - "return_id": null, - "shipping_option": { - "id": "so_01F0YET7C758MMXF1WNVCPGKZJ", - "name": "test-option", - "region_id": "reg_01F0YET7BZTARY9MKN1SJ7AAXF", - "profile_id": "sp_01F0YET7AF62TCC9CMWK5TXXAQ", - "provider_id": "test-ful", - "price_type": "flat_rate", - "amount": 1000, - "is_return": false, - "data": {}, - "created_at": "2021-03-16T21:24:35.846Z", - "updated_at": "2021-03-16T21:24:35.846Z", - "deleted_at": null, - "metadata": null - }, - "price": 1000, - "data": {} - } - ], - "payments": [ - { - "id": "test-payment", - "swap_id": null, - "cart_id": null, - "order_id": "order_01F0YET7CZ741ECWG1J3N34RXF", - "amount": 10000, - "currency_code": "usd", - "amount_refunded": 0, - "provider_id": "test", - "data": {}, - "captured_at": null, - "canceled_at": null, - "created_at": "2021-03-16T21:24:35.871Z", - "updated_at": "2021-03-16T21:24:35.871Z", - "metadata": null, - "idempotency_key": null - } - ], - "fulfillments": [], - "returns": [], - "claims": [], - "refunds": [], - "swaps": [], - "items": [ - { - "id": "test-item", - "cart_id": null, - "order_id": "order_01F0YET7CZ741ECWG1J3N34RXF", - "swap_id": null, - "claim_order_id": null, - "title": "Line Item", - "description": "Line Item Desc", - "thumbnail": "https://test.js/1234", - "is_giftcard": false, - "should_merge": true, - "allow_discounts": true, - "has_shipping": null, - "unit_price": 8000, - "variant_id": "variant_01F0YET7BMD9FGWA5NTPBWT2SS", - "variant": { - "id": "variant_01F0YET7BMD9FGWA5NTPBWT2SS", - "title": "test variant", - "product_id": "prod_01F0YET7BA4AQ8WEK687BNWP3N", - "product": { - "id": "prod_01F0YET7BA4AQ8WEK687BNWP3N", - "title": "test product", - "subtitle": null, - "description": null, - "handle": "test-product", - "is_giftcard": false, - "thumbnail": null, - "profile_id": "sp_01F0YET7AF62TCC9CMWK5TXXAQ", - "weight": null, - "length": null, - "height": null, - "width": null, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "collection_id": null, - "type_id": null, - "created_at": "2021-03-16T21:24:35.818Z", - "updated_at": "2021-03-16T21:24:35.818Z", - "deleted_at": null, - "metadata": null - }, - "sku": null, - "barcode": null, - "ean": null, - "upc": null, - "inventory_quantity": 1, - "allow_backorder": false, - "manage_inventory": true, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "weight": null, - "length": null, - "height": null, - "width": null, - "created_at": "2021-03-16T21:24:35.828Z", - "updated_at": "2021-03-16T21:24:35.828Z", - "deleted_at": null, - "metadata": null - }, - "quantity": 1, - "fulfilled_quantity": 1, - "returned_quantity": null, - "shipped_quantity": null, - "created_at": "2021-03-16T21:24:35.871Z", - "updated_at": "2021-03-16T21:24:35.871Z", - "metadata": null, - "refundable": 7200 - } - ], - "gift_card_transactions": [], - "canceled_at": null, - "created_at": "2021-03-16T21:24:35.871Z", - "updated_at": "2021-03-16T21:24:35.871Z", - "metadata": null, - "shipping_total": 1000, - "gift_card_total": 0, - "discount_total": 800, - "tax_total": 0, - "subtotal": 8000, - "total": 8200, - "refunded_total": 0, - "refundable_amount": 8200 - }, - "order_edit": { - "id": "oe_01F0YET7XPCMF8RZ0Y151NZV2V", - "order_id": "ord_01F0YET7XPCMF8RZ0Y151NZV2V", - "internal_note": "internal note", - "declined_reason": null, - "declined_at": null, - "declined_by": null, - "canceled_at": null, - "canceled_by": null, - "requested_at": null, - "requested_by": null, - "created_at": "2021-03-16T21:24:35.871Z", - "created_by_id": "admin_user", - "confirmed_at": null, - "confirmed_by": null - }, - "store_order_edit": { - "id": "oe_01F0YET7XPCMF8RZ0Y151NZV2B", - "order_id": "ord_01F0YET7XPCMF8RZ0Y151NZV2V", - "declined_reason": null, - "declined_at": null, - "declined_by": null, - "canceled_at": null, - "requested_at": null, - "created_at": "2021-03-16T21:24:35.871Z", - "confirmed_at": null, - "confirmed_by": null - }, - "return": { - "id": "ret_01F0YET7XPCMF8RZ0Y151NZV2V", - "status": "requested", - "items": [ - { - "return_id": "ret_01F0YET7XPCMF8RZ0Y151NZV2V", - "item_id": "test-item", - "quantity": 1, - "is_requested": true, - "requested_quantity": 1, - "received_quantity": null, - "reason_id": null, - "reason": null, - "note": null, - "metadata": null - } - ], - "swap_id": null, - "claim_order_id": null, - "order_id": "order_01F0YET7RD6NWQTEM0ZN5DRRVD", - "shipping_method": null, - "shipping_data": null, - "refund_amount": 7200, - "received_at": null, - "created_at": "2021-03-16T21:24:36.381Z", - "updated_at": "2021-03-16T21:24:36.381Z", - "metadata": null, - "idempotency_key": "f3dee891-7a24-4e34-9071-62606035563d" - }, - "swap": { - "id": "swap_01F0YET86Y9G92D3YDR9Y6V676", - "fulfillment_status": "not_fulfilled", - "payment_status": "not_paid", - "order_id": "order_01F0YET82SR6NB8K61TNRN36FW", - "additional_items": [ - { - "id": "item_01F0YET86YR1J3GX155E9R81A3", - "cart_id": "cart_01F0YET896KVZ17Y2QDVT28QFE", - "order_id": null, - "swap_id": "swap_01F0YET86Y9G92D3YDR9Y6V676", - "claim_order_id": null, - "title": "test product", - "description": "test variant", - "thumbnail": null, - "is_giftcard": false, - "should_merge": true, - "allow_discounts": true, - "has_shipping": null, - "unit_price": 8000, - "variant_id": "variant_01F0YET825M92TKN1ZGAVBPX1B", - "variant": { - "id": "variant_01F0YET825M92TKN1ZGAVBPX1B", - "title": "test variant", - "product_id": "prod_01F0YET8213X0J501ZZHZ56Y7Y", - "product": { - "id": "prod_01F0YET8213X0J501ZZHZ56Y7Y", - "title": "test product", - "subtitle": null, - "description": null, - "handle": "test-product", - "is_giftcard": false, - "thumbnail": null, - "profile_id": "sp_01F0YET7AF62TCC9CMWK5TXXAQ", - "weight": null, - "length": null, - "height": null, - "width": null, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "collection_id": null, - "type_id": null, - "created_at": "2021-03-16T21:24:36.545Z", - "updated_at": "2021-03-16T21:24:36.545Z", - "deleted_at": null, - "metadata": null - }, - "sku": null, - "barcode": null, - "ean": null, - "upc": null, - "inventory_quantity": 1, - "allow_backorder": false, - "manage_inventory": true, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "weight": null, - "length": null, - "height": null, - "width": null, - "created_at": "2021-03-16T21:24:36.549Z", - "updated_at": "2021-03-16T21:24:36.549Z", - "deleted_at": null, - "metadata": null - }, - "quantity": 2, - "fulfilled_quantity": null, - "returned_quantity": null, - "shipped_quantity": null, - "created_at": "2021-03-16T21:24:36.659Z", - "updated_at": "2021-03-16T21:24:36.659Z", - "metadata": {} - } - ], - "return_order": { - "id": "ret_01F0YET873ZAXQ7PYVKVFMT9FP", - "status": "requested", - "items": [ - { - "return_id": "ret_01F0YET873ZAXQ7PYVKVFMT9FP", - "item_id": "test-item", - "quantity": 1, - "is_requested": true, - "requested_quantity": 1, - "received_quantity": null, - "reason_id": null, - "reason": null, - "note": null, - "metadata": null - } - ], - "swap_id": "swap_01F0YET86Y9G92D3YDR9Y6V676", - "claim_order_id": null, - "order_id": null, - "shipping_method": null, - "shipping_data": null, - "refund_amount": 7200, - "received_at": null, - "created_at": "2021-03-16T21:24:36.659Z", - "updated_at": "2021-03-16T21:24:36.659Z", - "metadata": null, - "idempotency_key": null - }, - "fulfillments": [], - "payment": null, - "difference_due": null, - "shipping_address_id": null, - "shipping_address": null, - "shipping_methods": [], - "cart_id": "cart_01F0YET896KVZ17Y2QDVT28QFE", - "confirmed_at": null, - "created_at": "2021-03-16T21:24:36.659Z", - "updated_at": "2021-03-16T21:24:36.659Z", - "deleted_at": null, - "metadata": null, - "idempotency_key": "10804103-2f4f-41ef-b44e-7049459f157d" - }, - "line_item": { - "id": "test-item", - "cart_id": "cart_01F0YES82DA12W88KQ90EY6W4C", - "order_id": null, - "swap_id": null, - "claim_order_id": null, - "title": "Line Item", - "description": "Line Item Desc", - "thumbnail": "https://test.js/1234", - "is_giftcard": false, - "should_merge": true, - "allow_discounts": true, - "has_shipping": null, - "unit_price": 8000, - "variant_id": "variant_01F0YET7BMD9FGWA5NTPBWT2SS", - "variant": { - "id": "variant_01F0YET7BMD9FGWA5NTPBWT2SS", - "title": "test variant", - "product_id": "prod_01F0YET7BA4AQ8WEK687BNWP3N", - "product": { - "id": "prod_01F0YET7BA4AQ8WEK687BNWP3N", - "title": "test product", - "subtitle": null, - "description": null, - "handle": "test-product", - "is_giftcard": false, - "thumbnail": null, - "profile_id": "sp_01F0YET7AF62TCC9CMWK5TXXAQ", - "weight": null, - "length": null, - "height": null, - "width": null, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "collection_id": null, - "type_id": null, - "created_at": "2021-03-16T21:24:35.818Z", - "updated_at": "2021-03-16T21:24:35.818Z", - "deleted_at": null, - "metadata": null - }, - "sku": null, - "barcode": null, - "ean": null, - "upc": null, - "inventory_quantity": 1, - "allow_backorder": false, - "manage_inventory": true, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "weight": null, - "length": null, - "height": null, - "width": null, - "created_at": "2021-03-16T21:24:35.828Z", - "updated_at": "2021-03-16T21:24:35.828Z", - "deleted_at": null, - "metadata": null - }, - "quantity": 1, - "fulfilled_quantity": 1, - "returned_quantity": null, - "shipped_quantity": null, - "created_at": "2021-03-16T21:24:35.871Z", - "updated_at": "2021-03-16T21:24:35.871Z", - "metadata": null, - "refundable": 7200 - }, - "return_reason": { - "id": "rr_01F0ZXDBAB9KVZWJVW6115VEM7", - "value": "too_big", - "label": "Size too big", - "description": "use if the size was too big", - "created_at": "2021-03-17 11:58:56.975971+01", - "updated_at": "2021-03-17 12:09:59.156058+01", - "metadata": null, - "parent_return_reason_id": null - }, - "product_type": { - "id": "ptype_ZXDBABWJVW6115VEMZXDBAB", - "value": "clothing", - "created_at": "2021-03-16T21:24:35.828Z", - "updated_at": "2021-03-16T21:24:35.828Z", - "deleted_at": null, - "metadata": null - }, - "product_tag": { - "id": "ptag_ZXDBABWJVW6115VEMZXDBAB", - "value": "pants", - "created_at": "2021-03-16T21:24:35.828Z", - "updated_at": "2021-03-16T21:24:35.828Z", - "deleted_at": null, - "metadata": null - }, - "price_list": { - "id": "pl_ZXDBABWJVW6115VEMZXDBAB", - "name": "test price list", - "description": "test price list", - "type": "products", - "status": "active", - "starts_at": null, - "ends_at": null, - "created_at": "2021-03-16T21:24:35.828Z", - "updated_at": "2021-03-16T21:24:35.828Z", - "deleted_at": null - }, - "note": { - "id": "note_01F0ZXDBAB9KVZWJVW6115VEM7", - "value": "customer contacted", - "resource_type": "swap", - "resource_id": "swap_01F0YET86Y9G92D3YDR9Y6V676", - "author_id": "admin_user", - "created_at": "2021-03-17 11:58:56.975971+01", - "updated_at": "2021-03-17 12:09:59.156058+01", - "metadata": null - }, - "inventory_item": { - "id": "iitem_320ZXDBAB4WJVW6115VEM7", - "sku": "sku123", - "origin_country": "dk", - "hs_code": null, - "mid_code": null, - "material": null, - "weight": 10, - "lenght": 4, - "height": 5, - "width": 2, - "requires_shipping": true, - "created_at": "2021-03-17 11:58:56.975971+01", - "updated_at": "2021-03-17 12:09:59.156058+01", - "metadata": null, - "location_levels": [ - { - "id": "ilev_320ZXDBAB4WJVW6115VEM7", - "inventory_item_id": "iitem_320ZXDBAB4WJVW6115VEM7", - "location_id": "loc_01F0ZXDBAB9KVZWJVW6115VEM7", - "stocked_quantity": 1, - "reserved_quantity": 0, - "incoming_quantity": 10 - } - ] - }, - "stock_location": { - "id": "loc_01F0ZXDBAB9KVZWJVW6115VEM7", - "name": "Stock location 1", - "address_id": "addr_01F0ZXDBAB9KVZWJVW6115VEM7", - "created_at": "2021-03-17 11:58:56.975971+01", - "updated_at": "2021-03-17 12:09:59.156058+01" - }, - "reservation": { - "id": "res_01F0ZXDBAB9KVZWJVW6115VEM7", - "line_item_id": "li_01F0ZXDBAB9KVZWJVW6115VEM7", - "inventory_item_id": "iitem_320ZXDBAB4WJVW6115VEM7", - "location_id": "loc_01F0ZXDBAB9KVZWJVW6115VEM7", - "quantity": 1 - }, - "invite": { - "id": "invite_320ZXDBAB4WJVW6115VEM7", - "user_email": "lebron@james.com", - "role": "admin", - "accepted": true, - "token": "secret_token", - "expires_at": "2021-03-18 11:58:56.975971+01", - "created_at": "2021-03-17 11:58:56.975971+01", - "updated_at": "2021-03-17 12:09:59.156058+01", - "metadata": null - }, - "publishable_api_key": { - "id": "pubkey_1234", - "created_by": "admin_user", - "created_at": "2021-11-08 11:58:56.975971+01", - "updated_at": "2021-11-08 11:58:56.975971+01", - "revoked_by": null, - "revoked_at": null - }, - "draft_order": { - "id": "dorder_01FGKMYKMJ4E8HP3RGEW28E7CZ", - "status": "open", - "display_id": 1, - "cart_id": "cart_01FGKMYKM9V8FVEJE23Q26FG5B", - "cart": { - "id": "cart_01FGKMYKM9V8FVEJE23Q26FG5B", - "email": "jane@medusa.test", - "billing_address_id": null, - "billing_address": null, - "shipping_address_id": "addr_01FGKMYKKQ3S1Q4ZC9HV4REXC6", - "shipping_address": { - "id": "addr_01FGKMYKKQ3S1Q4ZC9HV4REXC6", - "customer_id": null, - "company": null, - "first_name": "Jane", - "last_name": "Medusan", - "address_1": null, - "address_2": null, - "city": null, - "country_code": "dk", - "province": null, - "postal_code": null, - "phone": null, - "created_at": "2021-09-27T12:51:21.335Z", - "updated_at": "2021-09-27T12:51:21.335Z", - "deleted_at": null, - "metadata": null - }, - "items": [ - { - "id": "item_01FGKMYKM9AKV5D146N28QFPX7", - "cart_id": "cart_01FGKMYKM9V8FVEJE23Q26FG5B", - "order_id": null, - "swap_id": null, - "claim_order_id": null, - "title": "Basic Tee - One Size", - "description": "Soft and sweet", - "thumbnail": "https://test.js/1234", - "is_giftcard": false, - "should_merge": true, - "allow_discounts": true, - "has_shipping": null, - "unit_price": 8000, - "variant_id": "variant_01FGKMYKJVY3DYDZWCRB2GZS0G", - "variant": { - "id": "variant_01FGKMYKJVY3DYDZWCRB2GZS0G", - "title": "One Size", - "product_id": "prod_01FGKMYKJJMZ6XFN37JBGTZ46G", - "sku": null, - "barcode": null, - "ean": null, - "upc": null, - "inventory_quantity": 1, - "allow_backorder": false, - "manage_inventory": true, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "weight": null, - "length": null, - "height": null, - "width": null, - "created_at": "2021-09-27T12:51:21.307Z", - "updated_at": "2021-09-27T12:51:21.307Z", - "deleted_at": null, - "metadata": null - }, - "quantity": 1, - "fulfilled_quantity": 1, - "returned_quantity": null, - "shipped_quantity": null, - "created_at": "2021-09-27T12:51:21.352Z", - "updated_at": "2021-09-27T12:51:21.352Z", - "metadata": null - } - ], - "region_id": "reg_01FGKMYKKG6ACZANRNHR3XVRN3", - "region": { - "id": "reg_01FGKMYKKG6ACZANRNHR3XVRN3", - "name": "United States", - "currency_code": "usd", - "tax_rate": "0", - "tax_code": null, - "payment_providers": [ - { - "id": "test-pay", - "is_installed": true - } - ], - "fulfillment_providers": [], - "created_at": "2021-09-27T12:51:21.328Z", - "updated_at": "2021-09-27T12:51:21.328Z", - "deleted_at": null, - "metadata": null - }, - "discounts": [], - "gift_cards": [], - "customer_id": "cus_01FGKMYKM2TAKTGZ1XMEW45RJZ", - "payment_sessions": [], - "payment_id": null, - "payment": null, - "shipping_methods": [], - "type": "draft_order", - "completed_at": null, - "payment_authorized_at": null, - "created_at": "2021-09-27T12:51:21.352Z", - "updated_at": "2021-09-27T12:51:21.352Z", - "deleted_at": null, - "metadata": null, - "idempotency_key": null, - "context": null, - "shipping_total": 0, - "discount_total": 0, - "tax_total": 0, - "gift_card_total": 0, - "subtotal": 8000, - "total": 8000 - }, - "order_id": null, - "order": null, - "canceled_at": null, - "created_at": "2021-09-27T12:51:21.360Z", - "updated_at": "2021-09-27T12:51:21.360Z", - "no_notification_order": null, - "metadata": null - }, - "fulfillment_option": { - "provider_id": "test-ful", - "options": [] - }, - "batch_job": { - "id": "batch_01F0YES4R67TXXC1QBQ8P54A8Y", - "type": "product_export", - "created_by": "usr_123412341234", - "context": null, - "result": null, - "dry_run": false, - "updated_at": "2021-03-16T21:24:00.389Z", - "created_at": "2021-03-16T21:24:00.389Z", - "deleted_at": null - }, - "upload": { - "url": "test-url" - }, - "sales_channel": { - "id": "sc_01F0YES4R67TXXC1QBQ8P54A8Y", - "name": "sales channel 1 name", - "description": "sales channel 1 description", - "is_disabled": false, - "updated_at": "2022-07-05T15:16:01.959Z", - "created_at": "2022-07-05T15:16:01.959Z", - "deleted_at": null - }, - "sales_channels": [ - { - "id": "sc_01F0YES4R67TXXC1QBQ8P54A8Y", - "name": "sales channel 1 name", - "description": "sales channel 1 description", - "is_disabled": false, - "updated_at": "2022-07-05T15:16:01.959Z", - "created_at": "2022-07-05T15:16:01.959Z", - "deleted_at": null - } - ], - "payment_collection": { - "id": "paycol_01GJK7P9MRHM6XWCJG70JFB8PF", - "created_at": "2022-11-23T21:53:19.367Z", - "updated_at": "2022-11-24T12:57:08.652Z", - "deleted_at": null, - "type": "order_edit", - "status": "authorized", - "description": null, - "amount": 900, - "authorized_amount": 900, - "region_id": "test-region", - "currency_code": "usd", - "metadata": null, - "created_by": "admin_user", - "payment_sessions": [ - { - "id": "ps_01GJMVD71Z4WF9FXXGT7DHGPCM", - "created_at": "2022-11-24T12:57:07.883Z", - "updated_at": "2022-11-24T12:57:08.652Z", - "cart_id": null, - "provider_id": "test-pay", - "is_selected": null, - "status": "authorized", - "data": {}, - "idempotency_key": null, - "amount": 900, - "payment_authorized_at": "2022-11-24T12:57:08.672Z" - } - ] - }, - "payment_sessions": { - "id": "ps_01GJMVD71Z4WF9FXXGT7DHGPCM", - "created_at": "2022-11-24T12:57:07.883Z", - "updated_at": "2022-11-24T12:57:08.652Z", - "cart_id": null, - "provider_id": "test-pay", - "is_selected": null, - "status": "authorized", - "data": {}, - "idempotency_key": null, - "amount": 900, - "payment_authorized_at": "2022-11-24T12:57:08.672Z" - }, - "payment": { - "id": "pay_A1GJEVD71Z4WF9FXFGT7D1GP15", - "swap_id": null, - "cart_id": null, - "order_id": null, - "amount": 900, - "currency_code": "usd", - "amount_refunded": 0, - "amount_captured": 900, - "provider_id": "manual", - "data": {}, - "captured_at": "2022-11-17T21:24:35.871Z", - "canceled_at": null, - "created_at": "2022-11-16T21:24:35.871Z", - "updated_at": "2022-11-16T21:24:35.871Z", - "metadata": null, - "idempotency_key": null - }, - "refund": { - "order_id": null, - "payment_id": "pay_A1GJEVD71Z4WF9FXFGT7D1GP15", - "amount": 900, - "note": null, - "reason": "return", - "metadata": null, - "idempotency_key": null - } - } -} diff --git a/packages/medusa-react/mocks/data/index.ts b/packages/medusa-react/mocks/data/index.ts deleted file mode 100644 index 3787e86946..0000000000 --- a/packages/medusa-react/mocks/data/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -import data from "./fixtures.json" - -const resources = data["resources"] - -type Resources = typeof resources - -type ResourcesWithKey = { - [K in keyof T]: { [_ in Entity]: K } & T[K] -} - -type KeyedResources = ResourcesWithKey<"entity", Resources> - -export const fixtures = { - get( - entity: Entity - ): Omit { - return resources[entity as string] - }, - list( - entity: Entity, - number = 2 - ): Omit[] { - return Array(number) - .fill(null) - .map((_) => fixtures.get(entity)) - }, -} as const diff --git a/packages/medusa-react/mocks/handlers/admin.ts b/packages/medusa-react/mocks/handlers/admin.ts deleted file mode 100644 index 0ab86ceb14..0000000000 --- a/packages/medusa-react/mocks/handlers/admin.ts +++ /dev/null @@ -1,2526 +0,0 @@ -import { rest } from "msw" -import { fixtures } from "../data" - -export const adminHandlers = [ - rest.post("/admin/batch-jobs/", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - batch_job: { - ...fixtures.get("batch_job"), - ...body, - }, - }) - ) - }), - - rest.get("/admin/batch-jobs/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - batch_jobs: fixtures.list("batch_job"), - }) - ) - }), - - rest.get("/admin/batch-jobs/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - batch_job: fixtures.get("batch_job"), - }) - ) - }), - - rest.post("/admin/batch-jobs/:id/confirm", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - batch_job: fixtures.get("batch_job"), - }) - ) - }), - - rest.post("/admin/batch-jobs/:id/cancel", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - batch_job: fixtures.get("batch_job"), - }) - ) - }), - - rest.post("/admin/collections/", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - collection: { - ...fixtures.get("product_collection"), - ...body, - }, - }) - ) - }), - - rest.get("/admin/collections/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - collections: fixtures.list("product_collection"), - }) - ) - }), - - rest.get("/admin/collections/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - collection: fixtures.get("product_collection"), - }) - ) - }), - - rest.post("/admin/collections/:id", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - collection: { - ...fixtures.get("product_collection"), - ...body, - id: req.params.id, - }, - }) - ) - }), - - rest.delete("/admin/collections/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "collection", - deleted: true, - }) - ) - }), - - rest.post("/admin/collections/:id/products/batch", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - collection: { - ...fixtures.get("product_collection"), - products: [fixtures.get("product")], - }, - }) - ) - }), - - rest.delete("/admin/collections/:id/products/batch", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "product-collection", - removed_products: [fixtures.get("product").id], - }) - ) - }), - - rest.get("/admin/product-categories/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product_categories: fixtures.list("product_category"), - }) - ) - }), - - rest.get("/admin/product-categories/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product_category: fixtures.get("product_category"), - }) - ) - }), - - rest.post("/admin/product-categories/", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - product_category: { - ...fixtures.get("product_category"), - ...body, - }, - }) - ) - }), - - rest.post("/admin/product-categories/:id", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - product_category: { - ...fixtures.get("product_category"), - ...body, - }, - }) - ) - }), - - rest.delete("/admin/product-categories/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "product-category", - deleted: true, - }) - ) - }), - - rest.post("/admin/product-categories/:id/products/batch", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product_category: fixtures.get("product_category"), - }) - ) - }), - - rest.delete( - "/admin/product-categories/:id/products/batch", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product_category: fixtures.get("product_category"), - }) - ) - } - ), - - rest.post("/admin/gift-cards/", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - gift_card: { - ...fixtures.get("gift_card"), - ...body, - }, - }) - ) - }), - - rest.get("/admin/gift-cards/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - gift_cards: fixtures.list("gift_card"), - }) - ) - }), - - rest.get("/admin/gift-cards/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - gift_card: fixtures.get("gift_card"), - }) - ) - }), - - rest.post("/admin/gift-cards/:id", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - gift_card: { - ...fixtures.get("gift_card"), - ...body, - id: req.params.id, - }, - }) - ) - }), - - rest.delete("/admin/gift-cards/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "gift_card", - deleted: true, - }) - ) - }), - - rest.post("/admin/notes/", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - note: { - ...fixtures.get("note"), - ...body, - }, - }) - ) - }), - - rest.get("/admin/notes/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - notes: fixtures.list("note"), - }) - ) - }), - - rest.get("/admin/notes/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - note: fixtures.get("note"), - }) - ) - }), - - rest.post("/admin/notes/:id", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - note: { - ...fixtures.get("note"), - ...body, - id: req.params.id, - }, - }) - ) - }), - - rest.delete("/admin/notes/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "note", - deleted: true, - }) - ) - }), - - rest.post("/admin/price-lists/", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - price_list: { - ...fixtures.get("price_list"), - ...body, - }, - }) - ) - }), - - rest.get("/admin/price-lists/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - price_lists: fixtures.list("price_list"), - count: 2, - offset: 0, - limit: 10, - }) - ) - }), - - rest.get("/admin/price-lists/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - price_list: fixtures.get("price_list"), - }) - ) - }), - - rest.post("/admin/price-lists/:id", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - price_list: { - ...fixtures.get("price_list"), - ...body, - id: req.params.id, - }, - }) - ) - }), - - rest.delete("/admin/price-lists/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "price_list", - deleted: true, - }) - ) - }), - - rest.delete("/admin/price-lists/:id/prices/batch", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - ids: body.price_ids, - object: "money-amount", - deleted: true, - }) - ) - }), - - rest.post("/admin/price-lists/:id/prices/batch", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - price_list: { - ...fixtures.get("price_list"), - id: req.params.id, - }, - }) - ) - }), - - rest.delete( - "/admin/price-lists/:id/products/:product_id/prices", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - ids: [], - object: "money-amount", - deleted: true, - }) - ) - } - ), - - rest.delete( - "/admin/price-lists/:id/variants/:variant_id/prices", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - ids: [], - object: "money-amount", - deleted: true, - }) - ) - } - ), - - rest.get("/admin/reservations/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - reservations: fixtures.list("reservation"), - }) - ) - }), - rest.post("/admin/reservations/", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - reservation: { - ...fixtures.get("reservation"), - ...body, - }, - }) - ) - }), - rest.get("/admin/reservations/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - reservation: { ...fixtures.get("reservation"), id: req.params.id }, - }) - ) - }), - - rest.post("/admin/reservations/:id", (req, res, ctx) => { - const body = req.body as Record - - return res( - ctx.status(200), - ctx.json({ - reservation: { - ...fixtures.get("reservation"), - ...body, - id: req.params.id, - }, - }) - ) - }), - - rest.delete("/admin/reservations/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "reservation", - deleted: true, - }) - ) - }), - - rest.post("/admin/return-reasons/", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - return_reason: { - ...fixtures.get("return_reason"), - ...body, - }, - }) - ) - }), - - rest.get("/admin/return-reasons/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - return_reasons: fixtures.list("return_reason"), - }) - ) - }), - - rest.get("/admin/return-reasons/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - return_reason: fixtures.get("return_reason"), - }) - ) - }), - - rest.post("/admin/return-reasons/:id", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - return_reason: { - ...fixtures.get("return_reason"), - ...body, - id: req.params.id, - }, - }) - ) - }), - - rest.delete("/admin/return-reasons/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "return_reason", - deleted: true, - }) - ) - }), - - rest.post("/admin/shipping-options/", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - shipping_option: { - ...fixtures.get("shipping_option"), - ...body, - }, - }) - ) - }), - - rest.get("/admin/shipping-options/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - shipping_options: fixtures.list("shipping_option"), - }) - ) - }), - - rest.get("/admin/shipping-options/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - shipping_option: fixtures.get("shipping_option"), - }) - ) - }), - - rest.post("/admin/shipping-options/:id", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - shipping_option: { - ...fixtures.get("shipping_option"), - ...body, - id: req.params.id, - }, - }) - ) - }), - - rest.delete("/admin/shipping-options/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "shipping_option", - deleted: true, - }) - ) - }), - - rest.get("/admin/stock-locations", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - stock_locations: fixtures.list("stock_location"), - }) - ) - }), - rest.post("/admin/stock-locations", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - stock_location: { - ...fixtures.get("stock_location"), - ...(req.body as any), - }, - }) - ) - }), - rest.get("/admin/stock-locations/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - stock_location: { - ...fixtures.get("stock_location"), - id: req.params.id, - }, - }) - ) - }), - - rest.post("/admin/stock-locations/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - stock_location: { - ...fixtures.get("stock_location"), - ...(req.body as any), - id: req.params.id, - }, - }) - ) - }), - - rest.delete("/admin/stock-locations/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "stock_location", - deleted: true, - }) - ) - }), - - rest.get("/admin/notifications/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - notifications: fixtures.list("notification"), - }) - ) - }), - - rest.post("/admin/notifications/:id/resend", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - notification: { - ...fixtures.get("notification"), - id: req.params.id, - ...(req.body as any), - }, - }) - ) - }), - - // inventory - rest.get("/admin/inventory-items", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - inventory_items: fixtures.list("inventory_item"), - }) - ) - }), - - rest.get("/admin/inventory-items/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - inventory_item: fixtures.get("inventory_item"), - }) - ) - }), - - rest.post("/admin/inventory-items/:id", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - inventory_item: { - ...fixtures.get("inventory_item"), - ...body, - id: req.params.id, - }, - }) - ) - }), - - rest.delete("/admin/inventory-items/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "inventory_item", - deleted: true, - }) - ) - }), - - rest.get("/admin/inventory-items/:id/location-levels", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - inventory_item: { - ...fixtures.get("inventory_item"), - id: req.params.id, - }, - }) - ) - }), - - rest.post("/admin/inventory-items/:id/location-levels", (req, res, ctx) => { - const body = req.body as Record - const { location_levels } = fixtures.get("inventory_item") - return res( - ctx.status(200), - ctx.json({ - inventory_item: { - ...fixtures.get("inventory_item"), - id: req.params.id, - location_levels: [...location_levels, { ...body, id: "2" }], - }, - }) - ) - }), - - rest.post( - "/admin/inventory-items/:id/location-levels/:location_id", - (req, res, ctx) => { - const body = req.body as Record - const inventoryItem = fixtures.get("inventory_item") - const locationlevel = { ...inventoryItem.location_levels[0], ...body } - return res( - ctx.status(200), - ctx.json({ - inventory_item: { - ...fixtures.get("inventory_item"), - id: req.params.id, - location_levels: [locationlevel], - }, - }) - ) - } - ), - - rest.delete( - "/admin/inventory-items/:id/location-levels/:location_id", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - inventory_item: { - ...fixtures.get("inventory_item"), - id: req.params.id, - location_levels: [], - }, - }) - ) - } - ), - - rest.get("/admin/invites", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - invites: fixtures.list("invite"), - }) - ) - }), - - rest.post("/admin/invites/accept", (req, res, ctx) => { - return res(ctx.status(200)) - }), - - rest.post("/admin/invites", (req, res, ctx) => { - return res(ctx.status(200)) - }), - - rest.post("/admin/invites/:id", (req, res, ctx) => { - return res(ctx.status(200)) - }), - - rest.delete("/admin/invites/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "invite", - deleted: true, - }) - ) - }), - - rest.get("/admin/returns", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - returns: fixtures.list("return"), - }) - ) - }), - - rest.post("/admin/returns/:id/receive", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - return: fixtures.get("return"), - }) - ) - }), - - rest.post("/admin/returns/:id/cancel", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/shipping-profiles/", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - shipping_profile: { - ...fixtures.get("shipping_profile"), - ...body, - }, - }) - ) - }), - - rest.get("/admin/shipping-profiles/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - shipping_profiles: fixtures.list("shipping_profile"), - }) - ) - }), - - rest.get("/admin/shipping-profiles/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - shipping_profile: fixtures.get("shipping_profile"), - }) - ) - }), - - rest.post("/admin/shipping-profiles/:id", (req, res, ctx) => { - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - shipping_profile: { - ...fixtures.get("shipping_profile"), - ...body, - id: req.params.id, - }, - }) - ) - }), - - rest.delete("/admin/shipping-profiles/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "shipping_profile", - deleted: true, - }) - ) - }), - - rest.get("/admin/store/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - store: fixtures.get("store"), - }) - ) - }), - - rest.post("/admin/store/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - store: { - ...fixtures.get("store"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/store/:currency_code", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - store: fixtures.get("store"), - }) - ) - }), - - rest.delete("/admin/store/currencies/:currency_code", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - store: fixtures.get("store"), - }) - ) - }), - - rest.get("/admin/store/payment-providers", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - payment_providers: fixtures.get("store").payment_providers, - }) - ) - }), - - rest.get("/admin/customers/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - customers: fixtures.list("customer"), - }) - ) - }), - - rest.get("/admin/customers/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - customer: fixtures.get("customer"), - }) - ) - }), - - rest.post("/admin/customers/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - customer: { - ...fixtures.get("customer"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/customers/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - customer: { - ...fixtures.get("customer"), - ...(req.body as any), - }, - }) - ) - }), - - rest.get("/admin/customer-groups/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - customer_groups: fixtures.list("customer_group"), - }) - ) - }), - - rest.get("/admin/customer-groups/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - customer_group: fixtures.get("customer_group"), - }) - ) - }), - - rest.post("/admin/customer-groups/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - customer_group: { - ...fixtures.get("customer_group"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/customer-groups/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - customer_group: { - ...fixtures.get("customer_group"), - ...(req.body as any), - }, - }) - ) - }), - - rest.get("/admin/customer-groups/:id/customers", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - customers: fixtures.list("customer"), - }) - ) - }), - - rest.get("/admin/discounts/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discounts: fixtures.list("discount"), - }) - ) - }), - - rest.get("/admin/discounts/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: fixtures.get("discount"), - }) - ) - }), - - rest.get("/admin/discounts/code/:code", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: fixtures.get("discount"), - }) - ) - }), - - rest.post("/admin/discounts/:id/regions/:region_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: fixtures.get("discount"), - }) - ) - }), - - rest.post("/admin/discounts/:id/products/:product_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: fixtures.get("discount"), - }) - ) - }), - - rest.post("/admin/discounts/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: { - ...fixtures.get("discount"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/discounts/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: { - ...fixtures.get("discount"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/discounts/:id/dynamic-codes", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: { - ...fixtures.get("discount"), - ...(req.body as any), - }, - }) - ) - }), - - rest.delete("/admin/discounts/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "discount", - deleted: true, - }) - ) - }), - - rest.delete("/admin/discounts/:id/dynamic-codes/:code", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: fixtures.get("discount"), - }) - ) - }), - - rest.delete("/admin/discounts/:id/regions/:region_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: fixtures.get("discount"), - }) - ) - }), - - rest.delete("/admin/discounts/:id/products/:product_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: fixtures.get("discount"), - }) - ) - }), - - rest.post("/admin/discounts/:id/conditions", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: { - ...fixtures.get("discount"), - }, - }) - ) - }), - - rest.post("/admin/discounts/:id/conditions/:conditionId", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: { - ...fixtures.get("discount"), - }, - }) - ) - }), - - rest.get("/admin/discounts/:id/conditions/:conditionId", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount_condition: { - ...fixtures - .get("discount") - .rule.conditions.find((c) => c.id === req.params.conditionId), - }, - }) - ) - }), - - rest.delete( - "/admin/discounts/:id/conditions/:conditionId", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.conditionId, - object: "discount-condition", - deleted: true, - discount: fixtures.get("discount"), - }) - ) - } - ), - - rest.post( - "/admin/discounts/:id/conditions/:conditionId/batch", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: { - ...fixtures.get("discount"), - rule: { - ...fixtures.get("discount").rule, - conditions: [ - { - ...fixtures.get("discount").rule.conditions[0], - products: [ - ...(fixtures.get("discount").rule.conditions[0]?.products ?? - []), - ...(req.body as any).resources, - ], - }, - ], - }, - }, - }) - ) - } - ), - - rest.delete( - "/admin/discounts/:id/conditions/:conditionId/batch", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - discount: { - ...fixtures.get("discount"), - rule: { - ...fixtures.get("discount").rule, - conditions: [ - { - ...fixtures.get("discount").rule.conditions[0], - products: [], - }, - ], - }, - }, - }) - ) - } - ), - - rest.get("/admin/publishable-api-keys/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - publishable_api_keys: fixtures.list("publishable_api_key"), - }) - ) - }), - - rest.get("/admin/publishable-api-keys/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - publishable_api_key: fixtures.get("publishable_api_key"), - }) - ) - }), - - rest.post("/admin/publishable-api-keys/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - publishable_api_key: { - ...fixtures.get("publishable_api_key"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post( - "/admin/publishable-api-keys/:id/sales-channels/batch", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - publishable_api_key: { - ...fixtures.get("publishable_api_key"), - ...(req.body as any), - }, - }) - ) - } - ), - - rest.delete( - "/admin/publishable-api-keys/:id/sales-channels/batch", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - publishable_api_key: { - ...fixtures.get("publishable_api_key"), - ...(req.body as any), - }, - }) - ) - } - ), - - rest.get( - "/admin/publishable-api-keys/:id/sales-channels", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - sales_channels: fixtures.get("sales_channels"), - }) - ) - } - ), - - rest.post("/admin/publishable-api-keys/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - publishable_api_key: { - ...fixtures.get("publishable_api_key"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/publishable-api-keys/:id/revoke", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - publishable_api_key: { - ...fixtures.get("publishable_api_key"), - revoked_at: "2022-11-10 11:17:46.666Z", - revoked_by: "admin_user", - }, - }) - ) - }), - - rest.delete("/admin/publishable-api-keys/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: fixtures.get("publishable_api_key").id, - object: "publishable_api_key", - deleted: true, - }) - ) - }), - - rest.get("/admin/draft-orders/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - draft_orders: fixtures.list("draft_order"), - }) - ) - }), - - rest.get("/admin/draft-orders/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - draft_order: fixtures.get("draft_order"), - }) - ) - }), - - rest.post("/admin/draft-orders/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - draft_order: { - ...fixtures.get("draft_order"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/draft-orders/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - draft_order: { - ...fixtures.get("draft_order"), - ...(req.body as any), - }, - }) - ) - }), - - rest.delete("/admin/draft-orders/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: fixtures.get("draft_order").id, - object: "draft_order", - deleted: true, - }) - ) - }), - - rest.post("/admin/draft-orders/:id/line-items", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - draft_order: fixtures.get("draft_order"), - }) - ) - }), - - rest.post("/admin/draft-orders/:id/line-items/:item_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - draft_order: fixtures.get("draft_order"), - }) - ) - }), - - rest.delete( - "/admin/draft-orders/:id/line-items/:item_id", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - draft_order: fixtures.get("draft_order"), - }) - ) - } - ), - - rest.post("/admin/draft-orders/:id/pay", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.get("/admin/swaps/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - swaps: fixtures.list("swap"), - }) - ) - }), - - rest.get("/admin/swaps/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - swap: fixtures.get("swap"), - }) - ) - }), - - rest.get("/admin/variants/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - variants: fixtures.list("product_variant"), - }) - ) - }), - - rest.get("/admin/variants/:id", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - variant: {...fixtures.get("product_variant"), id: id}, - }) - ) - }), - - rest.get("/admin/variants/:id/inventory", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - variant: { - ...fixtures.get("product_variant"), - sales_channel_availability: [ - { - channel_name: "default channel", - channel_id: "1", - available_quantity: 10, - }, - ], - }, - }) - ) - }), - - rest.get("/admin/users/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - user: fixtures.get("user"), - }) - ) - }), - - rest.get("/admin/users/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - users: fixtures.list("user"), - }) - ) - }), - - rest.post("/admin/users/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - user: { - ...fixtures.get("user"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/users/password-token", (req, res, ctx) => { - return res(ctx.status(200)) - }), - - rest.post("/admin/users/reset-password", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - user: fixtures.get("user"), - }) - ) - }), - - rest.post("/admin/users/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - user: { - ...fixtures.get("user"), - ...(req.body as any), - }, - }) - ) - }), - - rest.delete("/admin/users/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: fixtures.get("user").id, - object: "user", - deleted: true, - }) - ) - }), - - rest.get("/admin/products/types", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - types: fixtures.list("product_type"), - }) - ) - }), - - rest.get("/admin/products/tag-usage", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - tags: fixtures.list("product_tag"), - }) - ) - }), - - rest.get("/admin/products/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product: fixtures.get("product"), - }) - ) - }), - - rest.get("/admin/products/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - products: fixtures.list("product"), - }) - ) - }), - - rest.post("/admin/products/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product: { - ...fixtures.get("product"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/products/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product: { - ...fixtures.get("product"), - ...(req.body as any), - }, - }) - ) - }), - - rest.delete("/admin/products/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "product", - deleted: true, - }) - ) - }), - - rest.post("/admin/products/:id/metadata", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product: fixtures.get("product"), - }) - ) - }), - - rest.post("/admin/products/:id/variants", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product: fixtures.get("product"), - }) - ) - }), - - rest.post("/admin/products/:id/variants/:variant_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product: fixtures.get("product"), - }) - ) - }), - - rest.delete("/admin/products/:id/variants/:variant_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - variant_id: req.params.variant_id, - object: "product-variant", - deleted: true, - product: fixtures.get("product"), - }) - ) - }), - - rest.post("/admin/products/:id/options", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product: fixtures.get("product"), - }) - ) - }), - - rest.post("/admin/products/:id/options/:option_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product: fixtures.get("product"), - }) - ) - }), - - rest.delete("/admin/products/:id/options/:option_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - option_id: req.params.option_id, - object: "option", - deleted: true, - product: fixtures.get("product"), - }) - ) - }), - - rest.get("/admin/regions/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - region: fixtures.get("region"), - }) - ) - }), - - rest.get("/admin/regions/:id/fulfillment-options", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - fulfillment_options: fixtures.get("fulfillment_option"), - }) - ) - }), - - rest.get("/admin/regions/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - regions: fixtures.list("region"), - }) - ) - }), - - rest.post("/admin/regions/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - region: { - ...fixtures.get("region"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/regions/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - region: { - ...fixtures.get("region"), - ...(req.body as any), - }, - }) - ) - }), - - rest.delete("/admin/regions/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "region", - deleted: true, - }) - ) - }), - - rest.post("/admin/regions/:id/metadata", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - region: fixtures.get("region"), - }) - ) - }), - - rest.delete("/admin/regions/:id/metadata/:key", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - region: fixtures.get("region"), - }) - ) - }), - - rest.post("/admin/regions/:id/countries", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - region: fixtures.get("product"), - }) - ) - }), - - rest.delete("/admin/regions/:id/countries/:code", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - region: fixtures.get("product"), - }) - ) - }), - - rest.post("/admin/regions/:id/fulfillment-providers", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - region: fixtures.get("region"), - }) - ) - }), - - rest.delete( - "/admin/regions/:id/fulfillment-providers/:provider_id", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - region: fixtures.get("region"), - }) - ) - } - ), - - rest.delete( - "/admin/regions/:id/payment-providers/:provider_id", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - region: fixtures.get("region"), - }) - ) - } - ), - - rest.post("/admin/regions/:id/payment-providers", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - region: fixtures.get("region"), - }) - ) - }), - - rest.get("/admin/orders/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.get("/admin/orders/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - orders: fixtures.list("order"), - }) - ) - }), - - rest.post("/admin/orders/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: { - ...fixtures.get("order"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/orders/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: { - ...fixtures.get("order"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/orders/:id/complete", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/orders/:id/capture", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/orders/:id/refund", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/orders/:id/fulfillment", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post( - "/admin/orders/:id/fulfillments/:fulfillment_id/cancel", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - } - ), - - rest.post( - "/admin/orders/:id/swaps/:swap_id/fulfillments/:fulfillment_id/cancel", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - } - ), - - rest.post( - "/admin/orders/:id/claims/:claim_id/fulfillments/:fulfillment_id/cancel", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - } - ), - - rest.post("/admin/orders/:id/shipment", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/orders/:id/return", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/orders/:id/cancel", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/orders/:id/shipping-methods", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/orders/:id/archive", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/orders/:id/swaps", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/orders/:id/swaps/:swap_id/cancel", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/orders/:id/swaps/:swap_id/receive", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post( - "/admin/orders/:id/swaps/:swap_id/fulfillments", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - } - ), - - rest.post("/admin/orders/:id/swaps/:swap_id/shipments", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post( - "/admin/orders/:id/swaps/:swap_id/process-payment", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - } - ), - - rest.post("/admin/orders/:id/claims", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/orders/:id/claims/:claim_id/cancel", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post("/admin/orders/:id/claims/:claim_id/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.post( - "/admin/orders/:id/claims/:claim_id/fulfillments", - (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - } - ), - - rest.post("/admin/orders/:id/claims/:claim_id/shipments", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.delete("/admin/orders/:id/metadata/:key", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.get("/admin/order-edits/:id", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - order_edit: fixtures.get("order_edit"), - id, - }) - ) - }), - - rest.get("/admin/order-edits/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - count: 1, - limit: 20, - offset: 0, - order_edits: [fixtures.get("order_edit")], - }) - ) - }), - - rest.post("/admin/order-edits/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order_edit: { - ...fixtures.get("order_edit"), - ...(req.body as any), - }, - }) - ) - }), - - rest.get("/store/order-edits/:id", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - order_edit: fixtures.get("store_order_edit"), - id, - }) - ) - }), - - rest.post("/admin/order-edits/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order_edit: { ...fixtures.get("order_edit"), ...(req.body as any) }, - }) - ) - }), - - rest.post("/admin/order-edits/:id/cancel", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order_edit: { - ...fixtures.get("order_edit"), - canceled_at: new Date(), - status: "canceled", - }, - }) - ) - }), - - rest.post("/admin/order-edits/:id/confirm", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order_edit: { - ...fixtures.get("order_edit"), - confirmed_at: new Date(), - status: "confirmed", - }, - }) - ) - }), - - rest.post("/admin/order-edits/:id/items", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order_edit: { ...fixtures.get("order_edit"), ...(req.body as any) }, - }) - ) - }), - - rest.post("/admin/order-edits/:id/request", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order_edit: { - ...fixtures.get("order_edit"), - requested_at: new Date(), - status: "requested", - }, - }) - ) - }), - - rest.delete("/admin/order-edits/:id", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - id, - object: "order_edit", - deleted: true, - }) - ) - }), - - rest.delete("/admin/order-edits/:id/changes/:change_id", (req, res, ctx) => { - const { change_id } = req.params - return res( - ctx.status(200), - ctx.json({ - id: change_id, - object: "item_change", - deleted: true, - }) - ) - }), - - rest.post("/admin/order-edits/:id/items/:item_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order_edit: { - ...fixtures.get("order_edit"), - changes: [ - { - quantity: (req.body as any).quantity, - }, - ], - }, - }) - ) - }), - - rest.delete("/admin/order-edits/:id/items/:item_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order_edit: { - ...fixtures.get("order_edit"), - changes: [ - { - type: "item_remove", - }, - ], - }, - }) - ) - }), - - rest.get("/admin/auth", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - user: fixtures.get("user"), - }) - ) - }), - - rest.post("/admin/auth", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - user: fixtures.get("user"), - }) - ) - }), - - rest.delete("/admin/auth", (req, res, ctx) => { - return res(ctx.status(200)) - }), - - rest.delete("/admin/uploads", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: (req.body as any).file_key, - object: "file", - deleted: true, - }) - ) - }), - - rest.post("/admin/uploads/download-url", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - download_url: fixtures.get("upload").url, - }) - ) - }), - - rest.get("/admin/sales-channels/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - sales_channel: fixtures.get("sales_channel"), - }) - ) - }), - - rest.get("/admin/sales-channels", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - count: 1, - limit: 20, - offset: 20, - sales_channels: fixtures.get("sales_channels"), - }) - ) - }), - - rest.post("/admin/sales-channels/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - sales_channel: { - ...fixtures.get("sales_channel"), - ...(req.body as any), - }, - }) - ) - }), - - rest.post("/admin/sales-channels", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - sales_channel: fixtures.get("sales_channel"), - ...(req.body as Record), - }) - ) - }), - - rest.delete("/admin/sales-channels/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "sales-channel", - deleted: true, - }) - ) - }), - - rest.delete("/admin/sales-channels/:id/products/batch", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - sales_channel: fixtures.get("sales_channel"), - }) - ) - }), - - rest.post("/admin/sales-channels/:id/products/batch", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - sales_channel: fixtures.get("sales_channel"), - }) - ) - }), - - rest.get("/admin/currencies", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - count: 1, - limit: 20, - offset: 20, - currencies: fixtures.list("currency", 1), - }) - ) - }), - - rest.post("/admin/currencies/:code", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - currency: { ...fixtures.get("currency"), ...(req.body as any) }, - }) - ) - }), - - rest.get("/admin/payment-collections/:id", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - payment_collection: { - ...fixtures.get("payment_collection"), - id, - }, - }) - ) - }), - - rest.delete("/admin/payment-collections/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - id: req.params.id, - object: "payment_collection", - deleted: true, - }) - ) - }), - - rest.post("/admin/payment-collections/:id", (req, res, ctx) => { - const { id } = req.params - const { description, metadata } = req.body as any - - return res( - ctx.status(200), - ctx.json({ - payment_collection: { - ...fixtures.get("payment_collection"), - description, - metadata, - id, - }, - }) - ) - }), - - rest.post("/admin/payment-collections/:id/authorize", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - payment_collection: { - ...fixtures.get("payment_collection"), - id, - }, - }) - ) - }), - - rest.get("/admin/payments/:id", (req, res, ctx) => { - const { id } = req.params - - return res( - ctx.status(200), - ctx.json({ - payment: { - ...fixtures.get("payment"), - id, - }, - }) - ) - }), - - rest.post("/admin/payments/:id/capture", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - payment: { - ...fixtures.get("payment"), - id, - }, - }) - ) - }), - - rest.post("/admin/payments/:id/refund", (req, res, ctx) => { - const { id } = req.params - const { amount, reason, note } = req.body as any - - return res( - ctx.status(200), - ctx.json({ - refund: { - ...fixtures.get("refund"), - payment_id: id, - amount, - reason, - note, - }, - }) - ) - }), -] diff --git a/packages/medusa-react/mocks/handlers/index.ts b/packages/medusa-react/mocks/handlers/index.ts deleted file mode 100644 index ff30045897..0000000000 --- a/packages/medusa-react/mocks/handlers/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./store" -export * from "./admin" diff --git a/packages/medusa-react/mocks/handlers/store.ts b/packages/medusa-react/mocks/handlers/store.ts deleted file mode 100644 index 790a61a3ce..0000000000 --- a/packages/medusa-react/mocks/handlers/store.ts +++ /dev/null @@ -1,564 +0,0 @@ -import { rest } from "msw" -import { fixtures } from "../data" - -export const storeHandlers = [ - rest.get("/store/products", (req, res, ctx) => { - const limit = parseInt(req.url.searchParams.get("limit") || "2") - const offset = parseInt(req.url.searchParams.get("offset") || "0") - return res( - ctx.status(200), - ctx.json({ - products: fixtures.list("product", limit), - offset, - limit, - }) - ) - }), - - rest.get("/store/products/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product: fixtures.get("product"), - }) - ) - }), - - rest.get("/store/collections/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - collections: fixtures.list("product_collection"), - }) - ) - }), - - rest.get("/store/collections/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - collection: fixtures.get("product_collection"), - }) - ) - }), - - rest.get("/store/regions/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - regions: fixtures.list("region"), - }) - ) - }), - - rest.get("/store/regions/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - region: fixtures.get("region"), - }) - ) - }), - - rest.get("/store/gift-cards/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - gift_card: fixtures.get("gift_card"), - }) - ) - }), - - rest.post("/store/order-edits/:id/decline", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order_edit: { - ...fixtures.get("store_order_edit"), - declined_reason: (req.body as any).declined_reason, - status: "declined", - }, - }) - ) - }), - - rest.post("/store/order-edits/:id/complete", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order_edit: { - ...fixtures.get("store_order_edit"), - status: "confirmed", - }, - }) - ) - }), - - rest.get("/store/orders/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.get("/store/orders/cart/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - order: fixtures.get("order"), - }) - ) - }), - - rest.get("/store/orders/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - orders: fixtures.get("order"), - }) - ) - }), - - rest.post("/store/orders/customer/confirm", (req, res, ctx) => { - return res(ctx.status(200)) - }), - - rest.post("/store/orders/batch/customer/token", (req, res, ctx) => { - return res(ctx.status(200)) - }), - - rest.get("/store/return-reasons/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - return_reasons: fixtures.list("return_reason"), - }) - ) - }), - - rest.get("/store/return-reasons/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - return_reason: fixtures.get("return_reason"), - }) - ) - }), - - rest.get("/store/shipping-options/:cart_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - shipping_options: fixtures.list("shipping_option"), - }) - ) - }), - - rest.get("/store/shipping-options/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - shipping_options: fixtures.list("shipping_option", 5), - }) - ) - }), - - rest.get("/store/swaps/:cart_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - swap: fixtures.get("swap"), - }) - ) - }), - - rest.get("/store/customers/me", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - customer: fixtures.get("customer"), - }) - ) - }), - - rest.get("/store/customers/me/orders", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - orders: fixtures.list("order", 5), - limit: 5, - offset: 0, - }) - ) - }), - - rest.post("/store/customers/", (req, res, ctx) => { - const body = req.body as Record - const dummyCustomer = fixtures.get("customer") - const customer = { - ...dummyCustomer, - ...body, - } - - return res( - ctx.status(200), - ctx.json({ - customer, - }) - ) - }), - - rest.post("/store/customers/me", (req, res, ctx) => { - const body = req.body as Record - const dummyCustomer = fixtures.get("customer") - const customer = { - ...dummyCustomer, - ...body, - } - - return res( - ctx.status(200), - ctx.json({ - customer, - }) - ) - }), - - rest.get("/store/carts/:id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - cart: fixtures.get("cart"), - }) - ) - }), - - rest.post("/store/returns/", (req, res, ctx) => { - const { items, ...body } = req.body as Record - const ret = fixtures.get("return") - const item = ret.items[0] - ret.items = items.map((i) => ({ ...i, ...item })) - - return res( - ctx.status(200), - ctx.json({ - return: { - ...ret, - ...body, - }, - }) - ) - }), - - rest.post("/store/swaps/", (req, res, ctx) => { - const { additional_items, return_items, ...body } = req.body as Record< - string, - any - > - const swap = fixtures.get("swap") - const additional_item = swap.additional_items[0] - swap.additional_items = additional_items.map((i) => ({ - ...i, - ...additional_item, - })) - const return_item = swap.return_order.items[0] - swap.return_order.items = return_items.map((i) => ({ - ...i, - ...return_item, - })) - - return res( - ctx.status(200), - ctx.json({ - swap: { - ...swap, - ...body, - }, - }) - ) - }), - - rest.post("/store/carts/:id/line-items", (req, res, ctx) => { - const { id } = req.params - const { quantity, variant_id } = req.body as Record - const item = fixtures.get("line_item") - return res( - ctx.status(200), - ctx.json({ - cart: { - ...fixtures.get("cart"), - id, - items: [ - { - ...item, - quantity, - variant_id, - }, - ], - }, - }) - ) - }), - - rest.post("/store/carts/:id/line-items/:line_id", (req, res, ctx) => { - const { id, line_id } = req.params - const { quantity } = req.body as Record - const item = fixtures.get("line_item") - return res( - ctx.status(200), - ctx.json({ - cart: { - ...fixtures.get("cart"), - id, - items: [ - { - ...item, - id: line_id, - quantity, - }, - ], - }, - }) - ) - }), - - rest.delete("/store/carts/:id/line-items/:line_id", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - cart: fixtures.get("cart"), - }) - ) - }), - - rest.post("/store/carts/", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - cart: fixtures.get("cart"), - }) - ) - }), - - rest.post("/store/carts/:id", (req, res, ctx) => { - const { id } = req.params - const body = req.body as Record - return res( - ctx.status(200), - ctx.json({ - cart: { - ...fixtures.get("cart"), - id, - ...body, - }, - }) - ) - }), - - rest.post("/store/carts/:id/complete", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - type: "order", - data: fixtures.get("order"), - }) - ) - }), - - rest.post("/store/carts/:id/payment-sessions", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - cart: { - ...fixtures.get("cart"), - id, - }, - }) - ) - }), - - rest.post( - "/store/carts/:id/payment-sessions/:provider_id", - (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - cart: { - ...fixtures.get("cart"), - id, - }, - }) - ) - } - ), - - rest.post( - "/store/carts/:id/payment-sessions/:provider_id/refresh", - (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - cart: { - ...fixtures.get("cart"), - id, - }, - }) - ) - } - ), - - rest.post("/store/carts/:id/payment-session", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - cart: { - ...fixtures.get("cart"), - id, - }, - }) - ) - }), - - rest.delete( - "/store/carts/:id/payment-sessions/:provider_id", - (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - cart: { - ...fixtures.get("cart"), - id, - }, - }) - ) - } - ), - - rest.post("/store/carts/:id/shipping-methods", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - cart: { - ...fixtures.get("cart"), - id, - }, - }) - ) - }), - - rest.get("/store/payment-collections/:id", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - payment_collection: { - ...fixtures.get("payment_collection"), - id, - }, - }) - ) - }), - - rest.post( - "/store/payment-collections/:id/sessions/batch", - (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - payment_collection: { - ...fixtures.get("payment_collection"), - id, - }, - }) - ) - } - ), - - rest.post( - "/store/payment-collections/:id/sessions/batch/authorize", - (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(207), - ctx.json({ - payment_collection: { - ...fixtures.get("payment_collection"), - id, - }, - }) - ) - } - ), - - rest.post("/store/payment-collections/:id/sessions", (req, res, ctx) => { - const { id } = req.params - return res( - ctx.status(200), - ctx.json({ - payment_collection: { - ...fixtures.get("payment_collection"), - id, - }, - }) - ) - }), - - rest.post( - "/store/payment-collections/:id/sessions/:session_id", - (req, res, ctx) => { - const { id, session_id } = req.params - const payCol: any = { ...fixtures.get("payment_collection") } - - payCol.payment_sessions[0].id = `new_${session_id}` - const session = { - payment_session: payCol.payment_sessions[0], - } - - return res( - ctx.status(200), - ctx.json({ - ...session, - }) - ) - } - ), - - rest.post( - "/store/payment-collections/:id/sessions/:session_id/authorize", - (req, res, ctx) => { - const { session_id } = req.params - - const session = fixtures.get("payment_collection").payment_sessions[0] - return res( - ctx.status(200), - ctx.json({ - payment_session: { - ...session, - id: session_id, - }, - }) - ) - } - ), - - rest.get("/store/product-tags", (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - product_tags: fixtures.list("product_tag", 10), - limit: 5, - offset: 0, - }) - ) - }), -] diff --git a/packages/medusa-react/mocks/server.ts b/packages/medusa-react/mocks/server.ts deleted file mode 100644 index b19115e9e6..0000000000 --- a/packages/medusa-react/mocks/server.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { setupServer } from "msw/node" -import { storeHandlers, adminHandlers } from "./handlers" - -export const server = setupServer(...storeHandlers, ...adminHandlers) diff --git a/packages/medusa-react/package.json b/packages/medusa-react/package.json deleted file mode 100644 index 837fcb971e..0000000000 --- a/packages/medusa-react/package.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "version": "9.0.17", - "license": "MIT", - "main": "dist/index.js", - "module": "dist/index.mjs", - "types": "dist/index.d.ts", - "exports": { - ".": { - "import": "./dist/index.mjs", - "require": "./dist/index.js", - "types": "./dist/index.d.ts" - }, - "./package.json": "./package.json" - }, - "files": [ - "dist" - ], - "engines": { - "node": ">=10" - }, - "scripts": { - "build": "tsup src/index.ts", - "prepare": "cross-env NODE_ENV=production yarn run build", - "storybook": "start-storybook -p 6006 -s public", - "build-storybook": "build-storybook", - "test": "echo \"Tests disabled temporarily\"" - }, - "peerDependencies": { - "@medusajs/medusa": "^1.17.2", - "@tanstack/react-query": "^4.22.0", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - }, - "name": "medusa-react", - "author": "Zakaria S. El Asri", - "devDependencies": { - "@babel/core": "^7.16.0", - "@medusajs/medusa": "^1.20.5", - "@storybook/addon-essentials": "^6.3.12", - "@storybook/addon-links": "^6.3.12", - "@storybook/addons": "^6.3.12", - "@storybook/react": "^6.3.12", - "@tanstack/react-query": "4.22.0", - "@testing-library/react": "^13.4.0", - "@testing-library/react-hooks": "^8.0.1", - "@types/jest": "^27.0.3", - "@types/react": "^17.0.53", - "@types/react-dom": "^17.0.18", - "axios": "^0.24.0", - "babel-loader": "^8.2.3", - "cross-env": "^5.2.1", - "jest": "^29.4.1", - "jest-environment-jsdom": "^29.4.1", - "msw": "^0.35.0", - "msw-storybook-addon": "^1.5.0", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "react-is": "^17.0.2", - "react-json-view": "^1.21.3", - "ts-jest": "^29.0.5", - "tslib": "^2.3.1", - "tsup": "6.7.0" - }, - "dependencies": { - "@medusajs/medusa-js": "*" - }, - "msw": { - "workerDirectory": "public" - }, - "gitHead": "cd1f5afa5aa8c0b15ea957008ee19f1d695cbd2e" -} diff --git a/packages/medusa-react/public/mockServiceWorker.js b/packages/medusa-react/public/mockServiceWorker.js deleted file mode 100644 index 86167669ad..0000000000 --- a/packages/medusa-react/public/mockServiceWorker.js +++ /dev/null @@ -1,338 +0,0 @@ -/* eslint-disable */ -/* tslint:disable */ - -/** - * Mock Service Worker (0.35.0). - * @see https://github.com/mswjs/msw - * - Please do NOT modify this file. - * - Please do NOT serve this file on production. - */ - -const INTEGRITY_CHECKSUM = 'f0a916b13c8acc2b526a03a6d26df85f' -const bypassHeaderName = 'x-msw-bypass' -const activeClientIds = new Set() - -self.addEventListener('install', function () { - return self.skipWaiting() -}) - -self.addEventListener('activate', async function (event) { - return self.clients.claim() -}) - -self.addEventListener('message', async function (event) { - const clientId = event.source.id - - if (!clientId || !self.clients) { - return - } - - const client = await self.clients.get(clientId) - - if (!client) { - return - } - - const allClients = await self.clients.matchAll() - - switch (event.data) { - case 'KEEPALIVE_REQUEST': { - sendToClient(client, { - type: 'KEEPALIVE_RESPONSE', - }) - break - } - - case 'INTEGRITY_CHECK_REQUEST': { - sendToClient(client, { - type: 'INTEGRITY_CHECK_RESPONSE', - payload: INTEGRITY_CHECKSUM, - }) - break - } - - case 'MOCK_ACTIVATE': { - activeClientIds.add(clientId) - - sendToClient(client, { - type: 'MOCKING_ENABLED', - payload: true, - }) - break - } - - case 'MOCK_DEACTIVATE': { - activeClientIds.delete(clientId) - break - } - - case 'CLIENT_CLOSED': { - activeClientIds.delete(clientId) - - const remainingClients = allClients.filter((client) => { - return client.id !== clientId - }) - - // Unregister itself when there are no more clients - if (remainingClients.length === 0) { - self.registration.unregister() - } - - break - } - } -}) - -// Resolve the "master" client for the given event. -// Client that issues a request doesn't necessarily equal the client -// that registered the worker. It's with the latter the worker should -// communicate with during the response resolving phase. -async function resolveMasterClient(event) { - const client = await self.clients.get(event.clientId) - - if (client.frameType === 'top-level') { - return client - } - - const allClients = await self.clients.matchAll() - - return allClients - .filter((client) => { - // Get only those clients that are currently visible. - return client.visibilityState === 'visible' - }) - .find((client) => { - // Find the client ID that's recorded in the - // set of clients that have registered the worker. - return activeClientIds.has(client.id) - }) -} - -async function handleRequest(event, requestId) { - const client = await resolveMasterClient(event) - const response = await getResponse(event, client, requestId) - - // Send back the response clone for the "response:*" life-cycle events. - // Ensure MSW is active and ready to handle the message, otherwise - // this message will pend indefinitely. - if (client && activeClientIds.has(client.id)) { - ;(async function () { - const clonedResponse = response.clone() - sendToClient(client, { - type: 'RESPONSE', - payload: { - requestId, - type: clonedResponse.type, - ok: clonedResponse.ok, - status: clonedResponse.status, - statusText: clonedResponse.statusText, - body: - clonedResponse.body === null ? null : await clonedResponse.text(), - headers: serializeHeaders(clonedResponse.headers), - redirected: clonedResponse.redirected, - }, - }) - })() - } - - return response -} - -async function getResponse(event, client, requestId) { - const { request } = event - const requestClone = request.clone() - const getOriginalResponse = () => fetch(requestClone) - - // Bypass mocking when the request client is not active. - if (!client) { - return getOriginalResponse() - } - - // Bypass initial page load requests (i.e. static assets). - // The absence of the immediate/parent client in the map of the active clients - // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet - // and is not ready to handle requests. - if (!activeClientIds.has(client.id)) { - return await getOriginalResponse() - } - - // Bypass requests with the explicit bypass header - if (requestClone.headers.get(bypassHeaderName) === 'true') { - const cleanRequestHeaders = serializeHeaders(requestClone.headers) - - // Remove the bypass header to comply with the CORS preflight check. - delete cleanRequestHeaders[bypassHeaderName] - - const originalRequest = new Request(requestClone, { - headers: new Headers(cleanRequestHeaders), - }) - - return fetch(originalRequest) - } - - // Send the request to the client-side MSW. - const reqHeaders = serializeHeaders(request.headers) - const body = await request.text() - - const clientMessage = await sendToClient(client, { - type: 'REQUEST', - payload: { - id: requestId, - url: request.url, - method: request.method, - headers: reqHeaders, - cache: request.cache, - mode: request.mode, - credentials: request.credentials, - destination: request.destination, - integrity: request.integrity, - redirect: request.redirect, - referrer: request.referrer, - referrerPolicy: request.referrerPolicy, - body, - bodyUsed: request.bodyUsed, - keepalive: request.keepalive, - }, - }) - - switch (clientMessage.type) { - case 'MOCK_SUCCESS': { - return delayPromise( - () => respondWithMock(clientMessage), - clientMessage.payload.delay, - ) - } - - case 'MOCK_NOT_FOUND': { - return getOriginalResponse() - } - - case 'NETWORK_ERROR': { - const { name, message } = clientMessage.payload - const networkError = new Error(message) - networkError.name = name - - // Rejecting a request Promise emulates a network error. - throw networkError - } - - case 'INTERNAL_ERROR': { - const parsedBody = JSON.parse(clientMessage.payload.body) - - console.error( - `\ -[MSW] Uncaught exception in the request handler for "%s %s": - -${parsedBody.location} - -This exception has been gracefully handled as a 500 response, however, it's strongly recommended to resolve this error, as it indicates a mistake in your code. If you wish to mock an error response, please see this guide: https://mswjs.io/docs/recipes/mocking-error-responses\ -`, - request.method, - request.url, - ) - - return respondWithMock(clientMessage) - } - } - - return getOriginalResponse() -} - -self.addEventListener('fetch', function (event) { - const { request } = event - const accept = request.headers.get('accept') || '' - - // Bypass server-sent events. - if (accept.includes('text/event-stream')) { - return - } - - // Bypass navigation requests. - if (request.mode === 'navigate') { - return - } - - // Opening the DevTools triggers the "only-if-cached" request - // that cannot be handled by the worker. Bypass such requests. - if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { - return - } - - // Bypass all requests when there are no active clients. - // Prevents the self-unregistered worked from handling requests - // after it's been deleted (still remains active until the next reload). - if (activeClientIds.size === 0) { - return - } - - const requestId = uuidv4() - - return event.respondWith( - handleRequest(event, requestId).catch((error) => { - if (error.name === 'NetworkError') { - console.warn( - '[MSW] Successfully emulated a network error for the "%s %s" request.', - request.method, - request.url, - ) - return - } - - // At this point, any exception indicates an issue with the original request/response. - console.error( - `\ -[MSW] Caught an exception from the "%s %s" request (%s). This is probably not a problem with Mock Service Worker. There is likely an additional logging output above.`, - request.method, - request.url, - `${error.name}: ${error.message}`, - ) - }), - ) -}) - -function serializeHeaders(headers) { - const reqHeaders = {} - headers.forEach((value, name) => { - reqHeaders[name] = reqHeaders[name] - ? [].concat(reqHeaders[name]).concat(value) - : value - }) - return reqHeaders -} - -function sendToClient(client, message) { - return new Promise((resolve, reject) => { - const channel = new MessageChannel() - - channel.port1.onmessage = (event) => { - if (event.data && event.data.error) { - return reject(event.data.error) - } - - resolve(event.data) - } - - client.postMessage(JSON.stringify(message), [channel.port2]) - }) -} - -function delayPromise(cb, duration) { - return new Promise((resolve) => { - setTimeout(() => resolve(cb()), duration) - }) -} - -function respondWithMock(clientMessage) { - return new Response(clientMessage.payload.body, { - ...clientMessage.payload, - headers: clientMessage.payload.headers, - }) -} - -function uuidv4() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - const r = (Math.random() * 16) | 0 - const v = c == 'x' ? r : (r & 0x3) | 0x8 - return v.toString(16) - }) -} diff --git a/packages/medusa-react/src/contexts/cart.tsx b/packages/medusa-react/src/contexts/cart.tsx deleted file mode 100644 index 997a9d127f..0000000000 --- a/packages/medusa-react/src/contexts/cart.tsx +++ /dev/null @@ -1,239 +0,0 @@ -/** - * @packageDocumentation - * - * @customNamespace Providers.Cart - */ - -import React, { useState } from "react" -import { - useAddShippingMethodToCart, - useCompleteCart, - useCreateCart, - useSetPaymentSession, - useUpdateCart, - useCreatePaymentSession, -} from "../hooks/store/" -import { Cart } from "../types" - -interface CartState { - /** - * The currently-used cart. - */ - cart?: Cart -} - -/** - * The cart context available if the {@link CartProvider} is used previously in the React components tree. - */ -export interface CartContext extends CartState { - /** - * A state function used to set the cart object. - * - * @param {Cart} cart - The new value of the cart. - */ - setCart: (cart: Cart) => void - /** - * A mutation used to select a payment processor during checkout. - * Using it is equivalent to using the {@link useSetPaymentSession} mutation. - */ - pay: ReturnType - /** - * A mutation used to create a cart. - * Using it is equivalent to using the {@link useCreateCart} mutation. - */ - createCart: ReturnType - /** - * A mutation used to initialize payment sessions during checkout. - * Using it is equivalent to using the {@link useCreatePaymentSession} mutation. - */ - startCheckout: ReturnType - /** - * A mutation used to complete the cart and place the order. - * Using it is equivalent to using the {@link useCompleteCart} mutation. - */ - completeCheckout: ReturnType - /** - * A mutation used to update a cart’s details such as region, customer email, shipping address, and more. - * Using it is equivalent to using the {@link useUpdateCart} mutation. - */ - updateCart: ReturnType - /** - * A mutation used to add a shipping method to the cart during checkout. - * Using it is equivalent to using the {@link useAddShippingMethodToCart} mutation. - */ - addShippingMethod: ReturnType - /** - * The number of items in the cart. - */ - totalItems: number -} - -const CartContext = React.createContext(null) - -/** - * This hook exposes the context of {@link CartProvider}. - * - * The context provides helper functions and mutations for managing the cart and checkout. You can refer to the following guides for examples on how to use them: - * - * - [How to Add Cart Functionality](https://docs.medusajs.com/modules/carts-and-checkout/storefront/implement-cart) - * - [How to Implement Checkout Flow](https://docs.medusajs.com/modules/carts-and-checkout/storefront/implement-checkout-flow) - * - * @example - * ```tsx title="src/Cart.ts" - * import * as React from "react" - * - * import { useCart } from "medusa-react" - * - * const Cart = () => { - * const handleClick = () => { - * createCart.mutate({}) // create an empty cart - * } - * - * const { cart, createCart } = useCart() - * - * return ( - *
- * {createCart.isLoading &&
Loading...
} - * {!cart?.id && ( - * - * )} - * {cart?.id && ( - *
Cart ID: {cart.id}
- * )} - *
- * ) - * } - * - * export default Cart - * ``` - * - * In the example above, you retrieve the `createCart` mutation and `cart` state object using the `useCart` hook. - * If the `cart` is not set, a button is shown. When the button is clicked, the `createCart` mutation is executed, which interacts with the backend and creates a new cart. - * - * After the cart is created, the `cart` state variable is set and its ID is shown instead of the button. - * - * :::note - * - * The example above does not store in the browser the ID of the cart created, so the cart’s data will be gone on refresh. - * You would have to do that using the browser’s [Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). - * - * ::: - * - * @customNamespace Providers.Cart - */ -export const useCart = () => { - const context = React.useContext(CartContext) - if (!context) { - throw new Error("useCart must be used within a CartProvider") - } - return context -} - -export interface CartProps { - /** - * @ignore - */ - children: React.ReactNode - /** - * An optional initial value to be used for the cart. - */ - initialState?: Cart -} - -const defaultInitialState = { - id: "", - items: [] as any, -} as Cart - -/** - * `CartProvider` makes use of some of the hooks already exposed by `medusa-react` to perform cart operations on the Medusa backend. - * You can use it to create a cart, start the checkout flow, authorize payment sessions, and so on. - * - * It also manages one single global piece of state which represents a cart, exactly like the one created on your Medusa backend. - * - * To use `CartProvider`, you first have to insert it somewhere in your component tree below the {@link Providers.Medusa.MedusaProvider | MedusaProvider}. Then, in any of the child components, - * you can use the {@link useCart} hook exposed by `medusa-react` to get access to cart operations and data. - * - * @param {CartProps} param0 - Props of the provider. - * - * @example - * ```tsx title="src/App.ts" - * import { CartProvider, MedusaProvider } from "medusa-react" - * import Storefront from "./Storefront" - * import { QueryClient } from "@tanstack/react-query" - * import React from "react" - * - * const queryClient = new QueryClient() - * - * function App() { - * return ( - * - * - * - * - * - * ) - * } - * - * export default App - * ``` - * - * @customNamespace Providers.Cart - */ -export const CartProvider = ({ - children, - initialState = defaultInitialState, -}: CartProps) => { - const [cart, setCart] = useState(initialState) - - const createCart = useCreateCart({ - onSuccess: ({ cart }) => setCart(cart), - }) - - const updateCart = useUpdateCart(cart?.id, { - onSuccess: ({ cart }) => setCart(cart), - }) - - const addShippingMethod = useAddShippingMethodToCart(cart?.id, { - onSuccess: ({ cart }) => setCart(cart), - }) - - const startCheckout = useCreatePaymentSession(cart?.id, { - onSuccess: ({ cart }) => setCart(cart), - }) - - const pay = useSetPaymentSession(cart?.id, { - onSuccess: ({ cart }) => { - setCart(cart) - }, - }) - - const completeCheckout = useCompleteCart(cart?.id) - - const totalItems = cart?.items - .map(i => i.quantity) - .reduce((acc, curr) => acc + curr, 0) - - return ( - - {children} - - ) -} diff --git a/packages/medusa-react/src/contexts/index.ts b/packages/medusa-react/src/contexts/index.ts deleted file mode 100644 index 2a239e8448..0000000000 --- a/packages/medusa-react/src/contexts/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * :::info - * - * This is an experimental feature. - * - * ::: - * - * `medusa-react` exposes React Context Providers that facilitate building custom storefronts. - * - * @customNamespace Providers - */ - -export * from "./medusa" -export * from "./session-cart" -export * from "./cart" diff --git a/packages/medusa-react/src/contexts/medusa.tsx b/packages/medusa-react/src/contexts/medusa.tsx deleted file mode 100644 index 3e09288cc6..0000000000 --- a/packages/medusa-react/src/contexts/medusa.tsx +++ /dev/null @@ -1,171 +0,0 @@ -/** - * @packageDocumentation - * - * @customNamespace Providers.Medusa - */ - -import Medusa from "@medusajs/medusa-js" -import { - QueryClientProvider, - QueryClientProviderProps, -} from "@tanstack/react-query" -import React from "react" - -export interface MedusaContextState { - /** - * The Medusa JS Client instance. - */ - client: Medusa -} - -const MedusaContext = React.createContext(null) - -/** - * This hook gives you access to context of {@link MedusaProvider}. It's useful if you want access to the - * [Medusa JS Client](https://docs.medusajs.com/js-client/overview). - * - * @example - * import React from "react" - * import { useMeCustomer, useMedusa } from "medusa-react" - * - * const CustomerLogin = () => { - * const { client } = useMedusa() - * const { refetch: refetchCustomer } = useMeCustomer() - * // ... - * - * const handleLogin = ( - * email: string, - * password: string - * ) => { - * client.auth.authenticate({ - * email, - * password - * }) - * .then(() => { - * // customer is logged-in successfully - * refetchCustomer() - * }) - * .catch(() => { - * // an error occurred. - * }) - * } - * - * // ... - * } - * - * @customNamespace Providers.Medusa - */ -export const useMedusa = () => { - const context = React.useContext(MedusaContext) - if (!context) { - throw new Error("useMedusa must be used within a MedusaProvider") - } - return context -} - -export interface MedusaProviderProps { - /** - * The URL to your Medusa backend. - */ - baseUrl: string - /** - * An object used to set the Tanstack Query client. The object requires a `client` property, - * which should be an instance of [QueryClient](https://tanstack.com/query/v4/docs/react/reference/QueryClient). - */ - queryClientProviderProps: QueryClientProviderProps - /** - * @ignore - */ - children: React.ReactNode - /** - * API key used for authenticating admin requests. Follow [this guide](https://docs.medusajs.com/api/admin#authentication) to learn how to create an API key for an admin user. - */ - apiKey?: string - /** - * Publishable API key used for storefront requests. You can create a publishable API key either using the - * [admin APIs](https://docs.medusajs.com/development/publishable-api-keys/admin/manage-publishable-api-keys) or the - * [Medusa admin](https://docs.medusajs.com/user-guide/settings/publishable-api-keys#create-publishable-api-key). - */ - publishableApiKey?: string - /** - * Number of times to retry a request if it fails. - * - * @defaultValue 3 - */ - maxRetries?: number - /** - * An object of custom headers to pass with every request. Each key of the object is the name of the header, and its value is the header's value. - * - * @defaultValue `{}` - */ - customHeaders?: Record - /** - * An instance of the Medusa JS Client. If you don't provide an instance, one will be created using the `baseUrl`, `apiKey`, - * `publishableApiKey`, `maxRetries`, and `customHeaders` props. - */ - medusaClient?: Medusa -} - -/** - * The `MedusaProvider` must be used at the highest possible point in the React component tree. Using any of `medusa-react`'s hooks or providers requires having `MedusaProvider` - * higher in the component tree. - * - * @param {MedusaProviderProps} param0 - Props of the provider. - * - * @example - * ```tsx title="src/App.ts" - * import { MedusaProvider } from "medusa-react" - * import Storefront from "./Storefront" - * import { QueryClient } from "@tanstack/react-query" - * import React from "react" - * - * const queryClient = new QueryClient() - * - * const App = () => { - * return ( - * - * - * - * ) - * } - * - * export default App - * ``` - * - * In the example above, you wrap the `Storefront` component with the `MedusaProvider`. `Storefront` is assumed to be the top-level component of your storefront, but you can place `MedusaProvider` at any point in your tree. Only children of `MedusaProvider` can benefit from its hooks. - * - * The `Storefront` component and its child components can now use hooks exposed by Medusa React. - * - * @customNamespace Providers.Medusa - */ -export const MedusaProvider = ({ - queryClientProviderProps, - baseUrl, - apiKey, - publishableApiKey, - customHeaders, - maxRetries = 3, - children, - medusaClient = new Medusa({ - baseUrl, - maxRetries, - apiKey, - publishableApiKey, - customHeaders, - }), -}: MedusaProviderProps) => { - return ( - - - {children} - - - ) -} diff --git a/packages/medusa-react/src/contexts/session-cart.tsx b/packages/medusa-react/src/contexts/session-cart.tsx deleted file mode 100644 index 83e043d3bf..0000000000 --- a/packages/medusa-react/src/contexts/session-cart.tsx +++ /dev/null @@ -1,439 +0,0 @@ -/** - * @packageDocumentation - * - * @customNamespace Providers.Session Cart - */ - -import React, { useContext, useEffect } from "react" -import { getVariantPrice } from "../helpers" -import { useLocalStorage } from "../hooks/utils" -import { ProductVariant, RegionInfo } from "../types" -import { isArray, isEmpty, isObject } from "../utils" - -/** - * A session cart's item. - */ -export interface Item { - /** - * The product variant represented by this item in the cart. - */ - variant: ProductVariant - /** - * The quantity added in the cart. - */ - quantity: number - /** - * The total amount of the item in the cart. - */ - readonly total?: number -} - -export interface SessionCartState { - /** - * The region of the cart. - */ - region: RegionInfo - /** - * The items in the cart. - */ - items: Item[] - /** - * The total items in the cart. - */ - totalItems: number - /** - * The total amount of the cart. - */ - total: number -} - -export interface SessionCartContextState extends SessionCartState { - /** - * A state function used to set the region. - * - * @param region - The new value of the region. - */ - setRegion: (region: RegionInfo) => void - /** - * This function adds an item to the session cart. - * - * @param {Item} item - The item to add. - */ - addItem: (item: Item) => void - /** - * This function removes an item from the session cart. - * - * @param {string} id - The ID of the item. - */ - removeItem: (id: string) => void - /** - * This function updates an item in the session cart. - * - * @param {string} id - The ID of the item. - * @param {Partial} item - The item's data to update. - */ - updateItem: (id: string, item: Partial) => void - /** - * A state function used to set the items in the cart. - * - * @param {Item[]} items - The items to set in the cart. - */ - setItems: (items: Item[]) => void - /** - * This function updates an item's quantity in the cart. - * - * @param {string} id - The ID of the item. - * @param {number} quantity - The new quantity of the item. - */ - updateItemQuantity: (id: string, quantity: number) => void - /** - * This function increments the item's quantity in the cart. - * - * @param {string} id - The ID of the item. - */ - incrementItemQuantity: (id: string) => void - /** - * This function decrements the item's quantity in the cart. - * - * @param {string} id - The ID of the item. - */ - decrementItemQuantity: (id: string) => void - /** - * This function retrieves an item's details by its ID. - * - * @param {string} id - The ID of the item. - * @returns {Item | undefined} The item in the cart, if found. - */ - getItem: (id: string) => Item | undefined - /** - * Removes all items in the cart. - */ - clearItems: () => void -} - -const SessionCartContext = React.createContext( - null -) - -enum ACTION_TYPES { - INIT, - ADD_ITEM, - SET_ITEMS, - REMOVE_ITEM, - UPDATE_ITEM, - CLEAR_ITEMS, - SET_REGION, -} - -type Action = - | { type: ACTION_TYPES.SET_REGION; payload: RegionInfo } - | { type: ACTION_TYPES.INIT; payload: object } - | { type: ACTION_TYPES.ADD_ITEM; payload: Item } - | { - type: ACTION_TYPES.UPDATE_ITEM - payload: { id: string; item: Partial } - } - | { type: ACTION_TYPES.REMOVE_ITEM; payload: { id: string } } - | { type: ACTION_TYPES.SET_ITEMS; payload: Item[] } - | { type: ACTION_TYPES.CLEAR_ITEMS } - -const reducer = (state: SessionCartState, action: Action) => { - switch (action.type) { - case ACTION_TYPES.INIT: { - return state - } - case ACTION_TYPES.SET_REGION: { - return generateCartState( - { - ...state, - region: action.payload, - }, - state.items - ) - } - case ACTION_TYPES.ADD_ITEM: { - const duplicateVariantIndex = state.items.findIndex( - (item) => item.variant.id === action.payload?.variant?.id - ) - if (duplicateVariantIndex !== -1) { - state.items.splice(duplicateVariantIndex, 1) - } - const items = [...state.items, action.payload] - return generateCartState(state, items) - } - case ACTION_TYPES.UPDATE_ITEM: { - const items = state.items.map((item) => - item.variant.id === action.payload.id - ? { ...item, ...action.payload.item } - : item - ) - - return generateCartState(state, items) - } - case ACTION_TYPES.REMOVE_ITEM: { - const items = state.items.filter( - (item) => item.variant.id !== action.payload.id - ) - return generateCartState(state, items) - } - case ACTION_TYPES.SET_ITEMS: { - return generateCartState(state, action.payload) - } - case ACTION_TYPES.CLEAR_ITEMS: { - return { - ...state, - items: [], - total: 0, - totalItems: 0, - } - } - default: - return state - } -} - -/** - * @ignore - */ -export const generateCartState = (state: SessionCartState, items: Item[]) => { - const newItems = generateItems(state.region, items) - return { - ...state, - items: newItems, - totalItems: items.reduce((sum, item) => sum + item.quantity, 0), - total: calculateSessionCartTotal(newItems), - } -} - -const generateItems = (region: RegionInfo, items: Item[]) => { - return items.map((item) => ({ - ...item, - total: getVariantPrice(item.variant, region), - })) -} - -const calculateSessionCartTotal = (items: Item[]) => { - return items.reduce( - (total, item) => total + item.quantity * (item.total || 0), - 0 - ) -} - -export interface SessionCartProviderProps { - /** - * @ignore - */ - children: React.ReactNode - /** - * An optional initial value to be used for the session cart. - */ - initialState?: SessionCartState -} - -const defaultInitialState: SessionCartState = { - region: {} as RegionInfo, - items: [], - total: 0, - totalItems: 0, -} - -/** - * Unlike the {@link Providers.Cart.CartProvider | CartProvider}, `SessionProvider` never interacts with the Medusa backend. It can be used to implement the user experience related to managing a cart’s items. - * Its state variables are JavaScript objects living in the browser, but are in no way communicated with the backend. - * - * You can use the `SessionProvider` as a lightweight client-side cart functionality. It’s not stored in any database or on the Medusa backend. - * - * To use `SessionProvider`, you first have to insert it somewhere in your component tree below the {@link Providers.Medusa.MedusaProvider | MedusaProvider}. Then, in any of the child components, - * you can use the {@link useSessionCart} hook to get access to client-side cart item functionalities. - * - * @param {SessionCartProviderProps} param0 - Props of the provider. - * - * @example - * ```tsx title="src/App.ts" - * import { SessionProvider, MedusaProvider } from "medusa-react" - * import Storefront from "./Storefront" - * import { QueryClient } from "@tanstack/react-query" - * import React from "react" - * - * const queryClient = new QueryClient() - * - * const App = () => { - * return ( - * - * - * - * - * - * ) - * } - * - * export default App - * ``` - * - * @customNamespace Providers.Session Cart - */ -export const SessionCartProvider = ({ - initialState = defaultInitialState, - children, -}: SessionCartProviderProps) => { - const [saved, save] = useLocalStorage( - "medusa-session-cart", - JSON.stringify(initialState) - ) - - const [state, dispatch] = React.useReducer(reducer, JSON.parse(saved)) - - useEffect(() => { - save(JSON.stringify(state)) - }, [state, save]) - - const setRegion = (region: RegionInfo) => { - if (!isObject(region) || isEmpty(region)) { - throw new Error("region must be a non-empty object") - } - - dispatch({ type: ACTION_TYPES.SET_REGION, payload: region }) - } - - const getItem = (id: string) => { - return state.items.find((item) => item.variant.id === id) - } - - const setItems = (items: Item[]) => { - if (!isArray(items)) { - throw new Error("items must be an array of items") - } - - dispatch({ type: ACTION_TYPES.SET_ITEMS, payload: items }) - } - - const addItem = (item: Item) => { - if (!isObject(item) || isEmpty(item)) { - throw new Error("item must be a non-empty object") - } - - dispatch({ type: ACTION_TYPES.ADD_ITEM, payload: item }) - } - - const updateItem = (id: string, item: Partial) => { - dispatch({ type: ACTION_TYPES.UPDATE_ITEM, payload: { id, item } }) - } - - const updateItemQuantity = (id: string, quantity: number) => { - const item = getItem(id) - if (!item) return - - quantity = quantity <= 0 ? 1 : quantity - - dispatch({ - type: ACTION_TYPES.UPDATE_ITEM, - payload: { - id, - item: { - ...item, - quantity: Math.min(item.variant.inventory_quantity, quantity), - }, - }, - }) - } - - const incrementItemQuantity = (id: string) => { - const item = getItem(id) - if (!item) return - - dispatch({ - type: ACTION_TYPES.UPDATE_ITEM, - payload: { - id, - item: { - ...item, - quantity: Math.min( - item.variant.inventory_quantity, - item.quantity + 1 - ), - }, - }, - }) - } - - const decrementItemQuantity = (id: string) => { - const item = getItem(id) - if (!item) return - - dispatch({ - type: ACTION_TYPES.UPDATE_ITEM, - payload: { - id, - item: { ...item, quantity: Math.max(0, item.quantity - 1) }, - }, - }) - } - - const removeItem = (id: string) => { - dispatch({ - type: ACTION_TYPES.REMOVE_ITEM, - payload: { id }, - }) - } - - const clearItems = () => { - dispatch({ - type: ACTION_TYPES.CLEAR_ITEMS, - }) - } - - return ( - - {children} - - ) -} - -/** - * This hook exposes the context of {@link SessionCartProvider}. - * - * @example - * The following example assumes that you've added `SessionCartProvider` previously in the React components tree: - * - * ```tsx title="src/Products.ts" - * const Products = () => { - * const { addItem } = useSessionCart() - * // ... - * - * function addToCart(variant: ProductVariant) { - * addItem({ - * variant: variant, - * quantity: 1, - * }) - * } - * } - * ``` - * - * @customNamespace Providers.Session Cart - */ -export const useSessionCart = () => { - const context = useContext(SessionCartContext) - if (!context) { - throw new Error( - "useSessionCart should be used as a child of SessionCartProvider" - ) - } - return context -} diff --git a/packages/medusa-react/src/helpers/index.ts b/packages/medusa-react/src/helpers/index.ts deleted file mode 100644 index 059ebe7119..0000000000 --- a/packages/medusa-react/src/helpers/index.ts +++ /dev/null @@ -1,434 +0,0 @@ -/** - * @packageDocumentation - * - * `medusa-react` exposes a set of utility functions that are mainly used to retrieve or format the price of a product variant. - * - * @customNamespace Utilities - */ - -import { ProductVariantInfo, RegionInfo } from "../types" -import { isEmpty } from "../utils" - -/** - * @interface - * - * Options to format a variant's price. - */ -export type FormatVariantPriceParams = { - /** - * A variant's details. - */ - variant: ProductVariantInfo - /** - * A region's details. - */ - region: RegionInfo - /** - * Whether the computed price should include taxes or not. - * - * @defaultValue true - */ - includeTaxes?: boolean - /** - * The minimum number of fraction digits to use when formatting the price. This is passed as an option to `Intl.NumberFormat` in the underlying layer. - * You can learn more about this method’s options in - * [MDN’s documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#parameters). - */ - minimumFractionDigits?: number - /** - * The maximum number of fraction digits to use when formatting the price. This is passed as an option to `Intl.NumberFormat` which is used within the utility method. - * You can learn more about this method’s options in - * [MDN’s documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#parameters). - */ - maximumFractionDigits?: number - /** - * A BCP 47 language tag. The default value is `en-US`. This is passed as a first parameter to `Intl.NumberFormat` which is used within the utility method. - * You can learn more about this method’s parameters in - * [MDN’s documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#parameters). - */ - locale?: string -} - -/** - * This utility function can be used to compute the price of a variant for a region and retrieve the formatted amount. For example, `$20.00`. - * - * @param {FormatVariantPriceParams} param0 - Options to format the variant's price. - * @returns {string} The formatted price. - * - * @example - * ```tsx title="src/Products.ts" - * import React from "react" - * import { formatVariantPrice } from "medusa-react" - * import { Product, ProductVariant } from "@medusajs/medusa" - * - * const Products = () => { - * // ... - * return ( - *
    - * {products?.map((product: Product) => ( - *
  • - * {product.title} - *
      - * {product.variants.map((variant: ProductVariant) => ( - *
    • - * {formatVariantPrice({ - * variant, - * region, // should be retrieved earlier - * })} - *
    • - * ))} - *
    - *
  • - * ))} - *
- * ) - * } - * ``` - * - * @customNamespace Utilities - */ -export const formatVariantPrice = ({ - variant, - region, - includeTaxes = true, - ...rest -}: FormatVariantPriceParams) => { - const amount = computeVariantPrice({ variant, region, includeTaxes }) - - return convertToLocale({ - amount, - currency_code: region?.currency_code, - ...rest, - }) -} - -/** - * @interface - * - * Options to format a variant's price. - */ -export type ComputeVariantPriceParams = { - /** - * A variant's details. - */ - variant: ProductVariantInfo - /** - * A region's details. - */ - region: RegionInfo - /** - * Whether the computed price should include taxes or not. - * - * @defaultValue true - */ - includeTaxes?: boolean -} - -/** - * This utility function can be used to compute the price of a variant for a region and retrieve the amount without formatting. - * For example, `20`. This method is used by {@link formatVariantPrice} before applying the price formatting. - * - * @param {ComputeVariantPriceParams} param0 - Options to compute the variant's price. - * @returns The computed price of the variant. - * - * @example - * ```tsx title="src/Products.ts" - * import React from "react" - * import { computeVariantPrice } from "medusa-react" - * import { Product, ProductVariant } from "@medusajs/medusa" - * - * const Products = () => { - * // ... - * return ( - *
    - * {products?.map((product: Product) => ( - *
  • - * {product.title} - *
      - * {product.variants.map((variant: ProductVariant) => ( - *
    • - * {computeVariantPrice({ - * variant, - * region, // should be retrieved earlier - * })} - *
    • - * ))} - *
    - *
  • - * ))} - *
- * ) - * } - * ``` - * - * @customNamespace Utilities - */ -export const computeVariantPrice = ({ - variant, - region, - includeTaxes = true, -}: ComputeVariantPriceParams) => { - const amount = getVariantPrice(variant, region) - - return computeAmount({ - amount, - region, - includeTaxes, - }) -} - -/** - * This utility function is used to retrieve a variant's price in a region. It doesn't take into account taxes or any options, so you typically wouldn't need this function on its own. - * It's used by the {@link computeVariantPrice} function to retrieve the variant's price in a region before computing the correct price for the options provided. - * - * @param {ProductVariantInfo} variant - The variant's details. - * @param {RegionInfo} region - The region's details. - * @returns {number} The variant's price in a region. - * - * @example - * ```tsx title="src/Products.ts" - * import React from "react" - * import { getVariantPrice } from "medusa-react" - * import { Product, ProductVariant } from "@medusajs/medusa" - * - * const Products = () => { - * // ... - * return ( - *
    - * {products?.map((product: Product) => ( - *
  • - * {product.title} - *
      - * {product.variants.map((variant: ProductVariant) => ( - *
    • - * {getVariantPrice( - * variant, - * region, // should be retrieved earlier - * )} - *
    • - * ))} - *
    - *
  • - * ))} - *
- * ) - * } - * ``` - * - * @customNamespace Utilities - */ -export const getVariantPrice = ( - variant: ProductVariantInfo, - region: RegionInfo -) => { - let price = variant?.prices?.find( - (p) => - p.currency_code.toLowerCase() === region?.currency_code?.toLowerCase() - ) - - return price?.amount || 0 -} - -/** - * Options to compute an amount. - */ -export type ComputeAmountParams = { - /** - * The original amount used for computation. - */ - amount: number - /** - * The region's details. - */ - region: RegionInfo - /** - * Whether the computed price should include taxes or not. - * - * @defaultValue true - */ - includeTaxes?: boolean -} - -/** - * This utility function can be used to compute the price of an amount for a region and retrieve the amount without formatting. For example, `20`. - * This function is used by {@link formatAmount} before applying the price formatting. - * - * The main difference between this utility function and {@link computeVariantPrice} is that you don’t need to pass a complete variant object. This can be used with any number. - * - * @param {ComputeAmountParams} params0 - The options to compute the amount. - * @returns {number} The computed amount. - * - * @example - * ```tsx title="src/MyComponent.ts" - * import React from "react" - * import { computeAmount } from "medusa-react" - * - * const MyComponent = () => { - * // ... - * return ( - *
- * {computeAmount({ - * amount, - * region, // should be retrieved earlier - * })} - *
- * ) - * } - * ``` - * - * @customNamespace Utilities - */ -export const computeAmount = ({ - amount, - region, - includeTaxes = true, -}: ComputeAmountParams) => { - const toDecimal = convertToDecimal(amount, region) - - const taxRate = includeTaxes ? getTaxRate(region) : 0 - - const amountWithTaxes = toDecimal * (1 + taxRate) - - return amountWithTaxes -} - -/** - * Options to format an amount. - */ -export type FormatAmountParams = { - /** - * The original amount used for computation. - */ - amount: number - /** - * The region's details. - */ - region: RegionInfo - /** - * Whether the computed price should include taxes or not. - * - * @defaultValue true - */ - includeTaxes?: boolean - /** - * The minimum number of fraction digits to use when formatting the price. This is passed as an option to `Intl.NumberFormat` in the underlying layer. - * You can learn more about this method’s options in - * [MDN’s documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#parameters). - */ - minimumFractionDigits?: number - /** - * The maximum number of fraction digits to use when formatting the price. This is passed as an option to `Intl.NumberFormat` which is used within the utility method. - * You can learn more about this method’s options in - * [MDN’s documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#parameters). - */ - maximumFractionDigits?: number - /** - * A BCP 47 language tag. The default value is `en-US`. This is passed as a first parameter to `Intl.NumberFormat` which is used within the utility method. - * You can learn more about this method’s parameters in - * [MDN’s documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#parameters). - */ - locale?: string -} - -/** - * This utility function can be used to compute the price of an amount for a region and retrieve the formatted amount. For example, `$20.00`. - * - * The main difference between this utility function and {@link formatVariantPrice} is that you don’t need to pass a complete variant object. This can be used with any number. - * - * @param {FormatAmountParams} param0 - Options to format the amount. - * @returns {string} The formatted price. - * - * @example - * import React from "react" - * import { formatVariantPrice } from "medusa-react" - * import { Product, ProductVariant } from "@medusajs/medusa" - * - * const Products = () => { - * // ... - * return ( - *
    - * {products?.map((product: Product) => ( - *
  • - * {product.title} - *
      - * {product.variants.map((variant: ProductVariant) => ( - *
    • - * {formatVariantPrice({ - * variant, - * region, // should be retrieved earlier - * })} - *
    • - * ))} - *
    - *
  • - * ))} - *
- * ) - * } - * - * @customNamespace Utilities - */ -export const formatAmount = ({ - amount, - region, - includeTaxes = true, - ...rest -}: FormatAmountParams) => { - const taxAwareAmount = computeAmount({ - amount, - region, - includeTaxes, - }) - return convertToLocale({ - amount: taxAwareAmount, - currency_code: region.currency_code, - ...rest, - }) -} - -// we should probably add a more extensive list -const noDivisionCurrencies = ["krw", "jpy", "vnd"] - -const convertToDecimal = (amount: number, region: RegionInfo) => { - const divisor = noDivisionCurrencies.includes( - region?.currency_code?.toLowerCase() - ) - ? 1 - : 100 - - return Math.floor(amount) / divisor -} - -const getTaxRate = (region?: RegionInfo) => { - return region && !isEmpty(region) ? region?.tax_rate / 100 : 0 -} - -const convertToLocale = ({ - amount, - currency_code, - minimumFractionDigits, - maximumFractionDigits, - locale = "en-US", -}: ConvertToLocaleParams) => { - return currency_code && !isEmpty(currency_code) - ? new Intl.NumberFormat(locale, { - style: "currency", - currency: currency_code, - minimumFractionDigits, - maximumFractionDigits, - }).format(amount) - : amount.toString() -} - -type ConvertToLocaleParams = { - amount: number - currency_code: string - minimumFractionDigits?: number - maximumFractionDigits?: number - locale?: string -} - -/** - * @internal We need to export these types so that they're included in the generated reference documentation. - */ -export { ProductVariantInfo, RegionInfo } \ No newline at end of file diff --git a/packages/medusa-react/src/hooks/admin/auth/index.ts b/packages/medusa-react/src/hooks/admin/auth/index.ts deleted file mode 100644 index d00d0b97d3..0000000000 --- a/packages/medusa-react/src/hooks/admin/auth/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and mutations listed here are used to send requests to the [Admin Auth API Routes](https://docs.medusajs.com/api/admin#auth_getauth). - * - * They allow admin users to manage their session, such as login or log out. - * You can send authenticated requests for an admin user either using the Cookie header, their API token, or the JWT Token. - * When you log the admin user in using the {@link Hooks.Admin.Auth.useAdminLogin | user authentication} hook, Medusa React will automatically attach the - * cookie header in all subsequent requests. - * - * Related Guide: [How to implement user profiles](https://docs.medusajs.com/modules/users/admin/manage-profile). - * - * @customNamespace Hooks.Admin.Auth - */ - -export * from "./queries" -export * from "./mutations" \ No newline at end of file diff --git a/packages/medusa-react/src/hooks/admin/auth/mutations.ts b/packages/medusa-react/src/hooks/admin/auth/mutations.ts deleted file mode 100644 index 68d985a644..0000000000 --- a/packages/medusa-react/src/hooks/admin/auth/mutations.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { AdminAuthRes, AdminPostAuthReq } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminAuthKeys } from "./queries" - -/** - * This hook is used to log a User in using their credentials. If the user is authenticated successfully, - * the cookie is automatically attached to subsequent requests sent with other hooks. - * - * @example - * import React from "react" - * import { useAdminLogin } from "medusa-react" - * - * const Login = () => { - * const adminLogin = useAdminLogin() - * // ... - * - * const handleLogin = () => { - * adminLogin.mutate({ - * email: "user@example.com", - * password: "supersecret", - * }, { - * onSuccess: ({ user }) => { - * console.log(user) - * } - * }) - * } - * - * // ... - * } - * - * export default Login - * - * @customNamespace Hooks.Admin.Auth - * @category Mutations - */ -export const useAdminLogin = ( - options?: UseMutationOptions, Error, AdminPostAuthReq> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostAuthReq) => client.admin.auth.createSession(payload), - buildOptions(queryClient, adminAuthKeys.details(), options) - ) -} - -/** - * This hook is used to Log out the user and remove their authentication session. This will only work if you're using Cookie session for authentication. If the API token is still passed in the header, - * the user is still authorized to perform admin functionalities in other API Routes. - * - * This hook requires {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * @example - * import React from "react" - * import { useAdminDeleteSession } from "medusa-react" - * - * const Logout = () => { - * const adminLogout = useAdminDeleteSession() - * // ... - * - * const handleLogout = () => { - * adminLogout.mutate(undefined, { - * onSuccess: () => { - * // user logged out. - * } - * }) - * } - * - * // ... - * } - * - * export default Logout - * - * @customNamespace Hooks.Admin.Auth - * @category Mutations - */ -export const useAdminDeleteSession = ( - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.auth.deleteSession(), - buildOptions(queryClient, adminAuthKeys.details(), options) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/auth/queries.ts b/packages/medusa-react/src/hooks/admin/auth/queries.ts deleted file mode 100644 index 167cbc29b7..0000000000 --- a/packages/medusa-react/src/hooks/admin/auth/queries.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { AdminAuthRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_AUTH_QUERY_KEY = `admin_auth` as const - -export const adminAuthKeys = queryKeysFactory(ADMIN_AUTH_QUERY_KEY) - -type AuthQueryKey = typeof adminAuthKeys - -/** - * This hook is used to get the currently logged in user's details. Can also be used to check if there is an authenticated user. - * - * This hook requires {@link Hooks~Admin~Auth~useAdminLogin | user authentication}. - * - * @example - * import React from "react" - * import { useAdminGetSession } from "medusa-react" - * - * const Profile = () => { - * const { user, isLoading } = useAdminGetSession() - * - * return ( - *
- * {isLoading && Loading...} - * {user && {user.email}} - *
- * ) - * } - * - * export default Profile - * - * @customNamespace Hooks.Admin.Auth - * @category Queries - */ -export const useAdminGetSession = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminAuthKeys.details(), - () => client.admin.auth.getSession(), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/batch-jobs/index.ts b/packages/medusa-react/src/hooks/admin/batch-jobs/index.ts deleted file mode 100644 index ccfb0ecde1..0000000000 --- a/packages/medusa-react/src/hooks/admin/batch-jobs/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and mutations listed here are used to send requests to the [Admin Batch Job API Routes](https://docs.medusajs.com/api/admin#batch-jobs). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A batch job is a task that is performed by the Medusa backend asynchronusly. For example, the Import Product feature is implemented using batch jobs. - * The methods in this class allow admins to manage the batch jobs and their state. - * - * Related Guide: [How to import products](https://docs.medusajs.com/modules/products/admin/import-products). - * - * @customNamespace Hooks.Admin.Batch Jobs - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/batch-jobs/mutations.ts b/packages/medusa-react/src/hooks/admin/batch-jobs/mutations.ts deleted file mode 100644 index a5aff59c60..0000000000 --- a/packages/medusa-react/src/hooks/admin/batch-jobs/mutations.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { AdminBatchJobRes, AdminPostBatchesReq } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" - -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminBatchJobsKeys } from "./queries" - -/** - * This hook creates a Batch Job to be executed asynchronously in the Medusa backend. If `dry_run` is set to `true`, the batch job will not be executed until the it is confirmed, - * which can be done using the {@link useAdminConfirmBatchJob} hook. - * - * @example - * import React from "react" - * import { useAdminCreateBatchJob } from "medusa-react" - * - * const CreateBatchJob = () => { - * const createBatchJob = useAdminCreateBatchJob() - * // ... - * - * const handleCreateBatchJob = () => { - * createBatchJob.mutate({ - * type: "publish-products", - * context: {}, - * dry_run: true - * }, { - * onSuccess: ({ batch_job }) => { - * console.log(batch_job) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateBatchJob - * - * @customNamespace Hooks.Admin.Batch Jobs - * @category Mutations - */ -export const useAdminCreateBatchJob = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostBatchesReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostBatchesReq) => client.admin.batchJobs.create(payload), - buildOptions(queryClient, adminBatchJobsKeys.lists(), options) - ) -} - -/** - * This hook marks a batch job as canceled. When a batch job is canceled, the processing of the batch job doesn’t automatically stop. - * - * @example - * import React from "react" - * import { useAdminCancelBatchJob } from "medusa-react" - * - * type Props = { - * batchJobId: string - * } - * - * const BatchJob = ({ batchJobId }: Props) => { - * const cancelBatchJob = useAdminCancelBatchJob(batchJobId) - * // ... - * - * const handleCancel = () => { - * cancelBatchJob.mutate(undefined, { - * onSuccess: ({ batch_job }) => { - * console.log(batch_job) - * } - * }) - * } - * - * // ... - * } - * - * export default BatchJob - * - * @customNamespace Hooks.Admin.Batch Jobs - * @category Mutations - */ -export const useAdminCancelBatchJob = ( - /** - * The ID of the batch job. - */ - id: string, - options?: UseMutationOptions, Error> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.batchJobs.cancel(id), - buildOptions( - queryClient, - [adminBatchJobsKeys.lists(), adminBatchJobsKeys.detail(id)], - options - ) - ) -} - -/** - * When a batch job is created, it's not executed automatically if `dry_run` is set to `true`. This hook confirms that the batch job should be executed. - * - * @example - * import React from "react" - * import { useAdminConfirmBatchJob } from "medusa-react" - * - * type Props = { - * batchJobId: string - * } - * - * const BatchJob = ({ batchJobId }: Props) => { - * const confirmBatchJob = useAdminConfirmBatchJob(batchJobId) - * // ... - * - * const handleConfirm = () => { - * confirmBatchJob.mutate(undefined, { - * onSuccess: ({ batch_job }) => { - * console.log(batch_job) - * } - * }) - * } - * - * // ... - * } - * - * export default BatchJob - */ -export const useAdminConfirmBatchJob = ( - /** - * The ID of the batch job. - */ - id: string, - options?: UseMutationOptions, Error> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.batchJobs.confirm(id), - buildOptions( - queryClient, - [adminBatchJobsKeys.lists(), adminBatchJobsKeys.detail(id)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/batch-jobs/queries.ts b/packages/medusa-react/src/hooks/admin/batch-jobs/queries.ts deleted file mode 100644 index 5d2534c852..0000000000 --- a/packages/medusa-react/src/hooks/admin/batch-jobs/queries.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { - AdminBatchJobListRes, - AdminBatchJobRes, - AdminGetBatchParams, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_COLLECTIONS_QUERY_KEY = `admin_batches` as const - -export const adminBatchJobsKeys = queryKeysFactory(ADMIN_COLLECTIONS_QUERY_KEY) - -type BatchJobsQueryKey = typeof adminBatchJobsKeys - -/** - * This hook retrieves a list of Batch Jobs. The batch jobs can be filtered by fields such as `type` or `confirmed_at`. The batch jobs can also be sorted or paginated. - * - * @example - * To list batch jobs: - * - * ```ts - * import React from "react" - * import { useAdminBatchJobs } from "medusa-react" - * - * const BatchJobs = () => { - * const { - * batch_jobs, - * limit, - * offset, - * count, - * isLoading - * } = useAdminBatchJobs() - * - * return ( - *
- * {isLoading && Loading...} - * {batch_jobs?.length && ( - *
    - * {batch_jobs.map((batchJob) => ( - *
  • - * {batchJob.id} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default BatchJobs - * ``` - * - * To specify relations that should be retrieved within the batch jobs: - * - * ```ts - * import React from "react" - * import { useAdminBatchJobs } from "medusa-react" - * - * const BatchJobs = () => { - * const { - * batch_jobs, - * limit, - * offset, - * count, - * isLoading - * } = useAdminBatchJobs({ - * expand: "created_by_user", - * limit: 10, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {batch_jobs?.length && ( - *
    - * {batch_jobs.map((batchJob) => ( - *
  • - * {batchJob.id} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default BatchJobs - * ``` - * - * By default, only the first `10` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import React from "react" - * import { useAdminBatchJobs } from "medusa-react" - * - * const BatchJobs = () => { - * const { - * batch_jobs, - * limit, - * offset, - * count, - * isLoading - * } = useAdminBatchJobs({ - * expand: "created_by_user", - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {batch_jobs?.length && ( - *
    - * {batch_jobs.map((batchJob) => ( - *
  • - * {batchJob.id} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default BatchJobs - * ``` - * - * @customNamespace Hooks.Admin.Batch Jobs - * @category Queries - */ -export const useAdminBatchJobs = ( - /** - * Filters and pagination configurations to apply on the retrieved batch jobs. - */ - query?: AdminGetBatchParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminBatchJobsKeys.list(query), - () => client.admin.batchJobs.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves the details of a batch job. - * - * @example - * import React from "react" - * import { useAdminBatchJob } from "medusa-react" - * - * type Props = { - * batchJobId: string - * } - * - * const BatchJob = ({ batchJobId }: Props) => { - * const { batch_job, isLoading } = useAdminBatchJob(batchJobId) - * - * return ( - *
- * {isLoading && Loading...} - * {batch_job && {batch_job.created_by}} - *
- * ) - * } - * - * export default BatchJob - * - * @customNamespace Hooks.Admin.Batch Jobs - * @category Queries - */ -export const useAdminBatchJob = ( - /** - * The ID of the batch job. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminBatchJobsKeys.detail(id), - () => client.admin.batchJobs.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/claims/index.ts b/packages/medusa-react/src/hooks/admin/claims/index.ts deleted file mode 100644 index f735b931a9..0000000000 --- a/packages/medusa-react/src/hooks/admin/claims/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @packageDocumentation - * - * Mutations listed here are used to send requests to the [Admin Order API Routes related to claims](https://docs.medusajs.com/api/admin#orders). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A claim represents a return or replacement request of order items. It allows refunding the customer or replacing some or all of its - * order items with new items. - * - * Related Guide: [How to manage claims](https://docs.medusajs.com/modules/orders/admin/manage-claims). - * - * @customNamespace Hooks.Admin.Claims - */ - -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/claims/mutations.ts b/packages/medusa-react/src/hooks/admin/claims/mutations.ts deleted file mode 100644 index 1346201af4..0000000000 --- a/packages/medusa-react/src/hooks/admin/claims/mutations.ts +++ /dev/null @@ -1,417 +0,0 @@ -import { - AdminOrdersRes, - AdminPostOrdersOrderClaimsClaimFulfillmentsReq, - AdminPostOrdersOrderClaimsClaimReq, - AdminPostOrdersOrderClaimsClaimShipmentsReq, - AdminPostOrdersOrderClaimsReq, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminProductKeys } from "../products" -import { adminVariantKeys } from "../variants" -import { adminOrderKeys } from "./../orders/queries" - -/** - * This hook creates a claim for an order. If a return shipping method is specified, a return will also be created and associated with the claim. If the claim's type is `refund`, - * the refund is processed as well. - * - * @example - * import React from "react" - * import { useAdminCreateClaim } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const CreateClaim = ({ orderId }: Props) => { - * const createClaim = useAdminCreateClaim(orderId) - * // ... - * - * const handleCreate = (itemId: string) => { - * createClaim.mutate({ - * type: "refund", - * claim_items: [ - * { - * item_id: itemId, - * quantity: 1, - * }, - * ], - * }, { - * onSuccess: ({ order }) => { - * console.log(order.claims) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateClaim - * - * @customNamespace Hooks.Admin.Claims - * @category Mutations - */ -export const useAdminCreateClaim = ( - /** - * The ID of the order the claim is associated with. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostOrdersOrderClaimsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostOrdersOrderClaimsReq) => - client.admin.orders.createClaim(orderId, payload), - buildOptions(queryClient, adminOrderKeys.detail(orderId), options) - ) -} - -export type AdminUpdateClaimReq = AdminPostOrdersOrderClaimsClaimReq & { - /** - * The claim's ID. - */ - claim_id: string -} - -/** - * This hook updates a claim's details. - * - * @example - * import React from "react" - * import { useAdminUpdateClaim } from "medusa-react" - * - * type Props = { - * orderId: string - * claimId: string - * } - * - * const Claim = ({ orderId, claimId }: Props) => { - * const updateClaim = useAdminUpdateClaim(orderId) - * // ... - * - * const handleUpdate = () => { - * updateClaim.mutate({ - * claim_id: claimId, - * no_notification: false - * }, { - * onSuccess: ({ order }) => { - * console.log(order.claims) - * } - * }) - * } - * - * // ... - * } - * - * export default Claim - * - * @customNamespace Hooks.Admin.Claims - * @category Mutations - */ -export const useAdminUpdateClaim = ( - /** - * The ID of the order the claim is associated with. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - AdminUpdateClaimReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - ({ - claim_id, - ...payload - }: AdminUpdateClaimReq) => - client.admin.orders.updateClaim(orderId, claim_id, payload), - buildOptions(queryClient, adminOrderKeys.detail(orderId), options) - ) -} - -/** - * This hook cancels a claim and change its status. A claim can't be canceled if it has a refund, if its fulfillments haven't been canceled, - * of if its associated return hasn't been canceled. - * - * @typeParamDefinition string - The claim's ID. - * - * @example - * import React from "react" - * import { useAdminCancelClaim } from "medusa-react" - * - * type Props = { - * orderId: string - * claimId: string - * } - * - * const Claim = ({ orderId, claimId }: Props) => { - * const cancelClaim = useAdminCancelClaim(orderId) - * // ... - * - * const handleCancel = () => { - * cancelClaim.mutate(claimId) - * } - * - * // ... - * } - * - * export default Claim - * - * @customNamespace Hooks.Admin.Claims - * @category Mutations - */ -export const useAdminCancelClaim = ( - /** - * The ID of the order the claim is associated with. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - string - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (claimId: string) => client.admin.orders.cancelClaim(orderId, claimId), - buildOptions(queryClient, adminOrderKeys.detail(orderId), options) - ) -} - -/** - * The details of the claim's fulfillment. - */ -export type AdminFulfillClaimReq = AdminPostOrdersOrderClaimsClaimFulfillmentsReq & { - /** - * The claim's ID. - */ - claim_id: string -} - -/** - * This hook creates a Fulfillment for a Claim, and change its fulfillment status to `partially_fulfilled` or `fulfilled` depending on whether all the items were fulfilled. - * It may also change the status to `requires_action` if any actions are required. - * - * @example - * import React from "react" - * import { useAdminFulfillClaim } from "medusa-react" - * - * type Props = { - * orderId: string - * claimId: string - * } - * - * const Claim = ({ orderId, claimId }: Props) => { - * const fulfillClaim = useAdminFulfillClaim(orderId) - * // ... - * - * const handleFulfill = () => { - * fulfillClaim.mutate({ - * claim_id: claimId, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.claims) - * } - * }) - * } - * - * // ... - * } - * - * export default Claim - * - * @customNamespace Hooks.Admin.Claims - * @category Mutations - */ -export const useAdminFulfillClaim = ( - /** - * The ID of the order the claim is associated with. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - AdminFulfillClaimReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - ({ - claim_id, - ...payload - }: AdminFulfillClaimReq) => - client.admin.orders.fulfillClaim(orderId, claim_id, payload), - buildOptions( - queryClient, - [ - adminOrderKeys.detail(orderId), - adminVariantKeys.all, - adminProductKeys.lists(), - ], - options - ) - ) -} - -/** - * The cancelation details. - */ -export type AdminCancelClaimFulfillmentReq = { - /** - * The claim's ID. - */ - claim_id: string; - /** - * The fulfillment's ID. - */ - fulfillment_id: string -} - -/** - * This hook cancels a claim's fulfillment and change its fulfillment status to `canceled`. - * - * @example - * import React from "react" - * import { useAdminCancelClaimFulfillment } from "medusa-react" - * - * type Props = { - * orderId: string - * claimId: string - * } - * - * const Claim = ({ orderId, claimId }: Props) => { - * const cancelFulfillment = useAdminCancelClaimFulfillment( - * orderId - * ) - * // ... - * - * const handleCancel = (fulfillmentId: string) => { - * cancelFulfillment.mutate({ - * claim_id: claimId, - * fulfillment_id: fulfillmentId, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.claims) - * } - * }) - * } - * - * // ... - * } - * - * export default Claim - * - * @customNamespace Hooks.Admin.Claims - * @category Mutations - */ -export const useAdminCancelClaimFulfillment = ( - /** - * The ID of the order the claim is associated with. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - AdminCancelClaimFulfillmentReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - ({ - claim_id, - fulfillment_id, - }: AdminCancelClaimFulfillmentReq) => - client.admin.orders.cancelClaimFulfillment( - orderId, - claim_id, - fulfillment_id - ), - buildOptions(queryClient, adminOrderKeys.detail(orderId), options) - ) -} - -/** - * This hook creates a shipment for the claim and mark its fulfillment as shipped. If the shipment is created successfully, this changes the claim's fulfillment status - * to either `partially_shipped` or `shipped`, depending on whether all the items were shipped. - * - * @example - * import React from "react" - * import { useAdminCreateClaimShipment } from "medusa-react" - * - * type Props = { - * orderId: string - * claimId: string - * } - * - * const Claim = ({ orderId, claimId }: Props) => { - * const createShipment = useAdminCreateClaimShipment(orderId) - * // ... - * - * const handleCreateShipment = (fulfillmentId: string) => { - * createShipment.mutate({ - * claim_id: claimId, - * fulfillment_id: fulfillmentId, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.claims) - * } - * }) - * } - * - * // ... - * } - * - * export default Claim - * - * @customNamespace Hooks.Admin.Claims - * @category Mutations - */ -export const useAdminCreateClaimShipment = ( - /** - * The ID of the order the claim is associated with. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostOrdersOrderClaimsClaimShipmentsReq & { - /** - * The claim's ID. - */ - claim_id: string - } - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - ({ - claim_id, - ...payload - }: AdminPostOrdersOrderClaimsClaimShipmentsReq & { claim_id: string }) => - client.admin.orders.createClaimShipment(orderId, claim_id, payload), - buildOptions(queryClient, adminOrderKeys.detail(orderId), options) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/collections/index.ts b/packages/medusa-react/src/hooks/admin/collections/index.ts deleted file mode 100644 index e4266c2bc1..0000000000 --- a/packages/medusa-react/src/hooks/admin/collections/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Product Collection API Routes](https://docs.medusajs.com/api/admin#product-collections). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A product collection is used to organize products for different purposes such as marketing or discount purposes. For example, you can create a Summer Collection. - * - * @customNamespace Hooks.Admin.Product Collections - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/collections/mutations.ts b/packages/medusa-react/src/hooks/admin/collections/mutations.ts deleted file mode 100644 index 74168c317e..0000000000 --- a/packages/medusa-react/src/hooks/admin/collections/mutations.ts +++ /dev/null @@ -1,287 +0,0 @@ -import { - AdminCollectionsDeleteRes, - AdminCollectionsRes, - AdminDeleteProductsFromCollectionReq, - AdminDeleteProductsFromCollectionRes, - AdminPostCollectionsCollectionReq, - AdminPostCollectionsReq, - AdminPostProductsToCollectionReq, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - UseMutationOptions, - useMutation, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminCollectionKeys } from "./queries" - -/** - * This hook creates a product collection. - * - * @example - * import React from "react" - * import { useAdminCreateCollection } from "medusa-react" - * - * const CreateCollection = () => { - * const createCollection = useAdminCreateCollection() - * // ... - * - * const handleCreate = (title: string) => { - * createCollection.mutate({ - * title - * }, { - * onSuccess: ({ collection }) => { - * console.log(collection.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateCollection - * - * @customNamespace Hooks.Admin.Product Collections - * @category Mutations - */ -export const useAdminCreateCollection = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostCollectionsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostCollectionsReq) => - client.admin.collections.create(payload), - buildOptions(queryClient, adminCollectionKeys.lists(), options) - ) -} - -/** - * This hook updates a product collection's details. - * - * @example - * import React from "react" - * import { useAdminUpdateCollection } from "medusa-react" - * - * type Props = { - * collectionId: string - * } - * - * const Collection = ({ collectionId }: Props) => { - * const updateCollection = useAdminUpdateCollection(collectionId) - * // ... - * - * const handleUpdate = (title: string) => { - * updateCollection.mutate({ - * title - * }, { - * onSuccess: ({ collection }) => { - * console.log(collection.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Collection - * - * @customNamespace Hooks.Admin.Product Collections - * @category Mutations - */ -export const useAdminUpdateCollection = ( - /** - * The product collection's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostCollectionsCollectionReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostCollectionsCollectionReq) => - client.admin.collections.update(id, payload), - buildOptions( - queryClient, - [adminCollectionKeys.lists(), adminCollectionKeys.detail(id)], - options - ) - ) -} - -/** - * This hook deletes a product collection. This does not delete associated products. - * - * @example - * import React from "react" - * import { useAdminDeleteCollection } from "medusa-react" - * - * type Props = { - * collectionId: string - * } - * - * const Collection = ({ collectionId }: Props) => { - * const deleteCollection = useAdminDeleteCollection(collectionId) - * // ... - * - * const handleDelete = (title: string) => { - * deleteCollection.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Collection - * - * @customNamespace Hooks.Admin.Product Collections - * @category Mutations - */ -export const useAdminDeleteCollection = ( - /** - * The product collection's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - () => client.admin.collections.delete(id), - buildOptions( - queryClient, - [adminCollectionKeys.lists(), adminCollectionKeys.detail(id)], - options - ) - ) -} - -/** - * This hook adds products to a collection. - * - * @example - * import React from "react" - * import { useAdminAddProductsToCollection } from "medusa-react" - * - * type Props = { - * collectionId: string - * } - * - * const Collection = ({ collectionId }: Props) => { - * const addProducts = useAdminAddProductsToCollection(collectionId) - * // ... - * - * const handleAddProducts = (productIds: string[]) => { - * addProducts.mutate({ - * product_ids: productIds - * }, { - * onSuccess: ({ collection }) => { - * console.log(collection.products) - * } - * }) - * } - * - * // ... - * } - * - * export default Collection - * - * @customNamespace Hooks.Admin.Product Collections - * @category Mutations - */ -export const useAdminAddProductsToCollection = ( - /** - * The product collection's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostProductsToCollectionReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostProductsToCollectionReq) => - client.admin.collections.addProducts(id, payload), - buildOptions( - queryClient, - [adminCollectionKeys.lists(), adminCollectionKeys.detail(id)], - options - ) - ) -} - -/** - * This hook removes a list of products from a collection. This would not delete the product, - * only the association between the product and the collection. - * - * @example - * import React from "react" - * import { useAdminRemoveProductsFromCollection } from "medusa-react" - * - * type Props = { - * collectionId: string - * } - * - * const Collection = ({ collectionId }: Props) => { - * const removeProducts = useAdminRemoveProductsFromCollection(collectionId) - * // ... - * - * const handleRemoveProducts = (productIds: string[]) => { - * removeProducts.mutate({ - * product_ids: productIds - * }, { - * onSuccess: ({ id, object, removed_products }) => { - * console.log(removed_products) - * } - * }) - * } - * - * // ... - * } - * - * export default Collection - * - * @customNamespace Hooks.Admin.Product Collections - * @category Mutations - */ -export const useAdminRemoveProductsFromCollection = ( - /** - * The product collection's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminDeleteProductsFromCollectionReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminDeleteProductsFromCollectionReq) => - client.admin.collections.removeProducts(id, payload), - buildOptions( - queryClient, - [adminCollectionKeys.lists(), adminCollectionKeys.detail(id)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/collections/queries.ts b/packages/medusa-react/src/hooks/admin/collections/queries.ts deleted file mode 100644 index 24c92c1f59..0000000000 --- a/packages/medusa-react/src/hooks/admin/collections/queries.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { - AdminCollectionsListRes, - AdminCollectionsRes, - AdminGetCollectionsParams, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_COLLECTIONS_QUERY_KEY = `admin_collections` as const - -export const adminCollectionKeys = queryKeysFactory(ADMIN_COLLECTIONS_QUERY_KEY) - -type CollectionsQueryKey = typeof adminCollectionKeys - -/** - * This hook retrieves a list of product collections. The product collections can be filtered by fields such as `handle` or `title`. - * The collections can also be sorted or paginated. - * - * @example - * To list product collections: - * - * ```tsx - * import React from "react" - * import { useAdminCollections } from "medusa-react" - * - * const Collections = () => { - * const { collections, isLoading } = useAdminCollections() - * - * return ( - *
- * {isLoading && Loading...} - * {collections && !collections.length && - * No Product Collections - * } - * {collections && collections.length > 0 && ( - *
    - * {collections.map((collection) => ( - *
  • {collection.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Collections - * ``` - * - * By default, only the first `10` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminCollections } from "medusa-react" - * - * const Collections = () => { - * const { collections, limit, offset, isLoading } = useAdminCollections({ - * limit: 15, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {collections && !collections.length && - * No Product Collections - * } - * {collections && collections.length > 0 && ( - *
    - * {collections.map((collection) => ( - *
  • {collection.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Collections - * ``` - * - * @customNamespace Hooks.Admin.Product Collections - * @category Queries - */ -export const useAdminCollections = ( - /** - * Filters and pagination configurations to apply on the retrieved product collections. - */ - query?: AdminGetCollectionsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminCollectionKeys.list(query), - () => client.admin.collections.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a product collection by its ID. The products associated with it are expanded and returned as well. - * - * @example - * import React from "react" - * import { useAdminCollection } from "medusa-react" - * - * type Props = { - * collectionId: string - * } - * - * const Collection = ({ collectionId }: Props) => { - * const { collection, isLoading } = useAdminCollection(collectionId) - * - * return ( - *
- * {isLoading && Loading...} - * {collection && {collection.title}} - *
- * ) - * } - * - * export default Collection - * - * @customNamespace Hooks.Admin.Product Collections - * @category Queries - */ -export const useAdminCollection = ( - /** - * The product collection's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminCollectionKeys.detail(id), - () => client.admin.collections.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/currencies/index.ts b/packages/medusa-react/src/hooks/admin/currencies/index.ts deleted file mode 100644 index 5242a3f4b0..0000000000 --- a/packages/medusa-react/src/hooks/admin/currencies/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Currency API Routes](https://docs.medusajs.com/api/admin#currencies). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A store can use unlimited currencies, and each region must be associated with at least one currency. - * Currencies are defined within the Medusa backend. The methods in this class allow admins to list and update currencies. - * - * Related Guide: [How to manage currencies](https://docs.medusajs.com/modules/regions-and-currencies/admin/manage-currencies). - * - * @customNamespace Hooks.Admin.Currencies - */ - -export * from "./mutations" -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/admin/currencies/mutations.ts b/packages/medusa-react/src/hooks/admin/currencies/mutations.ts deleted file mode 100644 index f287ab152a..0000000000 --- a/packages/medusa-react/src/hooks/admin/currencies/mutations.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { - AdminCurrenciesRes, - AdminPostCurrenciesCurrencyReq, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminCurrenciesKeys } from "./queries" - -/** - * This hook updates a currency's details. - * - * @example - * import React from "react" - * import { useAdminUpdateCurrency } from "medusa-react" - * - * type Props = { - * currencyCode: string - * } - * - * const Currency = ({ currencyCode }: Props) => { - * const updateCurrency = useAdminUpdateCurrency(currencyCode) - * // ... - * - * const handleUpdate = (includes_tax: boolean) => { - * updateCurrency.mutate({ - * includes_tax, - * }, { - * onSuccess: ({ currency }) => { - * console.log(currency) - * } - * }) - * } - * - * // ... - * } - * - * export default Currency - * - * @customNamespace Hooks.Admin.Currencies - * @category Mutations - */ -export const useAdminUpdateCurrency = ( - /** - * The currency's code. - */ - code: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostCurrenciesCurrencyReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostCurrenciesCurrencyReq) => - client.admin.currencies.update(code, payload), - buildOptions( - queryClient, - [adminCurrenciesKeys.lists(), adminCurrenciesKeys.detail(code)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/currencies/queries.ts b/packages/medusa-react/src/hooks/admin/currencies/queries.ts deleted file mode 100644 index 8ac1ea672a..0000000000 --- a/packages/medusa-react/src/hooks/admin/currencies/queries.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { - AdminCurrenciesListRes, - AdminGetCurrenciesParams, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_CURRENCIES_QUERY_KEY = `admin_currencies` as const - -export const adminCurrenciesKeys = queryKeysFactory(ADMIN_CURRENCIES_QUERY_KEY) - -type CurrenciesQueryKey = typeof adminCurrenciesKeys - -/** - * This hook retrieves a list of currencies. The currencies can be filtered by fields such as `code`. - * The currencies can also be sorted or paginated. - * - * @example - * To list currencies: - * - * ```ts - * import React from "react" - * import { useAdminCurrencies } from "medusa-react" - * - * const Currencies = () => { - * const { currencies, isLoading } = useAdminCurrencies() - * - * return ( - *
- * {isLoading && Loading...} - * {currencies && !currencies.length && ( - * No Currencies - * )} - * {currencies && currencies.length > 0 && ( - *
    - * {currencies.map((currency) => ( - *
  • {currency.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Currencies - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```ts - * import React from "react" - * import { useAdminCurrencies } from "medusa-react" - * - * const Currencies = () => { - * const { currencies, limit, offset, isLoading } = useAdminCurrencies({ - * limit: 10, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {currencies && !currencies.length && ( - * No Currencies - * )} - * {currencies && currencies.length > 0 && ( - *
    - * {currencies.map((currency) => ( - *
  • {currency.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Currencies - * ``` - * - * @customNamespace Hooks.Admin.Currencies - * @category Queries - */ -export const useAdminCurrencies = ( - /** - * Filters and pagination configurations to apply on retrieved currencies. - */ - query?: AdminGetCurrenciesParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminCurrenciesKeys.list(query), - () => client.admin.currencies.list(query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/custom/index.ts b/packages/medusa-react/src/hooks/admin/custom/index.ts deleted file mode 100644 index 7ab3f97440..0000000000 --- a/packages/medusa-react/src/hooks/admin/custom/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @packageDocumentation - * - * This class is used to send requests custom API Routes. All its method - * are available in the JS Client under the `medusa.admin.custom` property. - * - * @customNamespace Hooks.Admin.Custom - */ - -export { useAdminCustomDelete, useAdminCustomPost } from "./mutations" -export { useAdminCustomQuery } from "./queries" diff --git a/packages/medusa-react/src/hooks/admin/custom/mutations.ts b/packages/medusa-react/src/hooks/admin/custom/mutations.ts deleted file mode 100644 index a93d3f489e..0000000000 --- a/packages/medusa-react/src/hooks/admin/custom/mutations.ts +++ /dev/null @@ -1,231 +0,0 @@ -import { Response } from "@medusajs/medusa-js" -import { - QueryClient, - QueryKey, - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { adminCustomerGroupKeys } from "../customer-groups" -import { adminCustomerKeys } from "../customers" -import { adminDiscountKeys } from "../discounts" -import { adminGiftCardKeys } from "../gift-cards" -import { adminOrderKeys } from "../orders" -import { adminPriceListKeys } from "../price-lists" -import { adminProductKeys } from "../products" - -type RelatedDomain = - | "product" - | "customer" - | "customer_group" - | "order" - | "discount" - | "gift_card" - | "price_list" - -export type RelatedDomains = { - [key in RelatedDomain]?: boolean -} - -const invalidateRelatedDomain = ( - queryClient: QueryClient, - domain: RelatedDomain -) => { - switch (domain) { - case "product": - queryClient.invalidateQueries(adminProductKeys.all) - break - case "customer": - queryClient.invalidateQueries(adminCustomerKeys.all) - break - case "customer_group": - queryClient.invalidateQueries(adminCustomerGroupKeys.all) - break - case "order": - queryClient.invalidateQueries(adminOrderKeys.all) - break - case "discount": - queryClient.invalidateQueries(adminDiscountKeys.all) - break - case "gift_card": - queryClient.invalidateQueries(adminGiftCardKeys.all) - break - case "price_list": - queryClient.invalidateQueries(adminPriceListKeys.all) - break - } -} - -export const buildCustomOptions = < - TData, - TError, - TVariables, - TContext, - TKey extends QueryKey ->( - queryClient: QueryClient, - queryKey?: TKey, - options?: UseMutationOptions, - relatedDomains?: RelatedDomains -): UseMutationOptions => { - return { - ...options, - onSuccess: (...args) => { - if (queryKey !== undefined) { - queryKey.forEach((key) => { - queryClient.invalidateQueries({ queryKey: key as QueryKey }) - }) - } - - if (relatedDomains) { - Object.keys(relatedDomains).forEach((key) => { - if (relatedDomains[key as RelatedDomain]) { - invalidateRelatedDomain(queryClient, key as RelatedDomain) - } - }) - } - - return options?.onSuccess?.(...args) - }, - } -} - -/** - * This hook sends a `POST` request to a custom API Route. - * - * @typeParam TPayload - The type of accepted body parameters which defaults to `Record`. - * @typeParam TResponse - The type of response, which defaults to `any`. - * @typeParamDefinition TResponse - The response based on the specified type for `TResponse`. - * @typeParamDefinition TPayload - The payload based on the specified type for `TPayload`. - * - * @example - * import React from "react" - * import { useAdminCustomPost } from "medusa-react" - * import Post from "./models/Post" - * - * type PostRequest = { - * title: string - * } - * type PostResponse = { - * post: Post - * } - * - * const Custom = () => { - * const customPost = useAdminCustomPost - * ( - * "/blog/posts", - * ["posts"] - * ) - * - * // ... - * - * const handleAction = (title: string) => { - * customPost.mutate({ - * title - * }, { - * onSuccess: ({ post }) => { - * console.log(post) - * } - * }) - * } - * - * // ... - * } - * - * export default Custom - * - * @customNamespace Hooks.Admin.Custom - * @category Mutations - */ -export const useAdminCustomPost = < - TPayload extends Record, - TResponse ->( - /** - * The path to the custom endpoint. - */ - path: string, - /** - * A list of query keys, used to invalidate data. - */ - queryKey: QueryKey, - /** - * A list of related domains that should be invalidated and refetch when the mutation - * function is invoked. - */ - relatedDomains?: RelatedDomains, - options?: UseMutationOptions, Error, TPayload> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: TPayload) => - client.admin.custom.post(path, payload), - buildCustomOptions(queryClient, queryKey, options, relatedDomains) - ) -} - -/** - * This hook sends a `DELETE` request to a custom API Route. - * - * @typeParam TResponse - The response's type which defaults to `any`. - * @typeParamDefinition TResponse - The response based on the type provided for `TResponse`. - * - * @example - * import React from "react" - * import { useAdminCustomDelete } from "medusa-react" - * - * type Props = { - * customId: string - * } - * - * const Custom = ({ customId }: Props) => { - * const customDelete = useAdminCustomDelete( - * `/blog/posts/${customId}`, - * ["posts"] - * ) - * - * // ... - * - * const handleAction = (title: string) => { - * customDelete.mutate(void 0, { - * onSuccess: () => { - * // Delete action successful - * } - * }) - * } - * - * // ... - * } - * - * export default Custom - * - * @customNamespace Hooks.Admin.Custom - * @category Mutations - */ -export const useAdminCustomDelete = ( - /** - * The path to the custom endpoint. - */ - path: string, - /** - * A list of query keys, used to invalidate data. - */ - queryKey: QueryKey, - /** - * A list of related domains that should be invalidated and refetch when the mutation - * function is invoked. - */ - relatedDomains?: RelatedDomains, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.custom.delete(path), - buildCustomOptions(queryClient, queryKey, options, relatedDomains) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/custom/queries.ts b/packages/medusa-react/src/hooks/admin/custom/queries.ts deleted file mode 100644 index 79dda86402..0000000000 --- a/packages/medusa-react/src/hooks/admin/custom/queries.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { Response } from "@medusajs/medusa-js" -import { QueryKey, useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" - -/** - * This hook sends a `GET` request to a custom API Route. - * - * @typeParam TQuery - The type of accepted query parameters which defaults to `Record`. - * @typeParam TResponse - The type of response which defaults to `any`. - * @typeParamDefinition TQuery - The query parameters based on the type specified for `TQuery`. - * @typeParamDefinition TResponse - The response based on the type specified for `TResponse`. - * - * @example - * import React from "react" - * import { useAdminCustomQuery } from "medusa-react" - * import Post from "./models/Post" - * - * type RequestQuery = { - * title: string - * } - * - * type ResponseData = { - * posts: Post - * } - * - * const Custom = () => { - * const { data, isLoading } = useAdminCustomQuery - * ( - * "/blog/posts", - * ["posts"], - * { - * title: "My post" - * } - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {data?.posts && !data.posts.length && ( - * No Post - * )} - * {data?.posts && data.posts?.length > 0 && ( - *
    - * {data.posts.map((post) => ( - *
  • {post.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Custom - * - * @customNamespace Hooks.Admin.Custom - * @category Mutations - */ -export const useAdminCustomQuery = < - TQuery extends Record, - TResponse = any ->( - /** - * The path to the custom endpoint. - */ - path: string, - /** - * A list of query keys, used to invalidate data. - */ - queryKey: QueryKey, - /** - * Query parameters to pass to the request. - */ - query?: TQuery, - options?: UseQueryOptionsWrapper< - Response, - Error, - (string | TQuery | QueryKey | undefined)[] - > -) => { - const { client } = useMedusa() - - const { data, ...rest } = useQuery( - [path, query, queryKey], - () => client.admin.custom.get(path, query), - options - ) - - return { data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/customer-groups/index.ts b/packages/medusa-react/src/hooks/admin/customer-groups/index.ts deleted file mode 100644 index 09022b31c8..0000000000 --- a/packages/medusa-react/src/hooks/admin/customer-groups/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Customer Group API Routes](https://docs.medusajs.com/api/admin#customer-groups). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Customer Groups can be used to organize customers that share similar data or attributes into dedicated groups. - * This can be useful for different purposes such as setting a different price for a specific customer group. - * - * Related Guide: [How to manage customer groups](https://docs.medusajs.com/modules/customers/admin/manage-customer-groups). - * - * @customNamespace Hooks.Admin.Customer Groups - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/customer-groups/mutations.ts b/packages/medusa-react/src/hooks/admin/customer-groups/mutations.ts deleted file mode 100644 index 25b2e0e56e..0000000000 --- a/packages/medusa-react/src/hooks/admin/customer-groups/mutations.ts +++ /dev/null @@ -1,301 +0,0 @@ -import { - AdminCustomerGroupsDeleteRes, - AdminCustomerGroupsRes, - AdminDeleteCustomerGroupsGroupCustomerBatchReq, - AdminPostCustomerGroupsGroupCustomersBatchReq, - AdminPostCustomerGroupsGroupReq, - AdminPostCustomerGroupsReq, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" - -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminCustomerGroupKeys } from "./queries" - -/** - * This hook creates a customer group. - * - * @example - * import React from "react" - * import { useAdminCreateCustomerGroup } from "medusa-react" - * - * const CreateCustomerGroup = () => { - * const createCustomerGroup = useAdminCreateCustomerGroup() - * // ... - * - * const handleCreate = (name: string) => { - * createCustomerGroup.mutate({ - * name, - * }) - * } - * - * // ... - * } - * - * export default CreateCustomerGroup - * - * @customNamespace Hooks.Admin.Customer Groups - * @category Mutations - */ -export const useAdminCreateCustomerGroup = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostCustomerGroupsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostCustomerGroupsReq) => - client.admin.customerGroups.create(payload), - buildOptions(queryClient, adminCustomerGroupKeys.lists(), options) - ) -} - -/** - * This hook updates a customer group's details. - * - * @example - * import React from "react" - * import { useAdminUpdateCustomerGroup } from "medusa-react" - * - * type Props = { - * customerGroupId: string - * } - * - * const CustomerGroup = ({ customerGroupId }: Props) => { - * const updateCustomerGroup = useAdminUpdateCustomerGroup( - * customerGroupId - * ) - * // .. - * - * const handleUpdate = (name: string) => { - * updateCustomerGroup.mutate({ - * name, - * }) - * } - * - * // ... - * } - * - * export default CustomerGroup - * - * @customNamespace Hooks.Admin.Customer Groups - * @category Mutations - */ -export const useAdminUpdateCustomerGroup = ( - /** - * The customer group's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostCustomerGroupsGroupReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostCustomerGroupsGroupReq) => - client.admin.customerGroups.update(id, payload), - buildOptions( - queryClient, - [adminCustomerGroupKeys.lists(), adminCustomerGroupKeys.detail(id)], - options - ) - ) -} - -/** - * This hook deletes a customer group. This doesn't delete the customers associated with the customer group. - * - * @example - * import React from "react" - * import { useAdminDeleteCustomerGroup } from "medusa-react" - * - * type Props = { - * customerGroupId: string - * } - * - * const CustomerGroup = ({ customerGroupId }: Props) => { - * const deleteCustomerGroup = useAdminDeleteCustomerGroup( - * customerGroupId - * ) - * // ... - * - * const handleDeleteCustomerGroup = () => { - * deleteCustomerGroup.mutate() - * } - * - * // ... - * } - * - * export default CustomerGroup - * - * @customNamespace Hooks.Admin.Customer Groups - * @category Mutations - */ -export const useAdminDeleteCustomerGroup = ( - /** - * The customer group's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - void - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.customerGroups.delete(id), - buildOptions( - queryClient, - [adminCustomerGroupKeys.lists(), adminCustomerGroupKeys.detail(id)], - options - ) - ) -} - -/** - * The hook adds a list of customers to a customer group. - * - * @example - * import React from "react" - * import { - * useAdminAddCustomersToCustomerGroup, - * } from "medusa-react" - * - * type Props = { - * customerGroupId: string - * } - * - * const CustomerGroup = ({ customerGroupId }: Props) => { - * const addCustomers = useAdminAddCustomersToCustomerGroup( - * customerGroupId - * ) - * // ... - * - * const handleAddCustomers= (customerId: string) => { - * addCustomers.mutate({ - * customer_ids: [ - * { - * id: customerId, - * }, - * ], - * }) - * } - * - * // ... - * } - * - * export default CustomerGroup - * - * @customNamespace Hooks.Admin.Customer Groups - * @category Mutations - */ -export const useAdminAddCustomersToCustomerGroup = ( - /** - * The customer group's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostCustomerGroupsGroupCustomersBatchReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostCustomerGroupsGroupCustomersBatchReq) => - client.admin.customerGroups.addCustomers(id, payload), - buildOptions( - queryClient, - [ - adminCustomerGroupKeys.lists(), - adminCustomerGroupKeys.detailCustomer(id), - ], - options - ) - ) -} - -/** - * This hook removes a list of customers from a customer group. This doesn't delete the customer, - * only the association between the customer and the customer group. - * - * @example - * import React from "react" - * import { - * useAdminRemoveCustomersFromCustomerGroup, - * } from "medusa-react" - * - * type Props = { - * customerGroupId: string - * } - * - * const CustomerGroup = ({ customerGroupId }: Props) => { - * const removeCustomers = - * useAdminRemoveCustomersFromCustomerGroup( - * customerGroupId - * ) - * // ... - * - * const handleRemoveCustomer = (customerId: string) => { - * removeCustomers.mutate({ - * customer_ids: [ - * { - * id: customerId, - * }, - * ], - * }) - * } - * - * // ... - * } - * - * export default CustomerGroup - * - * @customNamespace Hooks.Admin.Customer Groups - * @category Mutations - */ -export const useAdminRemoveCustomersFromCustomerGroup = ( - /** - * The customer group's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminDeleteCustomerGroupsGroupCustomerBatchReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminDeleteCustomerGroupsGroupCustomerBatchReq) => - client.admin.customerGroups.removeCustomers(id, payload), - buildOptions( - queryClient, - [ - adminCustomerGroupKeys.lists(), - adminCustomerGroupKeys.detailCustomer(id), - ], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/customer-groups/queries.ts b/packages/medusa-react/src/hooks/admin/customer-groups/queries.ts deleted file mode 100644 index f559b2cf25..0000000000 --- a/packages/medusa-react/src/hooks/admin/customer-groups/queries.ts +++ /dev/null @@ -1,292 +0,0 @@ -import { - AdminCustomerGroupsListRes, - AdminCustomerGroupsRes, - AdminCustomersListRes, - AdminGetCustomerGroupsGroupParams, - AdminGetCustomerGroupsParams, - AdminGetCustomersParams, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" - -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const ADMIN_CUSTOMER_GROUPS_QUERY_KEY = `admin_customer_groups` as const - -/** - * @ignore - */ -export const adminCustomerGroupKeys = { - ...queryKeysFactory(ADMIN_CUSTOMER_GROUPS_QUERY_KEY), - detailCustomer(id: string, query?: AdminGetCustomersParams) { - return [...this.detail(id), "customers", { ...(query || {}) }] - }, -} - -type CustomerGroupQueryKeys = typeof adminCustomerGroupKeys - -/** - * This hook retrieves a customer group by its ID. You can expand the customer group's relations or - * select the fields that should be returned. - * - * @example - * import React from "react" - * import { useAdminCustomerGroup } from "medusa-react" - * - * type Props = { - * customerGroupId: string - * } - * - * const CustomerGroup = ({ customerGroupId }: Props) => { - * const { customer_group, isLoading } = useAdminCustomerGroup( - * customerGroupId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {customer_group && {customer_group.name}} - *
- * ) - * } - * - * export default CustomerGroup - * - * @customNamespace Hooks.Admin.Customer Groups - * @category Queries - */ -export const useAdminCustomerGroup = ( - /** - * The customer group's ID. - */ - id: string, - /** - * Configurations to apply on the retrieved customer group. - */ - query?: AdminGetCustomerGroupsGroupParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminCustomerGroupKeys.detail(id), - () => client.admin.customerGroups.retrieve(id, query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a list of customer groups. The customer groups can be filtered by fields such as `name` or `id`. - * The customer groups can also be sorted or paginated. - * - * @example - * To list customer groups: - * - * ```tsx - * import React from "react" - * import { useAdminCustomerGroups } from "medusa-react" - * - * const CustomerGroups = () => { - * const { - * customer_groups, - * isLoading, - * } = useAdminCustomerGroups() - * - * return ( - *
- * {isLoading && Loading...} - * {customer_groups && !customer_groups.length && ( - * No Customer Groups - * )} - * {customer_groups && customer_groups.length > 0 && ( - *
    - * {customer_groups.map( - * (customerGroup) => ( - *
  • - * {customerGroup.name} - *
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default CustomerGroups - * ``` - * - * To specify relations that should be retrieved within the customer groups: - * - * ```tsx - * import React from "react" - * import { useAdminCustomerGroups } from "medusa-react" - * - * const CustomerGroups = () => { - * const { - * customer_groups, - * isLoading, - * } = useAdminCustomerGroups({ - * expand: "customers" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {customer_groups && !customer_groups.length && ( - * No Customer Groups - * )} - * {customer_groups && customer_groups.length > 0 && ( - *
    - * {customer_groups.map( - * (customerGroup) => ( - *
  • - * {customerGroup.name} - *
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default CustomerGroups - * ``` - * - * By default, only the first `10` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminCustomerGroups } from "medusa-react" - * - * const CustomerGroups = () => { - * const { - * customer_groups, - * limit, - * offset, - * isLoading, - * } = useAdminCustomerGroups({ - * expand: "customers", - * limit: 15, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {customer_groups && !customer_groups.length && ( - * No Customer Groups - * )} - * {customer_groups && customer_groups.length > 0 && ( - *
    - * {customer_groups.map( - * (customerGroup) => ( - *
  • - * {customerGroup.name} - *
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default CustomerGroups - * ``` - * - * @customNamespace Hooks.Admin.Customer Groups - * @category Queries - */ -export const useAdminCustomerGroups = ( - /** - * Filters and pagination configurations to apply on the retrieved customer groups. - */ - query?: AdminGetCustomerGroupsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminCustomerGroupKeys.list(query), - () => client.admin.customerGroups.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a list of customers in a customer group. The customers can be filtered - * by the `query` field. The customers can also be paginated. - * - * @example - * import React from "react" - * import { useAdminCustomerGroupCustomers } from "medusa-react" - * - * type Props = { - * customerGroupId: string - * } - * - * const CustomerGroup = ({ customerGroupId }: Props) => { - * const { - * customers, - * isLoading, - * } = useAdminCustomerGroupCustomers( - * customerGroupId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {customers && !customers.length && ( - * No customers - * )} - * {customers && customers.length > 0 && ( - *
    - * {customers.map((customer) => ( - *
  • {customer.first_name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default CustomerGroup - * - * @customNamespace Hooks.Admin.Customer Groups - * @category Queries - */ -export const useAdminCustomerGroupCustomers = ( - /** - * The customer group's ID. - */ - id: string, - /** - * Filters and pagination configurations to apply on the retrieved customers. - */ - query?: AdminGetCustomersParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminCustomerGroupKeys.detailCustomer(id, query), - () => client.admin.customerGroups.listCustomers(id, query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/customers/index.ts b/packages/medusa-react/src/hooks/admin/customers/index.ts deleted file mode 100644 index 91ed416ef1..0000000000 --- a/packages/medusa-react/src/hooks/admin/customers/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Customer API Routes](https://docs.medusajs.com/api/admin#customers). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Related Guide: [How to manage customers](https://docs.medusajs.com/modules/customers/admin/manage-customers). - * - * @customNamespace Hooks.Admin.Customers - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/customers/mutations.ts b/packages/medusa-react/src/hooks/admin/customers/mutations.ts deleted file mode 100644 index 495075cd85..0000000000 --- a/packages/medusa-react/src/hooks/admin/customers/mutations.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" - -import { - AdminCustomersRes, - AdminPostCustomersCustomerReq, - AdminPostCustomersReq, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" - -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminCustomerKeys } from "./queries" - -/** - * This hook creates a customer as an admin. - * - * @example - * import React from "react" - * import { useAdminCreateCustomer } from "medusa-react" - * - * type CustomerData = { - * first_name: string - * last_name: string - * email: string - * password: string - * } - * - * const CreateCustomer = () => { - * const createCustomer = useAdminCreateCustomer() - * // ... - * - * const handleCreate = (customerData: CustomerData) => { - * createCustomer.mutate(customerData, { - * onSuccess: ({ customer }) => { - * console.log(customer.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateCustomer - * - * @customNamespace Hooks.Admin.Customers - * @category Mutations - */ -export const useAdminCreateCustomer = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostCustomersReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostCustomersReq) => client.admin.customers.create(payload), - buildOptions(queryClient, adminCustomerKeys.lists(), options) - ) -} - -/** - * This hook updates a customer's details. - * - * @example - * import React from "react" - * import { useAdminUpdateCustomer } from "medusa-react" - * - * type CustomerData = { - * first_name: string - * last_name: string - * email: string - * password: string - * } - * - * type Props = { - * customerId: string - * } - * - * const Customer = ({ customerId }: Props) => { - * const updateCustomer = useAdminUpdateCustomer(customerId) - * // ... - * - * const handleUpdate = (customerData: CustomerData) => { - * updateCustomer.mutate(customerData) - * } - * - * // ... - * } - * - * export default Customer - * - * @customNamespace Hooks.Admin.Customers - * @category Mutations - */ -export const useAdminUpdateCustomer = ( - /** - * The customer's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostCustomersCustomerReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostCustomersCustomerReq) => - client.admin.customers.update(id, payload), - buildOptions( - queryClient, - [adminCustomerKeys.lists(), adminCustomerKeys.detail(id)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/customers/queries.ts b/packages/medusa-react/src/hooks/admin/customers/queries.ts deleted file mode 100644 index c59a03cb92..0000000000 --- a/packages/medusa-react/src/hooks/admin/customers/queries.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { - AdminCustomersListRes, - AdminCustomersRes, - AdminGetCustomersParams, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const ADMIN_CUSTOMERS_QUERY_KEY = `admin_customers` as const - -export const adminCustomerKeys = queryKeysFactory(ADMIN_CUSTOMERS_QUERY_KEY) - -type CustomerQueryKeys = typeof adminCustomerKeys - -/** - * This hook retrieves a list of Customers. The customers can be filtered by fields such as - * `q` or `groups`. The customers can also be paginated. - * - * @example - * To list customers: - * - * ```tsx - * import React from "react" - * import { useAdminCustomers } from "medusa-react" - * - * const Customers = () => { - * const { customers, isLoading } = useAdminCustomers() - * - * return ( - *
- * {isLoading && Loading...} - * {customers && !customers.length && ( - * No customers - * )} - * {customers && customers.length > 0 && ( - *
    - * {customers.map((customer) => ( - *
  • {customer.first_name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Customers - * ``` - * - * You can specify relations to be retrieved within each customer. In addition, by default, only the first `50` records are retrieved. - * You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminCustomers } from "medusa-react" - * - * const Customers = () => { - * const { - * customers, - * limit, - * offset, - * isLoading - * } = useAdminCustomers({ - * expand: "billing_address", - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {customers && !customers.length && ( - * No customers - * )} - * {customers && customers.length > 0 && ( - *
    - * {customers.map((customer) => ( - *
  • {customer.first_name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Customers - * ``` - * - * @customNamespace Hooks.Admin.Customers - * @category Queries - */ -export const useAdminCustomers = ( - /** - * Filters and pagination configurations to apply on the retrieved customers. - */ - query?: AdminGetCustomersParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminCustomerKeys.list(query), - () => client.admin.customers.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves the details of a customer. - * - * @example - * import React from "react" - * import { useAdminCustomer } from "medusa-react" - * - * type Props = { - * customerId: string - * } - * - * const Customer = ({ customerId }: Props) => { - * const { customer, isLoading } = useAdminCustomer( - * customerId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {customer && {customer.first_name}} - *
- * ) - * } - * - * export default Customer - * - * @customNamespace Hooks.Admin.Customers - * @category Queries - */ -export const useAdminCustomer = ( - /** - * The customer's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminCustomerKeys.detail(id), - () => client.admin.customers.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/discounts/index.ts b/packages/medusa-react/src/hooks/admin/discounts/index.ts deleted file mode 100644 index 4f50d4431a..0000000000 --- a/packages/medusa-react/src/hooks/admin/discounts/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Discount API Routes](https://docs.medusajs.com/api/admin#discounts). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Admins can create discounts with conditions and rules, providing them with advanced settings for variety of cases. - * The methods in this class can be used to manage discounts, their conditions, resources, and more. - * - * Related Guide: [How to manage discounts](https://docs.medusajs.com/modules/discounts/admin/manage-discounts). - * - * @customNamespace Hooks.Admin.Discounts - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/discounts/mutations.ts b/packages/medusa-react/src/hooks/admin/discounts/mutations.ts deleted file mode 100644 index 47e2ab664b..0000000000 --- a/packages/medusa-react/src/hooks/admin/discounts/mutations.ts +++ /dev/null @@ -1,766 +0,0 @@ -import { - AdminDeleteDiscountsDiscountConditionsConditionBatchReq, - AdminDiscountsDeleteRes, - AdminDiscountsRes, - AdminPostDiscountsDiscountConditions, - AdminPostDiscountsDiscountConditionsCondition, - AdminPostDiscountsDiscountConditionsConditionBatchParams, - AdminPostDiscountsDiscountConditionsConditionBatchReq, - AdminPostDiscountsDiscountDynamicCodesReq, - AdminPostDiscountsDiscountReq, - AdminPostDiscountsReq, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminDiscountKeys } from "./queries" - -/** - * This hook adds a batch of resources to a discount condition. The type of resource depends on the type of discount condition. - * For example, if the discount condition's type is `products`, the resources being added should be products. - * - * @example - * To add resources to a discount condition: - * - * ```tsx - * import React from "react" - * import { - * useAdminAddDiscountConditionResourceBatch - * } from "medusa-react" - * - * type Props = { - * discountId: string - * conditionId: string - * } - * - * const DiscountCondition = ({ - * discountId, - * conditionId - * }: Props) => { - * const addConditionResources = useAdminAddDiscountConditionResourceBatch( - * discountId, - * conditionId - * ) - * // ... - * - * const handleAdd = (itemId: string) => { - * addConditionResources.mutate({ - * resources: [ - * { - * id: itemId - * } - * ] - * }, { - * onSuccess: ({ discount }) => { - * console.log(discount.id) - * } - * }) - * } - * - * // ... - * } - * - * export default DiscountCondition - * ``` - * - * To specify relations to include in the returned discount: - * - * ```tsx - * import React from "react" - * import { - * useAdminAddDiscountConditionResourceBatch - * } from "medusa-react" - * - * type Props = { - * discountId: string - * conditionId: string - * } - * - * const DiscountCondition = ({ - * discountId, - * conditionId - * }: Props) => { - * const addConditionResources = useAdminAddDiscountConditionResourceBatch( - * discountId, - * conditionId, - * { - * expand: "rule" - * } - * ) - * // ... - * - * const handleAdd = (itemId: string) => { - * addConditionResources.mutate({ - * resources: [ - * { - * id: itemId - * } - * ] - * }, { - * onSuccess: ({ discount }) => { - * console.log(discount.id) - * } - * }) - * } - * - * // ... - * } - * - * export default DiscountCondition - * ``` - * - * @customNamespace Hooks.Admin.Discounts - * @category Mutations - */ -export const useAdminAddDiscountConditionResourceBatch = ( - /** - * The ID of the discount the condition belongs to. - */ - discountId: string, - /** - * The discount condition's ID. - */ - conditionId: string, - /** - * Configurations to apply on the retrieved discount. - */ - query?: AdminPostDiscountsDiscountConditionsConditionBatchParams, - options?: UseMutationOptions< - Response, - Error, - AdminPostDiscountsDiscountConditionsConditionBatchReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostDiscountsDiscountConditionsConditionBatchReq) => - client.admin.discounts.addConditionResourceBatch( - discountId, - conditionId, - payload, - query - ), - buildOptions(queryClient, adminDiscountKeys.detail(discountId), options) - ) -} - -/** - * This hook remove a batch of resources from a discount condition. This will only remove the association between the resource and - * the discount condition, not the resource itself. - * - * @example - * import React from "react" - * import { - * useAdminDeleteDiscountConditionResourceBatch - * } from "medusa-react" - * - * type Props = { - * discountId: string - * conditionId: string - * } - * - * const DiscountCondition = ({ - * discountId, - * conditionId - * }: Props) => { - * const deleteConditionResource = useAdminDeleteDiscountConditionResourceBatch( - * discountId, - * conditionId, - * ) - * // ... - * - * const handleDelete = (itemId: string) => { - * deleteConditionResource.mutate({ - * resources: [ - * { - * id: itemId - * } - * ] - * }, { - * onSuccess: ({ discount }) => { - * console.log(discount.id) - * } - * }) - * } - * - * // ... - * } - * - * export default DiscountCondition - * - * @customNamespace Hooks.Admin.Discounts - * @category Mutations - */ -export const useAdminDeleteDiscountConditionResourceBatch = ( - /** - * The ID of the discount the condition belongs to. - */ - discountId: string, - /** - * The discount condition's ID. - */ - conditionId: string, - options?: UseMutationOptions< - Response, - Error, - AdminDeleteDiscountsDiscountConditionsConditionBatchReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminDeleteDiscountsDiscountConditionsConditionBatchReq) => - client.admin.discounts.deleteConditionResourceBatch( - discountId, - conditionId, - payload - ), - buildOptions(queryClient, [adminDiscountKeys.detail(discountId)], options) - ) -} - -/** - * This hook creates a discount with a given set of rules that defines how the discount is applied. - * - * @example - * import React from "react" - * import { - * useAdminCreateDiscount, - * } from "medusa-react" - * import { - * AllocationType, - * DiscountRuleType, - * } from "@medusajs/medusa" - * - * const CreateDiscount = () => { - * const createDiscount = useAdminCreateDiscount() - * // ... - * - * const handleCreate = ( - * currencyCode: string, - * regionId: string - * ) => { - * // ... - * createDiscount.mutate({ - * code: currencyCode, - * rule: { - * type: DiscountRuleType.FIXED, - * value: 10, - * allocation: AllocationType.ITEM, - * }, - * regions: [ - * regionId, - * ], - * is_dynamic: false, - * is_disabled: false, - * }) - * } - * - * // ... - * } - * - * export default CreateDiscount - * - * @customNamespace Hooks.Admin.Discounts - * @category Mutations - */ -export const useAdminCreateDiscount = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostDiscountsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostDiscountsReq) => client.admin.discounts.create(payload), - buildOptions(queryClient, adminDiscountKeys.lists(), options) - ) -} - -/** - * This hook updates a discount with a given set of rules that define how the discount is applied. - * - * @example - * import React from "react" - * import { useAdminUpdateDiscount } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const updateDiscount = useAdminUpdateDiscount(discountId) - * // ... - * - * const handleUpdate = (isDisabled: boolean) => { - * updateDiscount.mutate({ - * is_disabled: isDisabled, - * }) - * } - * - * // ... - * } - * - * export default Discount - * - * @customNamespace Hooks.Admin.Discounts - * @category Mutations - */ -export const useAdminUpdateDiscount = ( - /** - * The discount's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostDiscountsDiscountReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostDiscountsDiscountReq) => - client.admin.discounts.update(id, payload), - buildOptions(queryClient, adminDiscountKeys.detail(id), options) - ) -} - -/** - * This hook deletes a discount. Deleting the discount will make it unavailable for customers to use. - * - * @example - * import React from "react" - * import { useAdminDeleteDiscount } from "medusa-react" - * - * const Discount = () => { - * const deleteDiscount = useAdminDeleteDiscount(discount_id) - * // ... - * - * const handleDelete = () => { - * deleteDiscount.mutate() - * } - * - * // ... - * } - * - * export default Discount - * - * @customNamespace Hooks.Admin.Discounts - * @category Mutations - */ -export const useAdminDeleteDiscount = ( - /** - * The discount's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - () => client.admin.discounts.delete(id), - buildOptions(queryClient, adminDiscountKeys.lists(), options) - ) -} - -/** - * This hook adds a Region to the list of Regions a Discount can be used in. - * - * @typeParamDefinition string - The ID of the region to add. - * - * @example - * import React from "react" - * import { useAdminDiscountAddRegion } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const addRegion = useAdminDiscountAddRegion(discountId) - * // ... - * - * const handleAdd = (regionId: string) => { - * addRegion.mutate(regionId, { - * onSuccess: ({ discount }) => { - * console.log(discount.regions) - * } - * }) - * } - * - * // ... - * } - * - * export default Discount - * - * @customNamespace Hooks.Admin.Discounts - * @category Mutations - */ -export const useAdminDiscountAddRegion = ( - /** - * The discount's ID. - */ - id: string, - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (regionId: string) => client.admin.discounts.addRegion(id, regionId), - buildOptions(queryClient, adminDiscountKeys.detail(id), options) - ) -} - -/** - * This hook removes a Region from the list of Regions that a Discount can be used in. - * This does not delete a region, only the association between it and the discount. - * - * @typeParamDefinition string - The ID of the region to remove. - * - * @example - * import React from "react" - * import { useAdminDiscountRemoveRegion } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const deleteRegion = useAdminDiscountRemoveRegion(discountId) - * // ... - * - * const handleDelete = (regionId: string) => { - * deleteRegion.mutate(regionId, { - * onSuccess: ({ discount }) => { - * console.log(discount.regions) - * } - * }) - * } - * - * // ... - * } - * - * export default Discount - * - * @customNamespace Hooks.Admin.Discounts - * @category Mutations - */ -export const useAdminDiscountRemoveRegion = ( - /** - * The discount's ID. - */ - id: string, - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (regionId: string) => client.admin.discounts.removeRegion(id, regionId), - buildOptions(queryClient, adminDiscountKeys.detail(id), options) - ) -} - -/** - * This hook creates a dynamic unique code that can map to a parent discount. This is useful if you want to - * automatically generate codes with the same rules and conditions. - * - * @example - * import React from "react" - * import { useAdminCreateDynamicDiscountCode } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const createDynamicDiscount = useAdminCreateDynamicDiscountCode(discountId) - * // ... - * - * const handleCreate = ( - * code: string, - * usageLimit: number - * ) => { - * createDynamicDiscount.mutate({ - * code, - * usage_limit: usageLimit - * }, { - * onSuccess: ({ discount }) => { - * console.log(discount.is_dynamic) - * } - * }) - * } - * - * // ... - * } - * - * export default Discount - * - * @customNamespace Hooks.Admin.Discounts - * @category Mutations - */ -export const useAdminCreateDynamicDiscountCode = ( - /** - * The discount's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostDiscountsDiscountDynamicCodesReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostDiscountsDiscountDynamicCodesReq) => - client.admin.discounts.createDynamicCode(id, payload), - buildOptions( - queryClient, - [adminDiscountKeys.lists(), adminDiscountKeys.detail(id)], - options - ) - ) -} - -/** - * This hook deletes a dynamic code from a discount. - * - * @typeParamDefinition string - The code of the dynamic discount to delete. - * - * @example - * import React from "react" - * import { useAdminDeleteDynamicDiscountCode } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const deleteDynamicDiscount = useAdminDeleteDynamicDiscountCode(discountId) - * // ... - * - * const handleDelete = (code: string) => { - * deleteDynamicDiscount.mutate(code, { - * onSuccess: ({ discount }) => { - * console.log(discount.is_dynamic) - * } - * }) - * } - * - * // ... - * } - * - * export default Discount - * - * @customNamespace Hooks.Admin.Discounts - * @category Mutations - */ -export const useAdminDeleteDynamicDiscountCode = ( - /** - * The discount's ID. - */ - id: string, - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (code: string) => client.admin.discounts.deleteDynamicCode(id, code), - buildOptions( - queryClient, - [adminDiscountKeys.lists(), adminDiscountKeys.detail(id)], - options - ) - ) -} - -/** - * This hook creates a discount condition. Only one of `products`, `product_types`, `product_collections`, `product_tags`, and `customer_groups` - * should be provided in the `payload` parameter, based on the type of discount condition. For example, if the discount condition's type is `products`, - * the `products` field should be provided in the `payload` parameter. - * - * @example - * import React from "react" - * import { DiscountConditionOperator } from "@medusajs/medusa" - * import { useAdminDiscountCreateCondition } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const createCondition = useAdminDiscountCreateCondition(discountId) - * // ... - * - * const handleCreateCondition = ( - * operator: DiscountConditionOperator, - * products: string[] - * ) => { - * createCondition.mutate({ - * operator, - * products - * }, { - * onSuccess: ({ discount }) => { - * console.log(discount.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Discount - * - * @customNamespace Hooks.Admin.Discounts - * @category Mutations - */ -export const useAdminDiscountCreateCondition = ( - /** - * The discount's ID. - */ - discountId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostDiscountsDiscountConditions - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostDiscountsDiscountConditions) => - client.admin.discounts.createCondition(discountId, payload), - buildOptions(queryClient, adminDiscountKeys.detail(discountId), options) - ) -} - -/** - * Update a discount condition. Only one of `products`, `product_types`, `product_collections`, `product_tags`, and `customer_groups` - * should be provided in the `payload` parameter, based on the type of discount condition. For example, if the discount condition's - * type is `products`, the `products` field should be provided in the `payload` parameter. - * - * @example - * import React from "react" - * import { useAdminDiscountUpdateCondition } from "medusa-react" - * - * type Props = { - * discountId: string - * conditionId: string - * } - * - * const DiscountCondition = ({ - * discountId, - * conditionId - * }: Props) => { - * const update = useAdminDiscountUpdateCondition( - * discountId, - * conditionId - * ) - * // ... - * - * const handleUpdate = ( - * products: string[] - * ) => { - * update.mutate({ - * products - * }, { - * onSuccess: ({ discount }) => { - * console.log(discount.id) - * } - * }) - * } - * - * // ... - * } - * - * export default DiscountCondition - * - * @customNamespace Hooks.Admin.Discounts - * @category Mutations - */ -export const useAdminDiscountUpdateCondition = ( - /** - * The discount's ID. - */ - discountId: string, - /** - * The discount condition's ID. - */ - conditionId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostDiscountsDiscountConditionsCondition - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostDiscountsDiscountConditionsCondition) => - client.admin.discounts.updateCondition(discountId, conditionId, payload), - buildOptions(queryClient, adminDiscountKeys.detail(discountId), options) - ) -} - -/** - * This hook deletes a discount condition. This doesn't delete resources associated to the discount condition. - * - * @typeParamDefinition string - The ID of the condition to delete. - * - * @example - * import React from "react" - * import { useAdminDiscountRemoveCondition } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const deleteCondition = useAdminDiscountRemoveCondition( - * discountId - * ) - * // ... - * - * const handleDelete = ( - * conditionId: string - * ) => { - * deleteCondition.mutate(conditionId, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(deleted) - * } - * }) - * } - * - * // ... - * } - * - * export default Discount - * - * @customNamespace Hooks.Admin.Discounts - * @category Mutations - */ -export const useAdminDiscountRemoveCondition = ( - /** - * The discount's ID. - */ - discountId: string, - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (conditionId: string) => - client.admin.discounts.deleteCondition(discountId, conditionId), - buildOptions(queryClient, adminDiscountKeys.detail(discountId), options) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/discounts/queries.ts b/packages/medusa-react/src/hooks/admin/discounts/queries.ts deleted file mode 100644 index 4e52269b35..0000000000 --- a/packages/medusa-react/src/hooks/admin/discounts/queries.ts +++ /dev/null @@ -1,324 +0,0 @@ -import { - AdminDiscountConditionsRes, - AdminDiscountsListRes, - AdminDiscountsRes, - AdminGetDiscountParams, - AdminGetDiscountsDiscountConditionsConditionParams, - AdminGetDiscountsParams, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const ADMIN_DISCOUNTS_QUERY_KEY = `admin_discounts` as const - -export const adminDiscountKeys = { - ...queryKeysFactory(ADMIN_DISCOUNTS_QUERY_KEY), - detailCondition(id: string, query?: any) { - return [ - ...this.detail(id), - "condition" as const, - { ...(query || {}) }, - ] as const - }, -} - -type DiscountQueryKeys = typeof adminDiscountKeys - -/** - * This hook retrieves a list of Discounts. The discounts can be filtered by fields such as `rule` or `is_dynamic`. - * The discounts can also be paginated. - * - * @example - * To list discounts: - * - * ```tsx - * import React from "react" - * import { useAdminDiscounts } from "medusa-react" - * - * const Discounts = () => { - * const { discounts, isLoading } = useAdminDiscounts() - * - * return ( - *
- * {isLoading && Loading...} - * {discounts && !discounts.length && ( - * No customers - * )} - * {discounts && discounts.length > 0 && ( - *
    - * {discounts.map((discount) => ( - *
  • {discount.code}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Discounts - * ``` - * - * To specify relations that should be retrieved within the discounts: - * - * ```tsx - * import React from "react" - * import { useAdminDiscounts } from "medusa-react" - * - * const Discounts = () => { - * const { discounts, isLoading } = useAdminDiscounts({ - * expand: "rule" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {discounts && !discounts.length && ( - * No customers - * )} - * {discounts && discounts.length > 0 && ( - *
    - * {discounts.map((discount) => ( - *
  • {discount.code}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Discounts - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminDiscounts } from "medusa-react" - * - * const Discounts = () => { - * const { - * discounts, - * limit, - * offset, - * isLoading - * } = useAdminDiscounts({ - * expand: "rule", - * limit: 10, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {discounts && !discounts.length && ( - * No customers - * )} - * {discounts && discounts.length > 0 && ( - *
    - * {discounts.map((discount) => ( - *
  • {discount.code}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Discounts - * ``` - * - * @customNamespace Hooks.Admin.Discounts - * @category Queries - */ -export const useAdminDiscounts = ( - /** - * Filters and pagination configurations to apply on the retrieved discounts. - */ - query?: AdminGetDiscountsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminDiscountKeys.list(query), - () => client.admin.discounts.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a discount. - * - * @example - * import React from "react" - * import { useAdminDiscount } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const { discount, isLoading } = useAdminDiscount( - * discountId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {discount && {discount.code}} - *
- * ) - * } - * - * export default Discount - * - * @customNamespace Hooks.Admin.Discounts - * @category Queries - */ -export const useAdminDiscount = ( - /** - * The discount's ID. - */ - id: string, - /** - * Configurations to apply on the retrieved discount. - */ - query?: AdminGetDiscountParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminDiscountKeys.detail(id), - () => client.admin.discounts.retrieve(id, query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook adds a batch of resources to a discount condition. The type of resource depends on the type of discount condition. For example, if the discount condition's type is `products`, - * the resources being added should be products. - * - * @example - * import React from "react" - * import { useAdminGetDiscountByCode } from "medusa-react" - * - * type Props = { - * discountCode: string - * } - * - * const Discount = ({ discountCode }: Props) => { - * const { discount, isLoading } = useAdminGetDiscountByCode( - * discountCode - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {discount && {discount.code}} - *
- * ) - * } - * - * export default Discount - * - * @customNamespace Hooks.Admin.Discounts - * @category Queries - */ -export const useAdminGetDiscountByCode = ( - /** - * The code of the discount. - */ - code: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminDiscountKeys.detail(code), - () => client.admin.discounts.retrieveByCode(code), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retries a Discount Condition's details. - * - * @example - * import React from "react" - * import { useAdminGetDiscountCondition } from "medusa-react" - * - * type Props = { - * discountId: string - * discountConditionId: string - * } - * - * const DiscountCondition = ({ - * discountId, - * discountConditionId - * }: Props) => { - * const { - * discount_condition, - * isLoading - * } = useAdminGetDiscountCondition( - * discountId, - * discountConditionId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {discount_condition && ( - * {discount_condition.type} - * )} - *
- * ) - * } - * - * export default DiscountCondition - * - * @customNamespace Hooks.Admin.Discounts - * @category Queries - */ -export const useAdminGetDiscountCondition = ( - /** - * The ID of the discount the condition belongs to. - */ - id: string, - /** - * The discount condition's ID. - */ - conditionId: string, - /** - * Configurations to apply on the retrieved discount condition. - */ - query?: AdminGetDiscountsDiscountConditionsConditionParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminDiscountKeys.detailCondition(conditionId), - () => client.admin.discounts.getCondition(id, conditionId, query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/draft-orders/index.ts b/packages/medusa-react/src/hooks/admin/draft-orders/index.ts deleted file mode 100644 index ffd53780a7..0000000000 --- a/packages/medusa-react/src/hooks/admin/draft-orders/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Draft Order API Routes](https://docs.medusajs.com/api/admin#draft-orders). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A draft order is an order created manually by the admin. It allows admins to create orders without direct involvement from the customer. - * - * Related Guide: [How to manage draft orders](https://docs.medusajs.com/modules/orders/admin/manage-draft-orders). - * - * @customNamespace Hooks.Admin.Draft Orders - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/draft-orders/mutations.ts b/packages/medusa-react/src/hooks/admin/draft-orders/mutations.ts deleted file mode 100644 index 089dcc5286..0000000000 --- a/packages/medusa-react/src/hooks/admin/draft-orders/mutations.ts +++ /dev/null @@ -1,411 +0,0 @@ -import { - AdminDraftOrdersDeleteRes, - AdminDraftOrdersRes, - AdminPostDraftOrdersDraftOrderLineItemsItemReq, - AdminPostDraftOrdersDraftOrderLineItemsReq, - AdminPostDraftOrdersDraftOrderRegisterPaymentRes, - AdminPostDraftOrdersDraftOrderReq, - AdminPostDraftOrdersReq, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminDraftOrderKeys } from "./queries" - -/** - * This hook creates a Draft Order. A draft order is not transformed into an order until payment is captured. - * - * @example - * import React from "react" - * import { useAdminCreateDraftOrder } from "medusa-react" - * - * type DraftOrderData = { - * email: string - * region_id: string - * items: { - * quantity: number, - * variant_id: string - * }[] - * shipping_methods: { - * option_id: string - * price: number - * }[] - * } - * - * const CreateDraftOrder = () => { - * const createDraftOrder = useAdminCreateDraftOrder() - * // ... - * - * const handleCreate = (data: DraftOrderData) => { - * createDraftOrder.mutate(data, { - * onSuccess: ({ draft_order }) => { - * console.log(draft_order.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateDraftOrder - * - * @customNamespace Hooks.Admin.Draft Orders - * @category Mutations - */ -export const useAdminCreateDraftOrder = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostDraftOrdersReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostDraftOrdersReq) => - client.admin.draftOrders.create(payload), - buildOptions(queryClient, adminDraftOrderKeys.lists(), options) - ) -} - -/** - * This hook updates a Draft Order's details. - * - * @example - * import React from "react" - * import { useAdminUpdateDraftOrder } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const updateDraftOrder = useAdminUpdateDraftOrder( - * draftOrderId - * ) - * // ... - * - * const handleUpdate = (email: string) => { - * updateDraftOrder.mutate({ - * email, - * }, { - * onSuccess: ({ draft_order }) => { - * console.log(draft_order.id) - * } - * }) - * } - * - * // ... - * } - * - * export default DraftOrder - * - * @customNamespace Hooks.Admin.Draft Orders - * @category Mutations - */ -export const useAdminUpdateDraftOrder = ( - /** - * The draft order's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostDraftOrdersDraftOrderReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostDraftOrdersDraftOrderReq) => - client.admin.draftOrders.update(id, payload), - buildOptions( - queryClient, - [adminDraftOrderKeys.detail(id), adminDraftOrderKeys.lists()], - options - ) - ) -} - -/** - * This hook deletes a Draft Order. - * - * @example - * import React from "react" - * import { useAdminDeleteDraftOrder } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const deleteDraftOrder = useAdminDeleteDraftOrder( - * draftOrderId - * ) - * // ... - * - * const handleDelete = () => { - * deleteDraftOrder.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default DraftOrder - * - * @customNamespace Hooks.Admin.Draft Orders - * @category Mutations - */ -export const useAdminDeleteDraftOrder = ( - /** - * The draft order's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - () => client.admin.draftOrders.delete(id), - buildOptions( - queryClient, - [adminDraftOrderKeys.detail(id), adminDraftOrderKeys.lists()], - options - ) - ) -} - -/** - * This hook capture the draft order's payment. This will also set the draft order's status to `completed` and create an order from the draft order. The payment is captured through Medusa's system payment, - * which is manual payment that isn't integrated with any third-party payment provider. It is assumed that the payment capturing is handled manually by the admin. - * - * @example - * import React from "react" - * import { useAdminDraftOrderRegisterPayment } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const registerPayment = useAdminDraftOrderRegisterPayment( - * draftOrderId - * ) - * // ... - * - * const handlePayment = () => { - * registerPayment.mutate(void 0, { - * onSuccess: ({ order }) => { - * console.log(order.id) - * } - * }) - * } - * - * // ... - * } - * - * export default DraftOrder - * - * @customNamespace Hooks.Admin.Draft Orders - * @category Mutations - */ -export const useAdminDraftOrderRegisterPayment = ( - /** - * The draft order's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - void - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - () => client.admin.draftOrders.markPaid(id), - buildOptions(queryClient, adminDraftOrderKeys.detail(id), options) - ) -} - -/** - * This hook creates a Line Item in the Draft Order. - * - * @example - * import React from "react" - * import { useAdminDraftOrderAddLineItem } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const addLineItem = useAdminDraftOrderAddLineItem( - * draftOrderId - * ) - * // ... - * - * const handleAdd = (quantity: number) => { - * addLineItem.mutate({ - * quantity, - * }, { - * onSuccess: ({ draft_order }) => { - * console.log(draft_order.cart) - * } - * }) - * } - * - * // ... - * } - * - * export default DraftOrder - * - * @customNamespace Hooks.Admin.Draft Orders - * @category Mutations - */ -export const useAdminDraftOrderAddLineItem = ( - /** - * The draft order's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostDraftOrdersDraftOrderLineItemsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostDraftOrdersDraftOrderLineItemsReq) => - client.admin.draftOrders.addLineItem(id, payload), - buildOptions(queryClient, adminDraftOrderKeys.detail(id), options) - ) -} - -/** - * This hook deletes a Line Item from a Draft Order. - * - * @typeParamDefinition string - The ID of the line item to remove. - * - * @example - * import React from "react" - * import { useAdminDraftOrderRemoveLineItem } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const deleteLineItem = useAdminDraftOrderRemoveLineItem( - * draftOrderId - * ) - * // ... - * - * const handleDelete = (itemId: string) => { - * deleteLineItem.mutate(itemId, { - * onSuccess: ({ draft_order }) => { - * console.log(draft_order.cart) - * } - * }) - * } - * - * // ... - * } - * - * export default DraftOrder - * - * @customNamespace Hooks.Admin.Draft Orders - * @category Mutations - */ -export const useAdminDraftOrderRemoveLineItem = ( - /** - * The draft order's ID. - */ - id: string, - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (itemId: string) => client.admin.draftOrders.removeLineItem(id, itemId), - buildOptions(queryClient, adminDraftOrderKeys.detail(id), options) - ) -} - -/** - * The details to update of the line item. - */ -export type AdminDraftOrderUpdateLineItemReq = AdminPostDraftOrdersDraftOrderLineItemsItemReq & { - /** - * The line item's ID to update. - */ - item_id: string -} - -/** - * This hook updates a Line Item in a Draft Order. - * - * @example - * import React from "react" - * import { useAdminDraftOrderUpdateLineItem } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const updateLineItem = useAdminDraftOrderUpdateLineItem( - * draftOrderId - * ) - * // ... - * - * const handleUpdate = ( - * itemId: string, - * quantity: number - * ) => { - * updateLineItem.mutate({ - * item_id: itemId, - * quantity, - * }) - * } - * - * // ... - * } - * - * export default DraftOrder - * - * @customNamespace Hooks.Admin.Draft Orders - * @category Mutations - */ -export const useAdminDraftOrderUpdateLineItem = ( - /** - * The draft order's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminDraftOrderUpdateLineItemReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - ({ - item_id, - ...payload - }: AdminDraftOrderUpdateLineItemReq) => - client.admin.draftOrders.updateLineItem(id, item_id, payload), - buildOptions(queryClient, adminDraftOrderKeys.detail(id), options) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/draft-orders/queries.ts b/packages/medusa-react/src/hooks/admin/draft-orders/queries.ts deleted file mode 100644 index 5c7315a400..0000000000 --- a/packages/medusa-react/src/hooks/admin/draft-orders/queries.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { - AdminDraftOrdersListRes, - AdminDraftOrdersRes, - AdminGetDraftOrdersParams, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_DRAFT_ORDERS_QUERY_KEY = `admin_draft_orders` as const - -export const adminDraftOrderKeys = queryKeysFactory( - ADMIN_DRAFT_ORDERS_QUERY_KEY -) - -type DraftOrderQueryKeys = typeof adminDraftOrderKeys - -/** - * This hook retrieves an list of Draft Orders. The draft orders can be filtered by parameters such as `query`. The draft orders can also paginated. - * - * @example - * To list draft orders: - * - * ```tsx - * import React from "react" - * import { useAdminDraftOrders } from "medusa-react" - * - * const DraftOrders = () => { - * const { draft_orders, isLoading } = useAdminDraftOrders() - * - * return ( - *
- * {isLoading && Loading...} - * {draft_orders && !draft_orders.length && ( - * No Draft Orders - * )} - * {draft_orders && draft_orders.length > 0 && ( - *
    - * {draft_orders.map((order) => ( - *
  • {order.display_id}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default DraftOrders - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminDraftOrders } from "medusa-react" - * - * const DraftOrders = () => { - * const { - * draft_orders, - * limit, - * offset, - * isLoading - * } = useAdminDraftOrders({ - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {draft_orders && !draft_orders.length && ( - * No Draft Orders - * )} - * {draft_orders && draft_orders.length > 0 && ( - *
    - * {draft_orders.map((order) => ( - *
  • {order.display_id}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default DraftOrders - * ``` - * - * @customNamespace Hooks.Admin.Draft Orders - * @category Queries - */ -export const useAdminDraftOrders = ( - /** - * Filters and pagination configurations to apply on the retrieved draft orders. - */ - query?: AdminGetDraftOrdersParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminDraftOrderKeys.list(query), - () => client.admin.draftOrders.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a Draft Order's details. - * - * @example - * import React from "react" - * import { useAdminDraftOrder } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const { - * draft_order, - * isLoading, - * } = useAdminDraftOrder(draftOrderId) - * - * return ( - *
- * {isLoading && Loading...} - * {draft_order && {draft_order.display_id}} - * - *
- * ) - * } - * - * export default DraftOrder - * - * @customNamespace Hooks.Admin.Draft Orders - * @category Queries - */ -export const useAdminDraftOrder = ( - /** - * The draft order's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminDraftOrderKeys.detail(id), - () => client.admin.draftOrders.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/gift-cards/index.ts b/packages/medusa-react/src/hooks/admin/gift-cards/index.ts deleted file mode 100644 index 0be7ee8e00..0000000000 --- a/packages/medusa-react/src/hooks/admin/gift-cards/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Gift Card API Routes](https://docs.medusajs.com/api/admin#gift-cards). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Admins can create gift cards and send them directly to customers, specifying options like their balance, region, and more. - * These gift cards are different than the saleable gift cards in a store, which are created and managed through {@link Hooks.Admin.Products.useAdminCreateProduct | useAdminCreateProduct}. - * - * Related Guide: [How to manage gift cards](https://docs.medusajs.com/modules/gift-cards/admin/manage-gift-cards#manage-custom-gift-cards). - * - * @customNamespace Hooks.Admin.Gift Cards - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/gift-cards/mutations.ts b/packages/medusa-react/src/hooks/admin/gift-cards/mutations.ts deleted file mode 100644 index cffc32353e..0000000000 --- a/packages/medusa-react/src/hooks/admin/gift-cards/mutations.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { - AdminGiftCardsDeleteRes, - AdminGiftCardsRes, - AdminPostGiftCardsGiftCardReq, - AdminPostGiftCardsReq, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminGiftCardKeys } from "./queries" - -/** - * This hook creates a gift card that can redeemed by its unique code. The Gift Card is only valid within one region. - * - * @example - * import React from "react" - * import { useAdminCreateGiftCard } from "medusa-react" - * - * const CreateCustomGiftCards = () => { - * const createGiftCard = useAdminCreateGiftCard() - * // ... - * - * const handleCreate = ( - * regionId: string, - * value: number - * ) => { - * createGiftCard.mutate({ - * region_id: regionId, - * value, - * }, { - * onSuccess: ({ gift_card }) => { - * console.log(gift_card.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateCustomGiftCards - * - * @customNamespace Hooks.Admin.Gift Cards - * @category Mutations - */ -export const useAdminCreateGiftCard = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostGiftCardsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostGiftCardsReq) => client.admin.giftCards.create(payload), - buildOptions(queryClient, adminGiftCardKeys.lists(), options) - ) -} - -/** - * This hook updates a gift card's details. - * - * @example - * import React from "react" - * import { useAdminUpdateGiftCard } from "medusa-react" - * - * type Props = { - * customGiftCardId: string - * } - * - * const CustomGiftCard = ({ customGiftCardId }: Props) => { - * const updateGiftCard = useAdminUpdateGiftCard( - * customGiftCardId - * ) - * // ... - * - * const handleUpdate = (regionId: string) => { - * updateGiftCard.mutate({ - * region_id: regionId, - * }, { - * onSuccess: ({ gift_card }) => { - * console.log(gift_card.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CustomGiftCard - * - * @customNamespace Hooks.Admin.Gift Cards - * @category Mutations - */ -export const useAdminUpdateGiftCard = ( - /** - * The gift card's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostGiftCardsGiftCardReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostGiftCardsGiftCardReq) => - client.admin.giftCards.update(id, payload), - buildOptions( - queryClient, - [adminGiftCardKeys.lists(), adminGiftCardKeys.detail(id)], - options - ) - ) -} - -/** - * This hook deletes a gift card. Once deleted, it can't be used by customers. - * - * @example - * import React from "react" - * import { useAdminDeleteGiftCard } from "medusa-react" - * - * type Props = { - * customGiftCardId: string - * } - * - * const CustomGiftCard = ({ customGiftCardId }: Props) => { - * const deleteGiftCard = useAdminDeleteGiftCard( - * customGiftCardId - * ) - * // ... - * - * const handleDelete = () => { - * deleteGiftCard.mutate(void 0, { - * onSuccess: ({ id, object, deleted}) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default CustomGiftCard - * - * @customNamespace Hooks.Admin.Gift Cards - * @category Mutations - */ -export const useAdminDeleteGiftCard = ( - /** - * The gift card's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - () => client.admin.giftCards.delete(id), - buildOptions( - queryClient, - [adminGiftCardKeys.lists(), adminGiftCardKeys.detail(id)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/gift-cards/queries.ts b/packages/medusa-react/src/hooks/admin/gift-cards/queries.ts deleted file mode 100644 index ae9c446308..0000000000 --- a/packages/medusa-react/src/hooks/admin/gift-cards/queries.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { - AdminGetGiftCardsParams, - AdminGiftCardsListRes, - AdminGiftCardsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_GIFT_CARDS_QUERY_KEY = `admin_gift_cards` as const - -export const adminGiftCardKeys = queryKeysFactory(ADMIN_GIFT_CARDS_QUERY_KEY) - -type GiftCardQueryKeys = typeof adminGiftCardKeys - -/** - * This hook retrieves a list of gift cards. The gift cards can be filtered by fields such as `q` passed in the `query` - * parameter. The gift cards can also paginated. - * - * @example - * To list gift cards: - * - * ```tsx - * import React from "react" - * import { useAdminGiftCards } from "medusa-react" - * - * const CustomGiftCards = () => { - * const { gift_cards, isLoading } = useAdminGiftCards() - * - * return ( - *
- * {isLoading && Loading...} - * {gift_cards && !gift_cards.length && ( - * No custom gift cards... - * )} - * {gift_cards && gift_cards.length > 0 && ( - *
    - * {gift_cards.map((giftCard) => ( - *
  • {giftCard.code}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default CustomGiftCards - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminGiftCards } from "medusa-react" - * - * const CustomGiftCards = () => { - * const { - * gift_cards, - * limit, - * offset, - * isLoading - * } = useAdminGiftCards({ - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {gift_cards && !gift_cards.length && ( - * No custom gift cards... - * )} - * {gift_cards && gift_cards.length > 0 && ( - *
    - * {gift_cards.map((giftCard) => ( - *
  • {giftCard.code}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default CustomGiftCards - * ``` - * - * @customNamespace Hooks.Admin.Gift Cards - * @category Queries - */ -export const useAdminGiftCards = ( - /** - * Filters and pagination configurations to apply on the retrieved gift cards. - */ - query?: AdminGetGiftCardsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminGiftCardKeys.list(query), - () => client.admin.giftCards.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a gift card's details. - * - * @example - * import React from "react" - * import { useAdminGiftCard } from "medusa-react" - * - * type Props = { - * giftCardId: string - * } - * - * const CustomGiftCard = ({ giftCardId }: Props) => { - * const { gift_card, isLoading } = useAdminGiftCard(giftCardId) - * - * return ( - *
- * {isLoading && Loading...} - * {gift_card && {gift_card.code}} - *
- * ) - * } - * - * export default CustomGiftCard - * - * @customNamespace Hooks.Admin.Gift Cards - * @category Queries - */ -export const useAdminGiftCard = ( - /** - * The gift card's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminGiftCardKeys.detail(id), - () => client.admin.giftCards.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/index.ts b/packages/medusa-react/src/hooks/admin/index.ts deleted file mode 100644 index d60dd737dc..0000000000 --- a/packages/medusa-react/src/hooks/admin/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -export * from "./auth" -export * from "./batch-jobs" -export * from "./claims" -export * from "./collections" -export * from "./currencies" -export * from "./custom" -export * from "./customer-groups" -export * from "./customers" -export * from "./discounts" -export * from "./draft-orders" -export * from "./gift-cards" -export * from "./inventory-item" -export * from "./invites" -export * from "./notes" -export * from "./notifications" -export * from "./order-edits" -export * from "./orders" -export * from "./payment-collections" -export * from "./payments" -export * from "./price-lists" -export * from "./product-categories" -export * from "./product-tags" -export * from "./product-types" -export * from "./products" -export * from "./publishable-api-keys" -export * from "./regions" -export * from "./reservations" -export * from "./return-reasons" -export * from "./returns" -export * from "./sales-channels" -export * from "./shipping-options" -export * from "./shipping-profiles" -export * from "./stock-locations" -export * from "./store" -export * from "./swaps" -export * from "./tax-rates" -export * from "./uploads" -export * from "./users" -export * from "./variants" diff --git a/packages/medusa-react/src/hooks/admin/inventory-item/index.ts b/packages/medusa-react/src/hooks/admin/inventory-item/index.ts deleted file mode 100644 index cef82cb3bc..0000000000 --- a/packages/medusa-react/src/hooks/admin/inventory-item/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Inventory Item API Routes](https://docs.medusajs.com/api/admin#inventory-items). - * To use these hooks, make sure to install the - * [@medusajs/inventory](https://docs.medusajs.com/modules/multiwarehouse/install-modules#inventory-module) module in your Medusa backend. - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Inventory items, provided by the [Inventory Module](https://docs.medusajs.com/modules/multiwarehouse/inventory-module), can be - * used to manage the inventory of saleable items in your store. - * - * Related Guide: [How to manage inventory items](https://docs.medusajs.com/modules/multiwarehouse/admin/manage-inventory-items). - * - * @customNamespace Hooks.Admin.Inventory Items - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/inventory-item/mutations.ts b/packages/medusa-react/src/hooks/admin/inventory-item/mutations.ts deleted file mode 100644 index 3ba9d96cd5..0000000000 --- a/packages/medusa-react/src/hooks/admin/inventory-item/mutations.ts +++ /dev/null @@ -1,392 +0,0 @@ -import { - AdminInventoryItemsDeleteRes, - AdminInventoryItemsRes, - AdminPostInventoryItemsInventoryItemReq, - AdminPostInventoryItemsItemLocationLevelsLevelReq, - AdminPostInventoryItemsItemLocationLevelsReq, - AdminPostInventoryItemsReq, - AdminPostInventoryItemsParams -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminInventoryItemsKeys } from "./queries" - -/** - * This hook creates an Inventory Item for a product variant. - * - * @example - * import React from "react" - * import { useAdminCreateInventoryItem } from "medusa-react" - * - * const CreateInventoryItem = () => { - * const createInventoryItem = useAdminCreateInventoryItem() - * // ... - * - * const handleCreate = (variantId: string) => { - * createInventoryItem.mutate({ - * variant_id: variantId, - * }, { - * onSuccess: ({ inventory_item }) => { - * console.log(inventory_item.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateInventoryItem - * - * @customNamespace Hooks.Admin.Inventory Items - * @category Mutations - */ -export const useAdminCreateInventoryItem = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostInventoryItemsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostInventoryItemsReq, query?: AdminPostInventoryItemsParams) => - client.admin.inventoryItems.create(payload, query), - buildOptions( - queryClient, - [adminInventoryItemsKeys.lists()], - options - ) - ) -} - - -/** - * This hook updates an Inventory Item's details. - * - * @example - * import React from "react" - * import { useAdminUpdateInventoryItem } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const updateInventoryItem = useAdminUpdateInventoryItem( - * inventoryItemId - * ) - * // ... - * - * const handleUpdate = (origin_country: string) => { - * updateInventoryItem.mutate({ - * origin_country, - * }, { - * onSuccess: ({ inventory_item }) => { - * console.log(inventory_item.origin_country) - * } - * }) - * } - * - * // ... - * } - * - * export default InventoryItem - * - * @customNamespace Hooks.Admin.Inventory Items - * @category Mutations - */ -export const useAdminUpdateInventoryItem = ( - /** - * The inventory item's ID. - */ - inventoryItemId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostInventoryItemsInventoryItemReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostInventoryItemsInventoryItemReq) => - client.admin.inventoryItems.update(inventoryItemId, payload), - buildOptions( - queryClient, - [adminInventoryItemsKeys.lists(), adminInventoryItemsKeys.detail(inventoryItemId)], - options - ) - ) -} - -/** - * This hook deletes an Inventory Item. This does not delete the associated product variant. - * - * @example - * import React from "react" - * import { useAdminDeleteInventoryItem } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const deleteInventoryItem = useAdminDeleteInventoryItem( - * inventoryItemId - * ) - * // ... - * - * const handleDelete = () => { - * deleteInventoryItem.mutate() - * } - * - * // ... - * } - * - * export default InventoryItem - * - * @customNamespace Hooks.Admin.Inventory Items - * @category Mutations - */ -export const useAdminDeleteInventoryItem = ( - /** - * The inventory item's ID. - */ - inventoryItemId: string, - options?: UseMutationOptions< - Response, - Error, - void - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.inventoryItems.delete(inventoryItemId), - buildOptions( - queryClient, - [adminInventoryItemsKeys.lists(), adminInventoryItemsKeys.detail(inventoryItemId)], - options - ) - ) -} - -export type AdminUpdateLocationLevelReq = AdminPostInventoryItemsItemLocationLevelsLevelReq & { - /** - * The ID of the location level to update. - */ - stockLocationId: string -} - -/** - * This hook updates a location level's details for a given inventory item. - * - * @example - * import React from "react" - * import { useAdminUpdateLocationLevel } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const updateLocationLevel = useAdminUpdateLocationLevel( - * inventoryItemId - * ) - * // ... - * - * const handleUpdate = ( - * stockLocationId: string, - * stockedQuantity: number - * ) => { - * updateLocationLevel.mutate({ - * stockLocationId, - * stocked_quantity: stockedQuantity, - * }, { - * onSuccess: ({ inventory_item }) => { - * console.log(inventory_item.id) - * } - * }) - * } - * - * // ... - * } - * - * export default InventoryItem - * - * @customNamespace Hooks.Admin.Inventory Items - * @category Mutations - */ -export const useAdminUpdateLocationLevel = ( - /** - * The inventory item's ID. - */ - inventoryItemId: string, - options?: UseMutationOptions< - Response, - Error, - AdminUpdateLocationLevelReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - ( - payload: AdminUpdateLocationLevelReq - ) => - client.admin.inventoryItems.updateLocationLevel( - inventoryItemId, - payload.stockLocationId, - { - incoming_quantity: payload.incoming_quantity, - stocked_quantity: payload.stocked_quantity, - } - ), - buildOptions( - queryClient, - [ - adminInventoryItemsKeys.detail(inventoryItemId), - adminInventoryItemsKeys.lists(), - ], - options - ) - ) -} - -/** - * This hook deletes a location level of an Inventory Item. - * - * @typeParamDefinition string - The ID of the location level to delete. - * - * @example - * import React from "react" - * import { useAdminDeleteLocationLevel } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const deleteLocationLevel = useAdminDeleteLocationLevel( - * inventoryItemId - * ) - * // ... - * - * const handleDelete = ( - * locationId: string - * ) => { - * deleteLocationLevel.mutate(locationId) - * } - * - * // ... - * } - * - * export default InventoryItem - * - * @customNamespace Hooks.Admin.Inventory Items - * @category Mutations - */ -export const useAdminDeleteLocationLevel = ( - /** - * The inventory item's ID. - */ - inventoryItemId: string, - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (stockLocationId: string) => - client.admin.inventoryItems.deleteLocationLevel( - inventoryItemId, - stockLocationId - ), - buildOptions( - queryClient, - [ - adminInventoryItemsKeys.detail(inventoryItemId), - adminInventoryItemsKeys.lists(), - ], - options - ) - ) -} - -/** - * This hook creates a Location Level for a given Inventory Item. - * - * @example - * import React from "react" - * import { useAdminCreateLocationLevel } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const createLocationLevel = useAdminCreateLocationLevel( - * inventoryItemId - * ) - * // ... - * - * const handleCreateLocationLevel = ( - * locationId: string, - * stockedQuantity: number - * ) => { - * createLocationLevel.mutate({ - * location_id: locationId, - * stocked_quantity: stockedQuantity, - * }, { - * onSuccess: ({ inventory_item }) => { - * console.log(inventory_item.id) - * } - * }) - * } - * - * // ... - * } - * - * export default InventoryItem - * - * @customNamespace Hooks.Admin.Inventory Items - * @category Mutations - */ -export const useAdminCreateLocationLevel = ( - /** - * The inventory item's ID. - */ - inventoryItemId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostInventoryItemsItemLocationLevelsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostInventoryItemsItemLocationLevelsReq) => - client.admin.inventoryItems.createLocationLevel(inventoryItemId, payload), - buildOptions( - queryClient, - [ - adminInventoryItemsKeys.detail(inventoryItemId), - adminInventoryItemsKeys.lists(), - ], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/inventory-item/queries.ts b/packages/medusa-react/src/hooks/admin/inventory-item/queries.ts deleted file mode 100644 index 2ffa41b34b..0000000000 --- a/packages/medusa-react/src/hooks/admin/inventory-item/queries.ts +++ /dev/null @@ -1,249 +0,0 @@ -import { - AdminGetInventoryItemsItemLocationLevelsParams, - AdminGetInventoryItemsParams, - AdminGetStockLocationsParams, - AdminInventoryItemsListWithVariantsAndLocationLevelsRes, - AdminInventoryItemsLocationLevelsRes, - AdminInventoryItemsRes, -} from "@medusajs/medusa" - -import { Response } from "@medusajs/medusa-js" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" -import { useMedusa } from "../../../contexts" -import { useQuery } from "@tanstack/react-query" - -const ADMIN_INVENTORY_ITEMS_QUERY_KEY = `admin_inventory_items` as const - -export const adminInventoryItemsKeys = queryKeysFactory( - ADMIN_INVENTORY_ITEMS_QUERY_KEY -) - -type InventoryItemsQueryKeys = typeof adminInventoryItemsKeys - -/** - * This hook retrieves a list of inventory items. The inventory items can be filtered by fields such as `q` or `location_id` passed in the `query` parameter. - * The inventory items can also be paginated. - * - * @example - * To list inventory items: - * - * ```tsx - * import React from "react" - * import { useAdminInventoryItems } from "medusa-react" - * - * function InventoryItems() { - * const { - * inventory_items, - * isLoading - * } = useAdminInventoryItems() - * - * return ( - *
- * {isLoading && Loading...} - * {inventory_items && !inventory_items.length && ( - * No Items - * )} - * {inventory_items && inventory_items.length > 0 && ( - *
    - * {inventory_items.map( - * (item) => ( - *
  • {item.id}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default InventoryItems - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminInventoryItems } from "medusa-react" - * - * function InventoryItems() { - * const { - * inventory_items, - * limit, - * offset, - * isLoading - * } = useAdminInventoryItems({ - * limit: 10, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {inventory_items && !inventory_items.length && ( - * No Items - * )} - * {inventory_items && inventory_items.length > 0 && ( - *
    - * {inventory_items.map( - * (item) => ( - *
  • {item.id}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default InventoryItems - * ``` - * - * @customNamespace Hooks.Admin.Inventory Items - * @category Queries - */ -export const useAdminInventoryItems = ( - /** - * Filters and pagination configurations applied on the retrieved inventory items. - */ - query?: AdminGetInventoryItemsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - - const { data, ...rest } = useQuery( - adminInventoryItemsKeys.list(query), - () => client.admin.inventoryItems.list(query), - { ...options } - ) - - return { ...data, ...rest } as const -} - -/** - * This hook retrieves an Inventory Item's details. - * - * @example - * import React from "react" - * import { useAdminInventoryItem } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const { - * inventory_item, - * isLoading - * } = useAdminInventoryItem(inventoryItemId) - * - * return ( - *
- * {isLoading && Loading...} - * {inventory_item && ( - * {inventory_item.sku} - * )} - *
- * ) - * } - * - * export default InventoryItem - * - * @customNamespace Hooks.Admin.Inventory Items - * @category Queries - */ -export const useAdminInventoryItem = ( - /** - * The inventory item's ID. - */ - inventoryItemId: string, - /** - * Configurations applied on the retrieved inventory item. - */ - query?: AdminGetStockLocationsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - - const { data, ...rest } = useQuery( - adminInventoryItemsKeys.detail(inventoryItemId), - () => client.admin.inventoryItems.retrieve(inventoryItemId, query), - { ...options } - ) - - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a list of inventory levels of an inventory item. The inventory levels can be filtered by fields - * such as `location_id` passed in the `query` parameter. - * - * @example - * import React from "react" - * import { - * useAdminInventoryItemLocationLevels, - * } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const { - * inventory_item, - * isLoading, - * } = useAdminInventoryItemLocationLevels(inventoryItemId) - * - * return ( - *
- * {isLoading && Loading...} - * {inventory_item && ( - *
    - * {inventory_item.location_levels.map((level) => ( - * {level.stocked_quantity} - * ))} - *
- * )} - *
- * ) - * } - * - * export default InventoryItem - * - * @customNamespace Hooks.Admin.Inventory Items - * @category Queries - */ -export const useAdminInventoryItemLocationLevels = ( - /** - * The ID of the inventory item that the location levels belong to. - */ - inventoryItemId: string, - /** - * Filters to apply on the retrieved location levels. - */ - query?: AdminGetInventoryItemsItemLocationLevelsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - - const { data, ...rest } = useQuery( - adminInventoryItemsKeys.detail(inventoryItemId), - () => - client.admin.inventoryItems.listLocationLevels(inventoryItemId, query), - { ...options } - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/invites/index.ts b/packages/medusa-react/src/hooks/admin/invites/index.ts deleted file mode 100644 index 1444fbf0a0..0000000000 --- a/packages/medusa-react/src/hooks/admin/invites/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Invite API Routes](https://docs.medusajs.com/api/admin#invites). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * An admin can invite new users to manage their team. This would allow new users to authenticate as admins and perform admin functionalities. - * - * Related Guide: [How to manage invites](https://docs.medusajs.com/modules/users/admin/manage-invites). - * - * @customNamespace Hooks.Admin.Invites - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/invites/mutations.ts b/packages/medusa-react/src/hooks/admin/invites/mutations.ts deleted file mode 100644 index ab4dfe31ad..0000000000 --- a/packages/medusa-react/src/hooks/admin/invites/mutations.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { - AdminInviteDeleteRes, - AdminPostInvitesInviteAcceptReq, -} from "@medusajs/medusa" -import { AdminPostInvitesPayload, Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminInviteKeys } from "./queries" - -/** - * This hook accepts an Invite. This will also delete the invite and create a new user that can log in and perform admin functionalities. - * The user will have the email associated with the invite, and the password provided in the mutation function's parameter. - * - * @example - * import React from "react" - * import { useAdminAcceptInvite } from "medusa-react" - * - * const AcceptInvite = () => { - * const acceptInvite = useAdminAcceptInvite() - * // ... - * - * const handleAccept = ( - * token: string, - * firstName: string, - * lastName: string, - * password: string - * ) => { - * acceptInvite.mutate({ - * token, - * user: { - * first_name: firstName, - * last_name: lastName, - * password, - * }, - * }, { - * onSuccess: () => { - * // invite accepted successfully. - * } - * }) - * } - * - * // ... - * } - * - * export default AcceptInvite - * - * @customNamespace Hooks.Admin.Invites - * @category Mutations - */ -export const useAdminAcceptInvite = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostInvitesInviteAcceptReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostInvitesInviteAcceptReq) => - client.admin.invites.accept(payload), - buildOptions(queryClient, adminInviteKeys.lists(), options) - ) -} - -/** - * This hook resends an invite. This renews the expiry date by seven days and generates a new token for the invite. It also triggers the `invite.created` event, - * so if you have a Notification Provider installed that handles this event, a notification should be sent to the email associated with the - * invite to allow them to accept the invite. - * - * @example - * import React from "react" - * import { useAdminResendInvite } from "medusa-react" - * - * type Props = { - * inviteId: string - * } - * - * const ResendInvite = ({ inviteId }: Props) => { - * const resendInvite = useAdminResendInvite(inviteId) - * // ... - * - * const handleResend = () => { - * resendInvite.mutate(void 0, { - * onSuccess: () => { - * // invite resent successfully - * } - * }) - * } - * - * // ... - * } - * - * export default ResendInvite - * - * @customNamespace Hooks.Admin.Invites - * @category Mutations - */ -export const useAdminResendInvite = ( - /** - * The invite's ID. - */ - id: string, - options?: UseMutationOptions -) => { - const { client } = useMedusa() - return useMutation(() => client.admin.invites.resend(id), options) -} - -export const useAdminCreateInvite = ( - options?: UseMutationOptions, Error, AdminPostInvitesPayload> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostInvitesPayload) => client.admin.invites.create(payload), - buildOptions(queryClient, adminInviteKeys.lists(), options) - ) -} - -/** - * This hook deletes an invite. Only invites that weren't accepted can be deleted. - * - * @example - * import React from "react" - * import { useAdminDeleteInvite } from "medusa-react" - * - * type Props = { - * inviteId: string - * } - * - * const DeleteInvite = ({ inviteId }: Props) => { - * const deleteInvite = useAdminDeleteInvite(inviteId) - * // ... - * - * const handleDelete = () => { - * deleteInvite.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Invite - * - * @customNamespace Hooks.Admin.Invites - * @category Mutations - */ -export const useAdminDeleteInvite = ( - /** - * The invite's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.invites.delete(id), - buildOptions( - queryClient, - [adminInviteKeys.lists(), adminInviteKeys.detail(id)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/invites/queries.ts b/packages/medusa-react/src/hooks/admin/invites/queries.ts deleted file mode 100644 index 7aab357db1..0000000000 --- a/packages/medusa-react/src/hooks/admin/invites/queries.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { AdminListInvitesRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_INVITES_QUERY_KEY = `admin_invites` as const - -export const adminInviteKeys = queryKeysFactory(ADMIN_INVITES_QUERY_KEY) - -type InviteQueryKeys = typeof adminInviteKeys - -/** - * This hook retrieves a list of invites. - * - * @example - * import React from "react" - * import { useAdminInvites } from "medusa-react" - * - * const Invites = () => { - * const { invites, isLoading } = useAdminInvites() - * - * return ( - *
- * {isLoading && Loading...} - * {invites && !invites.length && ( - * No Invites) - * } - * {invites && invites.length > 0 && ( - *
    - * {invites.map((invite) => ( - *
  • {invite.user_email}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Invites - * - * @customNamespace Hooks.Admin.Invites - * @category Queries - */ -export const useAdminInvites = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminInviteKeys.lists(), - () => client.admin.invites.list(), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/notes/index.ts b/packages/medusa-react/src/hooks/admin/notes/index.ts deleted file mode 100644 index 023f0d3517..0000000000 --- a/packages/medusa-react/src/hooks/admin/notes/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Note API Routes](https://docs.medusajs.com/api/admin#notes). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Notes are created by admins and can be associated with any resource. For example, an admin can add a note to an order for additional details or remarks. - * - * @customNamespace Hooks.Admin.Notes - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/notes/mutations.ts b/packages/medusa-react/src/hooks/admin/notes/mutations.ts deleted file mode 100644 index d28178aa3c..0000000000 --- a/packages/medusa-react/src/hooks/admin/notes/mutations.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { - AdminNotesDeleteRes, - AdminNotesRes, - AdminPostNotesNoteReq, - AdminPostNotesReq, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminNoteKeys } from "./queries" - -/** - * This hook creates a Note which can be associated with any resource. - * - * @example - * import React from "react" - * import { useAdminCreateNote } from "medusa-react" - * - * const CreateNote = () => { - * const createNote = useAdminCreateNote() - * // ... - * - * const handleCreate = () => { - * createNote.mutate({ - * resource_id: "order_123", - * resource_type: "order", - * value: "We delivered this order" - * }, { - * onSuccess: ({ note }) => { - * console.log(note.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateNote - * - * @customNamespace Hooks.Admin.Notes - * @category Mutations - */ -export const useAdminCreateNote = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostNotesReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostNotesReq) => client.admin.notes.create(payload), - buildOptions(queryClient, adminNoteKeys.lists(), options) - ) -} - -/** - * This hook updates a Note's details. - * - * @example - * import React from "react" - * import { useAdminUpdateNote } from "medusa-react" - * - * type Props = { - * noteId: string - * } - * - * const Note = ({ noteId }: Props) => { - * const updateNote = useAdminUpdateNote(noteId) - * // ... - * - * const handleUpdate = ( - * value: string - * ) => { - * updateNote.mutate({ - * value - * }, { - * onSuccess: ({ note }) => { - * console.log(note.value) - * } - * }) - * } - * - * // ... - * } - * - * export default Note - * - * @customNamespace Hooks.Admin.Notes - * @category Mutations - */ -export const useAdminUpdateNote = ( - /** - * The note's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostNotesNoteReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostNotesNoteReq) => client.admin.notes.update(id, payload), - buildOptions( - queryClient, - [adminNoteKeys.detail(id), adminNoteKeys.lists()], - options - ) - ) -} - -/** - * This hook deletes a Note. - * - * @example - * import React from "react" - * import { useAdminDeleteNote } from "medusa-react" - * - * type Props = { - * noteId: string - * } - * - * const Note = ({ noteId }: Props) => { - * const deleteNote = useAdminDeleteNote(noteId) - * // ... - * - * const handleDelete = () => { - * deleteNote.mutate() - * } - * - * // ... - * } - * - * export default Note - * - * @customNamespace Hooks.Admin.Notes - * @category Mutations - */ -export const useAdminDeleteNote = ( - /** - * The note's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.notes.delete(id), - buildOptions( - queryClient, - [adminNoteKeys.detail(id), adminNoteKeys.lists()], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/notes/queries.ts b/packages/medusa-react/src/hooks/admin/notes/queries.ts deleted file mode 100644 index cc78d5a6a7..0000000000 --- a/packages/medusa-react/src/hooks/admin/notes/queries.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { - AdminGetNotesParams, - AdminNotesListRes, - AdminNotesRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_NOTE_QUERY_KEY = `admin_notes` as const - -export const adminNoteKeys = queryKeysFactory(ADMIN_NOTE_QUERY_KEY) - -type NoteQueryKeys = typeof adminNoteKeys - -/** - * This hook retrieves a list of notes. The notes can be filtered by fields such as `resource_id` passed in - * the `query` parameter. The notes can also be paginated. - * - * @example - * To list notes: - * - * ```tsx - * import React from "react" - * import { useAdminNotes } from "medusa-react" - * - * const Notes = () => { - * const { notes, isLoading } = useAdminNotes() - * - * return ( - *
- * {isLoading && Loading...} - * {notes && !notes.length && No Notes} - * {notes && notes.length > 0 && ( - *
    - * {notes.map((note) => ( - *
  • {note.resource_type}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Notes - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminNotes } from "medusa-react" - * - * const Notes = () => { - * const { - * notes, - * limit, - * offset, - * isLoading - * } = useAdminNotes({ - * limit: 40, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {notes && !notes.length && No Notes} - * {notes && notes.length > 0 && ( - *
    - * {notes.map((note) => ( - *
  • {note.resource_type}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Notes - * ``` - * - * @customNamespace Hooks.Admin.Notes - * @category Queries - */ -export const useAdminNotes = ( - /** - * Filters and pagination configurations applied on retrieved notes. - */ - query?: AdminGetNotesParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminNoteKeys.list(query), - () => client.admin.notes.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a note's details. - * - * @example - * import React from "react" - * import { useAdminNote } from "medusa-react" - * - * type Props = { - * noteId: string - * } - * - * const Note = ({ noteId }: Props) => { - * const { note, isLoading } = useAdminNote(noteId) - * - * return ( - *
- * {isLoading && Loading...} - * {note && {note.resource_type}} - *
- * ) - * } - * - * export default Note - * - * @customNamespace Hooks.Admin.Notes - * @category Queries - */ -export const useAdminNote = ( - /** - * The note's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminNoteKeys.detail(id), - () => client.admin.notes.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/notifications/index.ts b/packages/medusa-react/src/hooks/admin/notifications/index.ts deleted file mode 100644 index 963466c20c..0000000000 --- a/packages/medusa-react/src/hooks/admin/notifications/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Notification API Routes](https://docs.medusajs.com/api/admin#notifications). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Notifications are sent to customers to inform them of new updates. For example, a notification can be sent to the customer when their order is place or its state is updated. - * The notification's type, such as an email or SMS, is determined by the notification provider installed on the Medusa backend. - * - * @customNamespace Hooks.Admin.Notifications - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/notifications/mutations.ts b/packages/medusa-react/src/hooks/admin/notifications/mutations.ts deleted file mode 100644 index 9cc787ab63..0000000000 --- a/packages/medusa-react/src/hooks/admin/notifications/mutations.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { - AdminNotificationsRes, - AdminPostNotificationsNotificationResendReq, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminNotificationKeys } from "./queries" - -/** - * This hook resends a previously sent notifications, with the same data but optionally to a different address. - * - * @example - * import React from "react" - * import { useAdminResendNotification } from "medusa-react" - * - * type Props = { - * notificationId: string - * } - * - * const Notification = ({ notificationId }: Props) => { - * const resendNotification = useAdminResendNotification( - * notificationId - * ) - * // ... - * - * const handleResend = () => { - * resendNotification.mutate({}, { - * onSuccess: ({ notification }) => { - * console.log(notification.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Notification - * - * @customNamespace Hooks.Admin.Notifications - * @category Mutations - */ -export const useAdminResendNotification = ( - /** - * The ID of the notification. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostNotificationsNotificationResendReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostNotificationsNotificationResendReq) => - client.admin.notifications.resend(id, payload), - buildOptions( - queryClient, - [adminNotificationKeys.lists(), adminNotificationKeys.detail(id)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/notifications/queries.ts b/packages/medusa-react/src/hooks/admin/notifications/queries.ts deleted file mode 100644 index ffc6e06328..0000000000 --- a/packages/medusa-react/src/hooks/admin/notifications/queries.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { - AdminGetNotificationsParams, - AdminNotificationsListRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_NOTIFICATIONS_QUERY_KEY = `admin_notifications` as const - -export const adminNotificationKeys = queryKeysFactory( - ADMIN_NOTIFICATIONS_QUERY_KEY -) - -type NotificationQueryKeys = typeof adminNotificationKeys - -/** - * This hook retrieves a list of notifications. The notifications can be filtered by fields such as `event_name` or `resource_type` passed in the `query` parameter. - * The notifications can also be paginated. - * - * @example - * To list notifications: - * - * ```tsx - * import React from "react" - * import { useAdminNotifications } from "medusa-react" - * - * const Notifications = () => { - * const { notifications, isLoading } = useAdminNotifications() - * - * return ( - *
- * {isLoading && Loading...} - * {notifications && !notifications.length && ( - * No Notifications - * )} - * {notifications && notifications.length > 0 && ( - *
    - * {notifications.map((notification) => ( - *
  • {notification.to}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Notifications - * ``` - * - * To specify relations that should be retrieved within the notifications: - * - * ```tsx - * import React from "react" - * import { useAdminNotifications } from "medusa-react" - * - * const Notifications = () => { - * const { notifications, isLoading } = useAdminNotifications({ - * expand: "provider" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {notifications && !notifications.length && ( - * No Notifications - * )} - * {notifications && notifications.length > 0 && ( - *
    - * {notifications.map((notification) => ( - *
  • {notification.to}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Notifications - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminNotifications } from "medusa-react" - * - * const Notifications = () => { - * const { - * notifications, - * limit, - * offset, - * isLoading - * } = useAdminNotifications({ - * expand: "provider", - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {notifications && !notifications.length && ( - * No Notifications - * )} - * {notifications && notifications.length > 0 && ( - *
    - * {notifications.map((notification) => ( - *
  • {notification.to}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Notifications - * ``` - * - * @customNamespace Hooks.Admin.Notifications - * @category Queries - */ -export const useAdminNotifications = ( - /** - * Filters and pagination configurations applied to the retrieved notifications. - */ - query?: AdminGetNotificationsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminNotificationKeys.list(query), - () => client.admin.notifications.list(query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/order-edits/index.ts b/packages/medusa-react/src/hooks/admin/order-edits/index.ts deleted file mode 100644 index eb52fb0938..0000000000 --- a/packages/medusa-react/src/hooks/admin/order-edits/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Order Edit API Routes](https://docs.medusajs.com/api/admin#order-edits). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * An admin can edit an order to remove, add, or update an item's quantity. When an admin edits an order, they're stored as an `OrderEdit`. - * - * Related Guide: [How to edit an order](https://docs.medusajs.com/modules/orders/admin/edit-order). - * - * @customNamespace Hooks.Admin.Order Edits - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/order-edits/mutations.ts b/packages/medusa-react/src/hooks/admin/order-edits/mutations.ts deleted file mode 100644 index dd2b6b8bfe..0000000000 --- a/packages/medusa-react/src/hooks/admin/order-edits/mutations.ts +++ /dev/null @@ -1,630 +0,0 @@ -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" - -import { - AdminOrderEditDeleteRes, - AdminOrderEditItemChangeDeleteRes, - AdminOrderEditsRes, - AdminPostOrderEditsEditLineItemsLineItemReq, - AdminPostOrderEditsEditLineItemsReq, - AdminPostOrderEditsOrderEditReq, - AdminPostOrderEditsReq, -} from "@medusajs/medusa" - -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminOrderKeys } from "../orders" -import { adminOrderEditsKeys } from "./queries" - -/** - * This hook creates an order edit. - * - * @example - * import React from "react" - * import { useAdminCreateOrderEdit } from "medusa-react" - * - * const CreateOrderEdit = () => { - * const createOrderEdit = useAdminCreateOrderEdit() - * - * const handleCreateOrderEdit = (orderId: string) => { - * createOrderEdit.mutate({ - * order_id: orderId, - * }, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateOrderEdit - * - * @customNamespace Hooks.Admin.Order Edits - * @category Mutations - */ -export const useAdminCreateOrderEdit = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostOrderEditsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostOrderEditsReq) => - client.admin.orderEdits.create(payload), - buildOptions( - queryClient, - [adminOrderEditsKeys.lists(), adminOrderKeys.details()], - options - ) - ) -} - -/** - * This hook deletes an order edit. Only order edits that have the status `created` can be deleted. - * - * @example - * import React from "react" - * import { useAdminDeleteOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const deleteOrderEdit = useAdminDeleteOrderEdit( - * orderEditId - * ) - * - * const handleDelete = () => { - * deleteOrderEdit.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - * @customNamespace Hooks.Admin.Order Edits - * @category Mutations - */ -export const useAdminDeleteOrderEdit = ( - /** - * Order Edit's ID - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.orderEdits.delete(id), - buildOptions( - queryClient, - [ - adminOrderEditsKeys.detail(id), - adminOrderEditsKeys.lists(), - adminOrderKeys.details(), - ], - options - ) - ) -} - -/** - * This hook deletes a line item change that indicates the addition, deletion, or update of a line item in the original order. - * - * @example - * import React from "react" - * import { useAdminDeleteOrderEditItemChange } from "medusa-react" - * - * type Props = { - * orderEditId: string - * itemChangeId: string - * } - * - * const OrderEditItemChange = ({ - * orderEditId, - * itemChangeId - * }: Props) => { - * const deleteItemChange = useAdminDeleteOrderEditItemChange( - * orderEditId, - * itemChangeId - * ) - * - * const handleDeleteItemChange = () => { - * deleteItemChange.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEditItemChange - * - * @customNamespace Hooks.Admin.Order Edits - * @category Mutations - */ -export const useAdminDeleteOrderEditItemChange = ( - /** - * The order edit's ID. - */ - orderEditId: string, - /** - * The line item change's ID. - */ - itemChangeId: string, - options?: UseMutationOptions< - Response, - Error, - void - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.orderEdits.deleteItemChange(orderEditId, itemChangeId), - buildOptions( - queryClient, - [adminOrderEditsKeys.detail(orderEditId), adminOrderEditsKeys.lists()], - options - ) - ) -} - -/** - * This hook creates or updates a line item change in the order edit that indicates addition, deletion, or update of a line item - * into an original order. Line item changes are only reflected on the original order after the order edit is confirmed. - * - * @example - * import React from "react" - * import { useAdminOrderEditUpdateLineItem } from "medusa-react" - * - * type Props = { - * orderEditId: string - * itemId: string - * } - * - * const OrderEditItemChange = ({ - * orderEditId, - * itemId - * }: Props) => { - * const updateLineItem = useAdminOrderEditUpdateLineItem( - * orderEditId, - * itemId - * ) - * - * const handleUpdateLineItem = (quantity: number) => { - * updateLineItem.mutate({ - * quantity, - * }, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.items) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEditItemChange - * - * @customNamespace Hooks.Admin.Order Edits - * @category Mutations - */ -export const useAdminOrderEditUpdateLineItem = ( - /** - * The order edit's ID. - */ - orderEditId: string, - /** - * The line item's ID. - */ - itemId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostOrderEditsEditLineItemsLineItemReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostOrderEditsEditLineItemsLineItemReq) => - client.admin.orderEdits.updateLineItem(orderEditId, itemId, payload), - buildOptions( - queryClient, - [adminOrderEditsKeys.detail(orderEditId), adminOrderEditsKeys.lists()], - options - ) - ) -} - -/** - * This hook creates a line item change in the order edit that indicates deleting an item in the original order. - * The item in the original order will not be deleted until the order edit is confirmed. - * - * @example - * import React from "react" - * import { useAdminOrderEditDeleteLineItem } from "medusa-react" - * - * type Props = { - * orderEditId: string - * itemId: string - * } - * - * const OrderEditLineItem = ({ - * orderEditId, - * itemId - * }: Props) => { - * const removeLineItem = useAdminOrderEditDeleteLineItem( - * orderEditId, - * itemId - * ) - * - * const handleRemoveLineItem = () => { - * removeLineItem.mutate(void 0, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.changes) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEditLineItem - * - * @customNamespace Hooks.Admin.Order Edits - * @category Mutations - */ -export const useAdminOrderEditDeleteLineItem = ( - /** - * The order edit's ID. - */ - orderEditId: string, - /** - * The line item's ID. - */ - itemId: string, - options?: UseMutationOptions, Error> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.orderEdits.removeLineItem(orderEditId, itemId), - buildOptions( - queryClient, - [adminOrderEditsKeys.detail(orderEditId), adminOrderEditsKeys.lists()], - options - ) - ) -} - -/** - * This hook updates an Order Edit's details. - * - * @example - * import React from "react" - * import { useAdminUpdateOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const updateOrderEdit = useAdminUpdateOrderEdit( - * orderEditId, - * ) - * - * const handleUpdate = ( - * internalNote: string - * ) => { - * updateOrderEdit.mutate({ - * internal_note: internalNote - * }, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.internal_note) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - * @customNamespace Hooks.Admin.Order Edits - * @category Mutations - */ -export const useAdminUpdateOrderEdit = ( - /** - * The order edit's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostOrderEditsOrderEditReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostOrderEditsOrderEditReq) => - client.admin.orderEdits.update(id, payload), - buildOptions( - queryClient, - [ - adminOrderEditsKeys.lists(), - adminOrderEditsKeys.detail(id), - adminOrderKeys.details(), - ], - options - ) - ) -} - -/** - * This hook creates a line item change in the order edit that indicates adding an item in the original order. - * The item will not be added to the original order until the order edit is confirmed. - * - * @example - * import React from "react" - * import { useAdminOrderEditAddLineItem } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const addLineItem = useAdminOrderEditAddLineItem( - * orderEditId - * ) - * - * const handleAddLineItem = - * (quantity: number, variantId: string) => { - * addLineItem.mutate({ - * quantity, - * variant_id: variantId, - * }, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.changes) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - * @customNamespace Hooks.Admin.Order Edits - * @category Mutations - */ -export const useAdminOrderEditAddLineItem = ( - /** - * The order edit's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostOrderEditsEditLineItemsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostOrderEditsEditLineItemsReq) => - client.admin.orderEdits.addLineItem(id, payload), - buildOptions( - queryClient, - [adminOrderEditsKeys.lists(), adminOrderEditsKeys.detail(id)], - options - ) - ) -} - -/** - * This hook requests customer confirmation of an order edit. This would emit the event `order-edit.requested` which Notification Providers listen to and send - * a notification to the customer about the order edit. - * - * @example - * import React from "react" - * import { - * useAdminRequestOrderEditConfirmation, - * } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const requestOrderConfirmation = - * useAdminRequestOrderEditConfirmation( - * orderEditId - * ) - * - * const handleRequestConfirmation = () => { - * requestOrderConfirmation.mutate(void 0, { - * onSuccess: ({ order_edit }) => { - * console.log( - * order_edit.requested_at, - * order_edit.requested_by - * ) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - * @customNamespace Hooks.Admin.Order Edits - * @category Mutations - */ -export const useAdminRequestOrderEditConfirmation = ( - /** - * The order edit's ID. - */ - id: string, - options?: UseMutationOptions, Error> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.orderEdits.requestConfirmation(id), - buildOptions( - queryClient, - [ - adminOrderEditsKeys.lists(), - adminOrderEditsKeys.detail(id), - adminOrderKeys.details(), - ], - options - ) - ) -} - -/** - * This hook cancels an order edit. - * - * @example - * import React from "react" - * import { - * useAdminCancelOrderEdit, - * } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const cancelOrderEdit = - * useAdminCancelOrderEdit( - * orderEditId - * ) - * - * const handleCancel = () => { - * cancelOrderEdit.mutate(void 0, { - * onSuccess: ({ order_edit }) => { - * console.log( - * order_edit.id - * ) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - * @customNamespace Hooks.Admin.Order Edits - * @category Mutations - */ -export const useAdminCancelOrderEdit = ( - /** - * The order edit's ID. - */ - id: string, - options?: UseMutationOptions, Error> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.orderEdits.cancel(id), - buildOptions( - queryClient, - [ - adminOrderEditsKeys.lists(), - adminOrderEditsKeys.detail(id), - adminOrderKeys.details(), - ], - options - ) - ) -} - -/** - * This hook confirms an order edit. This will reflect the changes in the order edit on the associated order. - * - * @example - * import React from "react" - * import { useAdminConfirmOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const confirmOrderEdit = useAdminConfirmOrderEdit( - * orderEditId - * ) - * - * const handleConfirmOrderEdit = () => { - * confirmOrderEdit.mutate(void 0, { - * onSuccess: ({ order_edit }) => { - * console.log( - * order_edit.confirmed_at, - * order_edit.confirmed_by - * ) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - * @customNamespace Hooks.Admin.Order Edits - * @category Mutations - */ -export const useAdminConfirmOrderEdit = ( - /** - * The order edit's ID. - */ - id: string, - options?: UseMutationOptions, Error> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.orderEdits.confirm(id), - buildOptions( - queryClient, - [ - adminOrderEditsKeys.lists(), - adminOrderEditsKeys.detail(id), - adminOrderKeys.details(), - ], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/order-edits/queries.ts b/packages/medusa-react/src/hooks/admin/order-edits/queries.ts deleted file mode 100644 index 1b387ac3e8..0000000000 --- a/packages/medusa-react/src/hooks/admin/order-edits/queries.ts +++ /dev/null @@ -1,238 +0,0 @@ -import { - AdminOrderEditsListRes, - AdminOrderEditsRes, - GetOrderEditsOrderEditParams, - GetOrderEditsParams, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const ADMIN_ORDER_EDITS_QUERY_KEY = `admin_order_edits` as const - -export const adminOrderEditsKeys = queryKeysFactory(ADMIN_ORDER_EDITS_QUERY_KEY) -type OrderEditQueryKeys = typeof adminOrderEditsKeys - -/** - * This hook retrieves an order edit's details. - * - * @example - * A simple example that retrieves an order edit by its ID: - * - * ```tsx - * import React from "react" - * import { useAdminOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const { - * order_edit, - * isLoading, - * } = useAdminOrderEdit(orderEditId) - * - * return ( - *
- * {isLoading && Loading...} - * {order_edit && {order_edit.status}} - *
- * ) - * } - * - * export default OrderEdit - * ``` - * - * To specify relations that should be retrieved: - * - * ```tsx - * import React from "react" - * import { useAdminOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const { - * order_edit, - * isLoading, - * } = useAdminOrderEdit( - * orderEditId, - * { - * expand: "order" - * } - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {order_edit && {order_edit.status}} - *
- * ) - * } - * - * export default OrderEdit - * ``` - * - * @customNamespace Hooks.Admin.Order Edits - * @category Queries - */ -export const useAdminOrderEdit = ( - /** - * The order edit's ID. - */ - id: string, - /** - * Configurations to apply on the retrieved order edit. - */ - query?: GetOrderEditsOrderEditParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminOrderEditsKeys.detail(id), - () => client.admin.orderEdits.retrieve(id, query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a list of order edits. The order edits can be filtered by fields such as `q` or `order_id` passed to the `query` parameter. - * The order edits can also be paginated. - * - * @example - * To list order edits: - * - * ```tsx - * import React from "react" - * import { useAdminOrderEdits } from "medusa-react" - * - * const OrderEdits = () => { - * const { order_edits, isLoading } = useAdminOrderEdits() - * - * return ( - *
- * {isLoading && Loading...} - * {order_edits && !order_edits.length && ( - * No Order Edits - * )} - * {order_edits && order_edits.length > 0 && ( - *
    - * {order_edits.map((orderEdit) => ( - *
  • - * {orderEdit.status} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default OrderEdits - * ``` - * - * To specify relations that should be retrieved within the order edits: - * - * ```tsx - * import React from "react" - * import { useAdminOrderEdits } from "medusa-react" - * - * const OrderEdits = () => { - * const { order_edits, isLoading } = useAdminOrderEdits({ - * expand: "order" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {order_edits && !order_edits.length && ( - * No Order Edits - * )} - * {order_edits && order_edits.length > 0 && ( - *
    - * {order_edits.map((orderEdit) => ( - *
  • - * {orderEdit.status} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default OrderEdits - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminOrderEdits } from "medusa-react" - * - * const OrderEdits = () => { - * const { - * order_edits, - * limit, - * offset, - * isLoading - * } = useAdminOrderEdits({ - * expand: "order", - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {order_edits && !order_edits.length && ( - * No Order Edits - * )} - * {order_edits && order_edits.length > 0 && ( - *
    - * {order_edits.map((orderEdit) => ( - *
  • - * {orderEdit.status} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default OrderEdits - * ``` - * - * @customNamespace Hooks.Admin.Order Edits - * @category Queries - */ -export const useAdminOrderEdits = ( - /** - * Filters and pagination configurations applied to retrieved order edits. - */ - query?: GetOrderEditsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminOrderEditsKeys.list(query), - () => client.admin.orderEdits.list(query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/orders/index.ts b/packages/medusa-react/src/hooks/admin/orders/index.ts deleted file mode 100644 index 19ed3736d1..0000000000 --- a/packages/medusa-react/src/hooks/admin/orders/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Order API Routes](https://docs.medusajs.com/api/admin#orders). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Orders are purchases made by customers, typically through a storefront using cart. Managing orders include managing fulfillment, payment, claims, reservations, and more. - * - * Related Guide: [How to manage orders](https://docs.medusajs.com/modules/orders/admin/manage-orders). - * - * @customNamespace Hooks.Admin.Orders - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/orders/mutations.ts b/packages/medusa-react/src/hooks/admin/orders/mutations.ts deleted file mode 100644 index 9a6a2be581..0000000000 --- a/packages/medusa-react/src/hooks/admin/orders/mutations.ts +++ /dev/null @@ -1,674 +0,0 @@ -import { - AdminOrdersRes, - AdminPostOrdersOrderFulfillmentsReq, - AdminPostOrdersOrderRefundsReq, - AdminPostOrdersOrderReq, - AdminPostOrdersOrderReturnsReq, - AdminPostOrdersOrderShipmentReq, - AdminPostOrdersOrderShippingMethodsReq, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminProductKeys } from "../products" -import { adminVariantKeys } from "../variants" -import { adminOrderKeys } from "./queries" - -/** - * This hook updates an order's details. - * - * @example - * import React from "react" - * import { useAdminUpdateOrder } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const updateOrder = useAdminUpdateOrder( - * orderId - * ) - * - * const handleUpdate = ( - * email: string - * ) => { - * updateOrder.mutate({ - * email, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.email) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - * @customNamespace Hooks.Admin.Orders - * @category Mutations - */ -export const useAdminUpdateOrder = ( - /** - * The order's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostOrdersOrderReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostOrdersOrderReq) => - client.admin.orders.update(id, payload), - buildOptions( - queryClient, - [adminOrderKeys.lists(), adminOrderKeys.detail(id)], - options - ) - ) -} - -/** - * This hook cancels an order and change its status. This will also cancel any associated fulfillments and payments, - * and it may fail if the payment or fulfillment Provider is unable to cancel the payment/fulfillment. - * - * @example - * import React from "react" - * import { useAdminCancelOrder } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const cancelOrder = useAdminCancelOrder( - * orderId - * ) - * // ... - * - * const handleCancel = () => { - * cancelOrder.mutate(void 0, { - * onSuccess: ({ order }) => { - * console.log(order.status) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - * @customNamespace Hooks.Admin.Orders - * @category Mutations - */ -export const useAdminCancelOrder = ( - /** - * The order's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.orders.cancel(id), - buildOptions( - queryClient, - [adminOrderKeys.lists(), adminOrderKeys.detail(id)], - options - ) - ) -} - -/** - * This hook completes an order and change its status. A canceled order can't be completed. - * - * @example - * import React from "react" - * import { useAdminCompleteOrder } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const completeOrder = useAdminCompleteOrder( - * orderId - * ) - * // ... - * - * const handleComplete = () => { - * completeOrder.mutate(void 0, { - * onSuccess: ({ order }) => { - * console.log(order.status) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - * @customNamespace Hooks.Admin.Orders - * @category Mutations - */ -export const useAdminCompleteOrder = ( - /** - * The order's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.orders.complete(id), - buildOptions( - queryClient, - [adminOrderKeys.lists(), adminOrderKeys.detail(id)], - options - ) - ) -} - -/** - * This hook captures all the payments associated with an order. The payment of canceled orders can't be captured. - * - * @example - * import React from "react" - * import { useAdminCapturePayment } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const capturePayment = useAdminCapturePayment( - * orderId - * ) - * // ... - * - * const handleCapture = () => { - * capturePayment.mutate(void 0, { - * onSuccess: ({ order }) => { - * console.log(order.status) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - * @customNamespace Hooks.Admin.Orders - * @category Mutations - */ -export const useAdminCapturePayment = ( - /** - * The order's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.orders.capturePayment(id), - buildOptions( - queryClient, - [adminOrderKeys.lists(), adminOrderKeys.detail(id)], - options - ) - ) -} - -/** - * This hook refunds an amount for an order. The amount must be less than or equal the `refundable_amount` of the order. - * - * @example - * import React from "react" - * import { useAdminRefundPayment } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const refundPayment = useAdminRefundPayment( - * orderId - * ) - * // ... - * - * const handleRefund = ( - * amount: number, - * reason: string - * ) => { - * refundPayment.mutate({ - * amount, - * reason, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.refunds) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - * @customNamespace Hooks.Admin.Orders - * @category Mutations - */ -export const useAdminRefundPayment = ( - /** - * The order's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostOrdersOrderRefundsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostOrdersOrderRefundsReq) => - client.admin.orders.refundPayment(id, payload), - buildOptions( - queryClient, - [adminOrderKeys.lists(), adminOrderKeys.detail(id)], - options - ) - ) -} - -/** - * This hook creates a Fulfillment of an Order using the fulfillment provider, and change the order's - * fulfillment status to either `partially_fulfilled` or `fulfilled`, depending on - * whether all the items were fulfilled. - * - * @example - * import React from "react" - * import { useAdminCreateFulfillment } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const createFulfillment = useAdminCreateFulfillment( - * orderId - * ) - * // ... - * - * const handleCreateFulfillment = ( - * itemId: string, - * quantity: number - * ) => { - * createFulfillment.mutate({ - * items: [ - * { - * item_id: itemId, - * quantity, - * }, - * ], - * }, { - * onSuccess: ({ order }) => { - * console.log(order.fulfillments) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - * @customNamespace Hooks.Admin.Orders - * @category Mutations - */ -export const useAdminCreateFulfillment = ( - /** - * The order's ID. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostOrdersOrderFulfillmentsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostOrdersOrderFulfillmentsReq) => - client.admin.orders.createFulfillment(orderId, payload), - buildOptions( - queryClient, - [ - adminOrderKeys.lists(), - adminOrderKeys.detail(orderId), - adminVariantKeys.all, - adminProductKeys.lists(), - ], - options - ) - ) -} - -/** - * This hook cancels an order's fulfillment and change its fulfillment status to `canceled`. - * - * @typeParamDefinition string - The fulfillment's ID. - * - * @example - * import React from "react" - * import { useAdminCancelFulfillment } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const cancelFulfillment = useAdminCancelFulfillment( - * orderId - * ) - * // ... - * - * const handleCancel = ( - * fulfillmentId: string - * ) => { - * cancelFulfillment.mutate(fulfillmentId, { - * onSuccess: ({ order }) => { - * console.log(order.fulfillments) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - * @customNamespace Hooks.Admin.Orders - * @category Mutations - */ -export const useAdminCancelFulfillment = ( - /** - * The order's ID. - */ - orderId: string, - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (fulfillmentId: string) => - client.admin.orders.cancelFulfillment(orderId, fulfillmentId), - buildOptions( - queryClient, - [adminOrderKeys.lists(), adminOrderKeys.detail(orderId)], - options - ) - ) -} - -/** - * This hook creates a shipment and mark a fulfillment as shipped. This changes the order's fulfillment status to either - * `partially_shipped` or `shipped`, depending on whether all the items were shipped. - * - * @example - * import React from "react" - * import { useAdminCreateShipment } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const createShipment = useAdminCreateShipment( - * orderId - * ) - * // ... - * - * const handleCreate = ( - * fulfillmentId: string - * ) => { - * createShipment.mutate({ - * fulfillment_id: fulfillmentId, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.fulfillment_status) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - * @customNamespace Hooks.Admin.Orders - * @category Mutations - */ -export const useAdminCreateShipment = ( - /** - * The order's ID. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostOrdersOrderShipmentReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostOrdersOrderShipmentReq) => - client.admin.orders.createShipment(orderId, payload), - buildOptions(queryClient, adminOrderKeys.detail(orderId), options) - ) -} - -/** - * This hook requests and create a return for items in an order. If the return shipping method is specified, it will be automatically fulfilled. - * - * @example - * import React from "react" - * import { useAdminRequestReturn } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const requestReturn = useAdminRequestReturn( - * orderId - * ) - * // ... - * - * const handleRequestingReturn = ( - * itemId: string, - * quantity: number - * ) => { - * requestReturn.mutate({ - * items: [ - * { - * item_id: itemId, - * quantity - * } - * ] - * }, { - * onSuccess: ({ order }) => { - * console.log(order.returns) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - * @customNamespace Hooks.Admin.Orders - * @category Mutations - */ -export const useAdminRequestReturn = ( - /** - * The order's ID. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostOrdersOrderReturnsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostOrdersOrderReturnsReq) => - client.admin.orders.requestReturn(orderId, payload), - buildOptions(queryClient, adminOrderKeys.detail(orderId), options) - ) -} - -/** - * This hook adds a shipping method to an order. If another shipping method exists with the same shipping profile, the previous shipping method will be replaced. - * - * @example - * import React from "react" - * import { useAdminAddShippingMethod } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const addShippingMethod = useAdminAddShippingMethod( - * orderId - * ) - * // ... - * - * const handleAddShippingMethod = ( - * optionId: string, - * price: number - * ) => { - * addShippingMethod.mutate({ - * option_id: optionId, - * price - * }, { - * onSuccess: ({ order }) => { - * console.log(order.shipping_methods) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - * @customNamespace Hooks.Admin.Orders - * @category Mutations - */ -export const useAdminAddShippingMethod = ( - /** - * The order's ID. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostOrdersOrderShippingMethodsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostOrdersOrderShippingMethodsReq) => - client.admin.orders.addShippingMethod(orderId, payload), - buildOptions(queryClient, adminOrderKeys.detail(orderId), options) - ) -} - -/** - * The hook archives an order and change its status. - * - * @example - * import React from "react" - * import { useAdminArchiveOrder } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const archiveOrder = useAdminArchiveOrder( - * orderId - * ) - * // ... - * - * const handleArchivingOrder = () => { - * archiveOrder.mutate(void 0, { - * onSuccess: ({ order }) => { - * console.log(order.status) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - * @customNamespace Hooks.Admin.Orders - * @category Mutations - */ -export const useAdminArchiveOrder = ( - /** - * The order's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.orders.archive(id), - buildOptions( - queryClient, - [adminOrderKeys.lists(), adminOrderKeys.detail(id)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/orders/queries.ts b/packages/medusa-react/src/hooks/admin/orders/queries.ts deleted file mode 100644 index 2af90cc7be..0000000000 --- a/packages/medusa-react/src/hooks/admin/orders/queries.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { - AdminGetOrdersParams, - AdminOrdersListRes, - AdminOrdersRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { FindParams } from "@medusajs/medusa/dist/types/common" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_ORDERS_QUERY_KEY = `admin_orders` as const - -export const adminOrderKeys = { - ...queryKeysFactory(ADMIN_ORDERS_QUERY_KEY), - detailOrder(id: string, query?: FindParams) { - return [...this.detail(id), { ...(query || {}) }] - }, -} - -type OrderQueryKeys = typeof adminOrderKeys - -/** - * This hook retrieves a list of orders. The orders can be filtered by fields such as `status` or `display_id` passed - * in the `query` parameter. The order can also be paginated. - * - * @example - * To list orders: - * - * ```tsx - * import React from "react" - * import { useAdminOrders } from "medusa-react" - * - * const Orders = () => { - * const { orders, isLoading } = useAdminOrders() - * - * return ( - *
- * {isLoading && Loading...} - * {orders && !orders.length && No Orders} - * {orders && orders.length > 0 && ( - *
    - * {orders.map((order) => ( - *
  • {order.display_id}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Orders - * ``` - * - * You can use the `query` parameter to pass filters and specify relations that should be retrieved within the orders. In addition, - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminOrders } from "medusa-react" - * - * const Orders = () => { - * const { - * orders, - * limit, - * offset, - * isLoading - * } = useAdminOrders({ - * expand: "customers", - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {orders && !orders.length && No Orders} - * {orders && orders.length > 0 && ( - *
    - * {orders.map((order) => ( - *
  • {order.display_id}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Orders - * ``` - * - * @customNamespace Hooks.Admin.Orders - * @category Queries - */ -export const useAdminOrders = ( - /** - * Filters and pagination configurations applied on the retrieved orders. - */ - query?: AdminGetOrdersParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminOrderKeys.list(query), - () => client.admin.orders.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieve an order's details. - * - * @example - * A simple example that retrieves an order by its ID: - * - * ```tsx - * import React from "react" - * import { useAdminOrder } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const { - * order, - * isLoading, - * } = useAdminOrder(orderId) - * - * return ( - *
- * {isLoading && Loading...} - * {order && {order.display_id}} - * - *
- * ) - * } - * - * export default Order - * ``` - * - * To specify relations that should be retrieved: - * - * ```tsx - * import React from "react" - * import { useAdminOrder } from "medusa-react" - * - * const Order = ( - * orderId: string - * ) => { - * const { - * order, - * isLoading, - * } = useAdminOrder(orderId, { - * expand: "customer" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {order && {order.display_id}} - * - *
- * ) - * } - * - * export default Order - * ``` - * - * @customNamespace Hooks.Admin.Orders - * @category Queries - */ -export const useAdminOrder = ( - /** - * The order's ID. - */ - id: string, - /** - * Configurations to apply on the retrieved order. - */ - query?: FindParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminOrderKeys.detailOrder(id, query), - () => client.admin.orders.retrieve(id, query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/payment-collections/index.ts b/packages/medusa-react/src/hooks/admin/payment-collections/index.ts deleted file mode 100644 index 46d9d45298..0000000000 --- a/packages/medusa-react/src/hooks/admin/payment-collections/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Payment Collection API Routes](https://docs.medusajs.com/api/admin#payment-collections). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A payment collection is useful for managing additional payments, such as for Order Edits, or installment payments. - * - * @customNamespace Hooks.Admin.Payment Collections - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/payment-collections/mutations.ts b/packages/medusa-react/src/hooks/admin/payment-collections/mutations.ts deleted file mode 100644 index da0950e780..0000000000 --- a/packages/medusa-react/src/hooks/admin/payment-collections/mutations.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" - -import { - AdminPaymentCollectionDeleteRes, - AdminPaymentCollectionsRes, - AdminUpdatePaymentCollectionsReq, -} from "@medusajs/medusa" - -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminPaymentCollectionQueryKeys } from "./queries" - -/** - * This hook deletes a payment collection. Only payment collections with the statuses `canceled` or `not_paid` can be deleted. - * - * @example - * import React from "react" - * import { useAdminDeletePaymentCollection } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ paymentCollectionId }: Props) => { - * const deleteCollection = useAdminDeletePaymentCollection( - * paymentCollectionId - * ) - * // ... - * - * const handleDelete = () => { - * deleteCollection.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - * @customNamespace Hooks.Admin.Payment Collections - * @category Mutations - */ -export const useAdminDeletePaymentCollection = ( - /** - * The payment collection's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - void - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.paymentCollections.delete(id), - buildOptions( - queryClient, - [ - adminPaymentCollectionQueryKeys.detail(id), - adminPaymentCollectionQueryKeys.lists(), - ], - options - ) - ) -} - -/** - * This hook updates a payment collection's details. - * - * @example - * import React from "react" - * import { useAdminUpdatePaymentCollection } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ paymentCollectionId }: Props) => { - * const updateCollection = useAdminUpdatePaymentCollection( - * paymentCollectionId - * ) - * // ... - * - * const handleUpdate = ( - * description: string - * ) => { - * updateCollection.mutate({ - * description - * }, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.description) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - * @customNamespace Hooks.Admin.Payment Collections - * @category Mutations - */ -export const useAdminUpdatePaymentCollection = ( - /** - * The payment collection's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminUpdatePaymentCollectionsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminUpdatePaymentCollectionsReq) => - client.admin.paymentCollections.update(id, payload), - buildOptions( - queryClient, - [ - adminPaymentCollectionQueryKeys.detail(id), - adminPaymentCollectionQueryKeys.lists(), - ], - options - ) - ) -} - -/** - * This hook sets the status of a payment collection as `authorized`. This will also change the `authorized_amount` of the payment collection. - * - * @example - * import React from "react" - * import { useAdminMarkPaymentCollectionAsAuthorized } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ paymentCollectionId }: Props) => { - * const markAsAuthorized = useAdminMarkPaymentCollectionAsAuthorized( - * paymentCollectionId - * ) - * // ... - * - * const handleAuthorization = () => { - * markAsAuthorized.mutate(void 0, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.status) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - * @customNamespace Hooks.Admin.Payment Collections - * @category Mutations - */ -export const useAdminMarkPaymentCollectionAsAuthorized = ( - /** - * The payment collection's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - void - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.paymentCollections.markAsAuthorized(id), - buildOptions( - queryClient, - [ - adminPaymentCollectionQueryKeys.detail(id), - adminPaymentCollectionQueryKeys.lists(), - ], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/payment-collections/queries.ts b/packages/medusa-react/src/hooks/admin/payment-collections/queries.ts deleted file mode 100644 index 17a7a9f055..0000000000 --- a/packages/medusa-react/src/hooks/admin/payment-collections/queries.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { AdminPaymentCollectionsRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const PAYMENT_COLLECTION_QUERY_KEY = `paymentCollection` as const - -export const adminPaymentCollectionQueryKeys = queryKeysFactory< - typeof PAYMENT_COLLECTION_QUERY_KEY ->(PAYMENT_COLLECTION_QUERY_KEY) - -type AdminPaymentCollectionKey = typeof adminPaymentCollectionQueryKeys - -/** - * This hook retrieves a Payment Collection's details. - * - * @example - * import React from "react" - * import { useAdminPaymentCollection } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ paymentCollectionId }: Props) => { - * const { - * payment_collection, - * isLoading, - * } = useAdminPaymentCollection(paymentCollectionId) - * - * return ( - *
- * {isLoading && Loading...} - * {payment_collection && ( - * {payment_collection.status} - * )} - * - *
- * ) - * } - * - * export default PaymentCollection - * - * @customNamespace Hooks.Admin.Payment Collections - * @category Queries - */ -export const useAdminPaymentCollection = ( - /** - * The payment collection's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminPaymentCollectionQueryKeys.detail(id), - () => client.admin.paymentCollections.retrieve(id), - options - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/payments/index.ts b/packages/medusa-react/src/hooks/admin/payments/index.ts deleted file mode 100644 index 334dc544c0..0000000000 --- a/packages/medusa-react/src/hooks/admin/payments/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Payment API Routes](https://docs.medusajs.com/api/admin#payments). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A payment can be related to an order, swap, return, or more. It can be captured or refunded. - * - * @customNamespace Hooks.Admin.Payments - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/payments/mutations.ts b/packages/medusa-react/src/hooks/admin/payments/mutations.ts deleted file mode 100644 index 05b7082ac0..0000000000 --- a/packages/medusa-react/src/hooks/admin/payments/mutations.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" - -import { - AdminPaymentRes, - AdminPostPaymentRefundsReq, - AdminRefundRes, -} from "@medusajs/medusa" - -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminPaymentQueryKeys } from "./queries" - -/** - * This hook captures a payment. - * - * @example - * import React from "react" - * import { useAdminPaymentsCapturePayment } from "medusa-react" - * - * type Props = { - * paymentId: string - * } - * - * const Payment = ({ paymentId }: Props) => { - * const capture = useAdminPaymentsCapturePayment( - * paymentId - * ) - * // ... - * - * const handleCapture = () => { - * capture.mutate(void 0, { - * onSuccess: ({ payment }) => { - * console.log(payment.amount) - * } - * }) - * } - * - * // ... - * } - * - * export default Payment - * - * @customNamespace Hooks.Admin.Payments - * @category Mutations - */ -export const useAdminPaymentsCapturePayment = ( - /** - * The payment's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.payments.capturePayment(id), - buildOptions( - queryClient, - [adminPaymentQueryKeys.detail(id), adminPaymentQueryKeys.lists()], - options - ) - ) -} - -/** - * This hook refunds a payment. The payment must be captured first. - * - * @example - * import React from "react" - * import { RefundReason } from "@medusajs/medusa" - * import { useAdminPaymentsRefundPayment } from "medusa-react" - * - * type Props = { - * paymentId: string - * } - * - * const Payment = ({ paymentId }: Props) => { - * const refund = useAdminPaymentsRefundPayment( - * paymentId - * ) - * // ... - * - * const handleRefund = ( - * amount: number, - * reason: RefundReason, - * note: string - * ) => { - * refund.mutate({ - * amount, - * reason, - * note - * }, { - * onSuccess: ({ refund }) => { - * console.log(refund.amount) - * } - * }) - * } - * - * // ... - * } - * - * export default Payment - * - * @customNamespace Hooks.Admin.Payments - * @category Mutations - */ -export const useAdminPaymentsRefundPayment = ( - /** - * The payment's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostPaymentRefundsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostPaymentRefundsReq) => - client.admin.payments.refundPayment(id, payload), - buildOptions( - queryClient, - [adminPaymentQueryKeys.detail(id), adminPaymentQueryKeys.lists()], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/payments/queries.ts b/packages/medusa-react/src/hooks/admin/payments/queries.ts deleted file mode 100644 index fa9000128a..0000000000 --- a/packages/medusa-react/src/hooks/admin/payments/queries.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { AdminPaymentRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const PAYMENT_QUERY_KEY = `payment` as const - -export const adminPaymentQueryKeys = - queryKeysFactory(PAYMENT_QUERY_KEY) - -type AdminPaymentKey = typeof adminPaymentQueryKeys - -/** - * This hook retrieves a payment's details. - * - * @example - * import React from "react" - * import { useAdminPayment } from "medusa-react" - * - * type Props = { - * paymentId: string - * } - * - * const Payment = ({ paymentId }: Props) => { - * const { - * payment, - * isLoading, - * } = useAdminPayment(paymentId) - * - * return ( - *
- * {isLoading && Loading...} - * {payment && {payment.amount}} - * - *
- * ) - * } - * - * export default Payment - * - * @customNamespace Hooks.Admin.Payments - * @category Queries - */ -export const useAdminPayment = ( - /** - * The payment's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminPaymentQueryKeys.detail(id), - () => client.admin.payments.retrieve(id), - options - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/price-lists/index.ts b/packages/medusa-react/src/hooks/admin/price-lists/index.ts deleted file mode 100644 index e63f8da6d8..0000000000 --- a/packages/medusa-react/src/hooks/admin/price-lists/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Price List API Routes](https://docs.medusajs.com/api/admin#price-lists). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A price list are special prices applied to products based on a set of conditions, such as customer group. - * - * Related Guide: [How to manage price lists](https://docs.medusajs.com/modules/price-lists/admin/manage-price-lists). - * - * @customNamespace Hooks.Admin.Price Lists - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/price-lists/mutations.ts b/packages/medusa-react/src/hooks/admin/price-lists/mutations.ts deleted file mode 100644 index 5c735fb6ac..0000000000 --- a/packages/medusa-react/src/hooks/admin/price-lists/mutations.ts +++ /dev/null @@ -1,541 +0,0 @@ -import { - AdminDeletePriceListPricesPricesReq, - AdminDeletePriceListsPriceListProductsPricesBatchReq, - AdminPostPriceListPricesPricesReq, - AdminPostPriceListsPriceListPriceListReq, - AdminPostPriceListsPriceListReq, - AdminPriceListDeleteBatchRes, - AdminPriceListDeleteProductPricesRes, - AdminPriceListDeleteRes, - AdminPriceListDeleteVariantPricesRes, - AdminPriceListRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - UseMutationOptions, - useMutation, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminProductKeys } from "../products" -import { adminVariantKeys } from "../variants" -import { adminPriceListKeys } from "./queries" - -/** - * This hook creates a price list. - * - * @example - * import React from "react" - * import { - * PriceListStatus, - * PriceListType, - * } from "@medusajs/medusa" - * import { useAdminCreatePriceList } from "medusa-react" - * - * type CreateData = { - * name: string - * description: string - * type: PriceListType - * status: PriceListStatus - * prices: { - * amount: number - * variant_id: string - * currency_code: string - * max_quantity: number - * }[] - * } - * - * const CreatePriceList = () => { - * const createPriceList = useAdminCreatePriceList() - * // ... - * - * const handleCreate = ( - * data: CreateData - * ) => { - * createPriceList.mutate(data, { - * onSuccess: ({ price_list }) => { - * console.log(price_list.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreatePriceList - * - * @customNamespace Hooks.Admin.Price Lists - * @category Mutations - */ -export const useAdminCreatePriceList = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostPriceListsPriceListReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostPriceListsPriceListReq) => - client.admin.priceLists.create(payload), - buildOptions(queryClient, [adminPriceListKeys.lists()], options) - ) -} - -/** - * This hook updates a price list's details. - * - * @example - * import React from "react" - * import { useAdminUpdatePriceList } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceList = ({ - * priceListId - * }: Props) => { - * const updatePriceList = useAdminUpdatePriceList(priceListId) - * // ... - * - * const handleUpdate = ( - * endsAt: Date - * ) => { - * updatePriceList.mutate({ - * ends_at: endsAt, - * }, { - * onSuccess: ({ price_list }) => { - * console.log(price_list.ends_at) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceList - * - * @customNamespace Hooks.Admin.Price Lists - * @category Mutations - */ -export const useAdminUpdatePriceList = ( - /** - * The price list's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostPriceListsPriceListPriceListReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostPriceListsPriceListPriceListReq) => - client.admin.priceLists.update(id, payload), - buildOptions( - queryClient, - [ - adminPriceListKeys.detail(id), - adminPriceListKeys.lists(), - adminPriceListKeys.detailProducts(id), - ], - options - ) - ) -} - -/** - * This hook deletes a price list and its associated prices. - * - * @example - * import React from "react" - * import { useAdminDeletePriceList } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceList = ({ - * priceListId - * }: Props) => { - * const deletePriceList = useAdminDeletePriceList(priceListId) - * // ... - * - * const handleDelete = () => { - * deletePriceList.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceList - * - * @customNamespace Hooks.Admin.Price Lists - * @category Mutations - */ -export const useAdminDeletePriceList = ( - /** - * The price list's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.priceLists.delete(id), - buildOptions( - queryClient, - [adminPriceListKeys.detail(id), adminPriceListKeys.lists()], - options - ) - ) -} - -/** - * This hook adds or updates a list of prices in a price list. - * - * @example - * import React from "react" - * import { useAdminCreatePriceListPrices } from "medusa-react" - * - * type PriceData = { - * amount: number - * variant_id: string - * currency_code: string - * } - * - * type Props = { - * priceListId: string - * } - * - * const PriceList = ({ - * priceListId - * }: Props) => { - * const addPrices = useAdminCreatePriceListPrices(priceListId) - * // ... - * - * const handleAddPrices = (prices: PriceData[]) => { - * addPrices.mutate({ - * prices - * }, { - * onSuccess: ({ price_list }) => { - * console.log(price_list.prices) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceList - * - * @customNamespace Hooks.Admin.Price Lists - * @category Mutations - */ -export const useAdminCreatePriceListPrices = ( - /** - * The price list's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostPriceListPricesPricesReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostPriceListPricesPricesReq) => - client.admin.priceLists.addPrices(id, payload), - buildOptions( - queryClient, - [ - adminPriceListKeys.detail(id), - adminPriceListKeys.lists(), - adminPriceListKeys.detailProducts(id), - ], - options - ) - ) -} - -/** - * This hook deletes a list of prices in a price list. - * - * @example - * import React from "react" - * import { useAdminDeletePriceListPrices } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceList = ({ - * priceListId - * }: Props) => { - * const deletePrices = useAdminDeletePriceListPrices(priceListId) - * // ... - * - * const handleDeletePrices = (priceIds: string[]) => { - * deletePrices.mutate({ - * price_ids: priceIds - * }, { - * onSuccess: ({ ids, deleted, object }) => { - * console.log(ids) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceList - * - * @customNamespace Hooks.Admin.Price Lists - * @category Mutations - */ -export const useAdminDeletePriceListPrices = ( - /** - * The price list's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminDeletePriceListPricesPricesReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminDeletePriceListPricesPricesReq) => - client.admin.priceLists.deletePrices(id, payload), - buildOptions( - queryClient, - [ - adminPriceListKeys.detail(id), - adminPriceListKeys.lists(), - adminPriceListKeys.detailProducts(id), - ], - options - ) - ) -} - -/** - * This hook deletes all the prices associated with multiple products in a price list. - * - * @example - * import React from "react" - * import { useAdminDeletePriceListProductsPrices } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceList = ({ - * priceListId - * }: Props) => { - * const deleteProductsPrices = useAdminDeletePriceListProductsPrices( - * priceListId - * ) - * // ... - * - * const handleDeleteProductsPrices = (productIds: string[]) => { - * deleteProductsPrices.mutate({ - * product_ids: productIds - * }, { - * onSuccess: ({ ids, deleted, object }) => { - * console.log(ids) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceList - * - * @customNamespace Hooks.Admin.Price Lists - * @category Mutations - */ -export const useAdminDeletePriceListProductsPrices = ( - /** - * The price list's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminDeletePriceListsPriceListProductsPricesBatchReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminDeletePriceListsPriceListProductsPricesBatchReq) => - client.admin.priceLists.deleteProductsPrices(id, payload), - buildOptions( - queryClient, - [adminPriceListKeys.detail(id), adminPriceListKeys.lists()], - options - ) - ) -} - -/** - * This hook deletes all the prices related to a specific product in a price list. - * - * @example - * import React from "react" - * import { - * useAdminDeletePriceListProductPrices - * } from "medusa-react" - * - * type Props = { - * priceListId: string - * productId: string - * } - * - * const PriceListProduct = ({ - * priceListId, - * productId - * }: Props) => { - * const deleteProductPrices = useAdminDeletePriceListProductPrices( - * priceListId, - * productId - * ) - * // ... - * - * const handleDeleteProductPrices = () => { - * deleteProductPrices.mutate(void 0, { - * onSuccess: ({ ids, deleted, object }) => { - * console.log(ids) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceListProduct - * - * @customNamespace Hooks.Admin.Price Lists - * @category Mutations - */ -export const useAdminDeletePriceListProductPrices = ( - /** - * The price list's ID. - */ - id: string, - /** - * The product's ID. - */ - productId: string, - options?: UseMutationOptions< - Response, - Error - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.priceLists.deleteProductPrices(id, productId), - buildOptions( - queryClient, - [ - adminPriceListKeys.detail(id), - adminPriceListKeys.lists(), - adminProductKeys.detail(productId), - ], - options - ) - ) -} - -/** - * This hook deletes all the prices related to a specific product variant in a price list. - * - * @example - * import React from "react" - * import { - * useAdminDeletePriceListVariantPrices - * } from "medusa-react" - * - * type Props = { - * priceListId: string - * variantId: string - * } - * - * const PriceListVariant = ({ - * priceListId, - * variantId - * }: Props) => { - * const deleteVariantPrices = useAdminDeletePriceListVariantPrices( - * priceListId, - * variantId - * ) - * // ... - * - * const handleDeleteVariantPrices = () => { - * deleteVariantPrices.mutate(void 0, { - * onSuccess: ({ ids, deleted, object }) => { - * console.log(ids) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceListVariant - * - * @customNamespace Hooks.Admin.Price Lists - * @category Mutations - */ -export const useAdminDeletePriceListVariantPrices = ( - /** - * The price list's ID. - */ - id: string, - /** - * The product variant's ID. - */ - variantId: string, - options?: UseMutationOptions< - Response, - Error - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.priceLists.deleteVariantPrices(id, variantId), - buildOptions( - queryClient, - [ - adminPriceListKeys.detail(id), - adminPriceListKeys.lists(), - adminVariantKeys.detail(variantId), - ], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/price-lists/queries.ts b/packages/medusa-react/src/hooks/admin/price-lists/queries.ts deleted file mode 100644 index a3bf055905..0000000000 --- a/packages/medusa-react/src/hooks/admin/price-lists/queries.ts +++ /dev/null @@ -1,361 +0,0 @@ -import { - AdminGetPriceListPaginationParams, - AdminGetPriceListsPriceListProductsParams, - AdminPriceListRes, - AdminPriceListsListRes, - AdminProductsListRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_PRICE_LISTS_QUERY_KEY = `admin_price_lists` as const - -export const adminPriceListKeys = { - ...queryKeysFactory(ADMIN_PRICE_LISTS_QUERY_KEY), - detailProducts(id: string, query?: any) { - return [ - ...this.detail(id), - "products" as const, - { ...(query || {}) }, - ] as const - }, -} - -type PriceListQueryKeys = typeof adminPriceListKeys - -/** - * This hook retrieves a list of price lists. The price lists can be filtered by fields such as `q` or `status` passed - * in the `query` parameter. The price lists can also be sorted or paginated. - * - * @example - * To list price lists: - * - * ```tsx - * import React from "react" - * import { useAdminPriceLists } from "medusa-react" - * - * const PriceLists = () => { - * const { price_lists, isLoading } = useAdminPriceLists() - * - * return ( - *
- * {isLoading && Loading...} - * {price_lists && !price_lists.length && ( - * No Price Lists - * )} - * {price_lists && price_lists.length > 0 && ( - *
    - * {price_lists.map((price_list) => ( - *
  • {price_list.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default PriceLists - * ``` - * - * To specify relations that should be retrieved within the price lists: - * - * ```tsx - * import React from "react" - * import { useAdminPriceLists } from "medusa-react" - * - * const PriceLists = () => { - * const { price_lists, isLoading } = useAdminPriceLists({ - * expand: "prices" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {price_lists && !price_lists.length && ( - * No Price Lists - * )} - * {price_lists && price_lists.length > 0 && ( - *
    - * {price_lists.map((price_list) => ( - *
  • {price_list.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default PriceLists - * ``` - * - * By default, only the first `10` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminPriceLists } from "medusa-react" - * - * const PriceLists = () => { - * const { - * price_lists, - * limit, - * offset, - * isLoading - * } = useAdminPriceLists({ - * expand: "prices", - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {price_lists && !price_lists.length && ( - * No Price Lists - * )} - * {price_lists && price_lists.length > 0 && ( - *
    - * {price_lists.map((price_list) => ( - *
  • {price_list.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default PriceLists - * ``` - * - * @customNamespace Hooks.Admin.Price Lists - * @category Queries - */ -export const useAdminPriceLists = ( - /** - * Filters and pagination configurations to apply on the retrieved price lists. - */ - query?: AdminGetPriceListPaginationParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminPriceListKeys.list(query), - () => client.admin.priceLists.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a price list's products. The products can be filtered by fields such as `q` or `status` - * passed in the `query` parameter. The products can also be sorted or paginated. - * - * @example - * To list products in a price list: - * - * ```tsx - * import React from "react" - * import { useAdminPriceListProducts } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceListProducts = ({ - * priceListId - * }: Props) => { - * const { products, isLoading } = useAdminPriceListProducts( - * priceListId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {products && !products.length && ( - * No Price Lists - * )} - * {products && products.length > 0 && ( - *
    - * {products.map((product) => ( - *
  • {product.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default PriceListProducts - * ``` - * - * To specify relations that should be retrieved within the products: - * - * ```tsx - * import React from "react" - * import { useAdminPriceListProducts } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceListProducts = ({ - * priceListId - * }: Props) => { - * const { products, isLoading } = useAdminPriceListProducts( - * priceListId, - * { - * expand: "variants" - * } - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {products && !products.length && ( - * No Price Lists - * )} - * {products && products.length > 0 && ( - *
    - * {products.map((product) => ( - *
  • {product.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default PriceListProducts - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminPriceListProducts } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceListProducts = ({ - * priceListId - * }: Props) => { - * const { - * products, - * limit, - * offset, - * isLoading - * } = useAdminPriceListProducts( - * priceListId, - * { - * expand: "variants", - * limit: 20, - * offset: 0 - * } - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {products && !products.length && ( - * No Price Lists - * )} - * {products && products.length > 0 && ( - *
    - * {products.map((product) => ( - *
  • {product.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default PriceListProducts - * ``` - * - * @customNamespace Hooks.Admin.Price Lists - * @category Queries - */ -export const useAdminPriceListProducts = ( - /** - * The ID of the associated price list. - */ - id: string, - /** - * Filters and pagination configurations applied on the retrieved products. - */ - query?: AdminGetPriceListsPriceListProductsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminPriceListKeys.detailProducts(id, query), - () => client.admin.priceLists.listProducts(id, query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a price list's details. - * - * @example - * import React from "react" - * import { useAdminPriceList } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceList = ({ - * priceListId - * }: Props) => { - * const { - * price_list, - * isLoading, - * } = useAdminPriceList(priceListId) - * - * return ( - *
- * {isLoading && Loading...} - * {price_list && {price_list.name}} - *
- * ) - * } - * - * export default PriceList - * - * @customNamespace Hooks.Admin.Price Lists - * @category Queries - */ -export const useAdminPriceList = ( - /** - * The price list's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminPriceListKeys.detail(id), - () => client.admin.priceLists.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/product-categories/index.ts b/packages/medusa-react/src/hooks/admin/product-categories/index.ts deleted file mode 100644 index d0323b3478..0000000000 --- a/packages/medusa-react/src/hooks/admin/product-categories/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Product Category API Routes](https://docs.medusajs.com/api/admin#product-categories). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Products can be categoriezed into categories. A product can be added into more than one category. - * - * Related Guide: [How to manage product categories](https://docs.medusajs.com/modules/products/admin/manage-categories). - * - * @featureFlag product_categories - * - * @customNamespace Hooks.Admin.Product Categories - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/product-categories/mutations.ts b/packages/medusa-react/src/hooks/admin/product-categories/mutations.ts deleted file mode 100644 index ae328ce9c9..0000000000 --- a/packages/medusa-react/src/hooks/admin/product-categories/mutations.ts +++ /dev/null @@ -1,345 +0,0 @@ -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { Response } from "@medusajs/medusa-js" -import { - AdminDeleteProductCategoriesCategoryProductsBatchReq, - AdminPostProductCategoriesCategoryProductsBatchReq, - AdminPostProductCategoriesCategoryReq, - AdminPostProductCategoriesReq, - AdminProductCategoriesCategoryDeleteRes, - AdminProductCategoriesCategoryRes, -} from "@medusajs/medusa" - -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminProductCategoryKeys } from "./queries" -import { adminProductKeys } from "../products" - -/** - * This hook creates a product category. - * - * @example - * import React from "react" - * import { useAdminCreateProductCategory } from "medusa-react" - * - * const CreateCategory = () => { - * const createCategory = useAdminCreateProductCategory() - * // ... - * - * const handleCreate = ( - * name: string - * ) => { - * createCategory.mutate({ - * name, - * }, { - * onSuccess: ({ product_category }) => { - * console.log(product_category.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateCategory - * - * @customNamespace Hooks.Admin.Product Categories - * @category Mutations - */ -export const useAdminCreateProductCategory = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostProductCategoriesReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostProductCategoriesReq) => - client.admin.productCategories.create(payload), - buildOptions( - queryClient, - [adminProductCategoryKeys.list(), adminProductKeys.details()], - options - ) - ) -} - -/** - * This hook updates a product category. - * - * @example - * import React from "react" - * import { useAdminUpdateProductCategory } from "medusa-react" - * - * type Props = { - * productCategoryId: string - * } - * - * const Category = ({ - * productCategoryId - * }: Props) => { - * const updateCategory = useAdminUpdateProductCategory( - * productCategoryId - * ) - * // ... - * - * const handleUpdate = ( - * name: string - * ) => { - * updateCategory.mutate({ - * name, - * }, { - * onSuccess: ({ product_category }) => { - * console.log(product_category.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Category - * - * @customNamespace Hooks.Admin.Product Categories - * @category Mutations - */ -export const useAdminUpdateProductCategory = ( - /** - * The product category's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostProductCategoriesCategoryReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostProductCategoriesCategoryReq) => - client.admin.productCategories.update(id, payload), - buildOptions( - queryClient, - [ - adminProductCategoryKeys.lists(), - adminProductCategoryKeys.detail(id), - adminProductKeys.details(), - ], - options - ) - ) -} - -/** - * This hook deletes a product category. This does not delete associated products. - * - * @example - * import React from "react" - * import { useAdminDeleteProductCategory } from "medusa-react" - * - * type Props = { - * productCategoryId: string - * } - * - * const Category = ({ - * productCategoryId - * }: Props) => { - * const deleteCategory = useAdminDeleteProductCategory( - * productCategoryId - * ) - * // ... - * - * const handleDelete = () => { - * deleteCategory.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Category - * - * @customNamespace Hooks.Admin.Product Categories - * @category Mutations - */ -export const useAdminDeleteProductCategory = ( - /** - * The product category's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - void - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.productCategories.delete(id), - buildOptions( - queryClient, - [ - adminProductCategoryKeys.lists(), - adminProductCategoryKeys.detail(id), - adminProductKeys.all - ], - options - ) - ) -} - -/** - * This hook adds a list of products to a product category. - * - * @example - * import React from "react" - * import { useAdminAddProductsToCategory } from "medusa-react" - * - * type ProductsData = { - * id: string - * } - * - * type Props = { - * productCategoryId: string - * } - * - * const Category = ({ - * productCategoryId - * }: Props) => { - * const addProducts = useAdminAddProductsToCategory( - * productCategoryId - * ) - * // ... - * - * const handleAddProducts = ( - * productIds: ProductsData[] - * ) => { - * addProducts.mutate({ - * product_ids: productIds - * }, { - * onSuccess: ({ product_category }) => { - * console.log(product_category.products) - * } - * }) - * } - * - * // ... - * } - * - * export default Category - * - * @customNamespace Hooks.Admin.Product Categories - * @category Mutations - */ -export const useAdminAddProductsToCategory = ( - /** - * The product category's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostProductCategoriesCategoryProductsBatchReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostProductCategoriesCategoryProductsBatchReq) => { - return client.admin.productCategories.addProducts(id, payload) - }, - buildOptions( - queryClient, - [ - adminProductCategoryKeys.lists(), - adminProductCategoryKeys.detail(id), - adminProductKeys.list({ product_category_id: [id] }), - ], - options - ) - ) -} - -/** - * This hook removes a list of products from a product category. - * - * @example - * import React from "react" - * import { useAdminDeleteProductsFromCategory } from "medusa-react" - * - * type ProductsData = { - * id: string - * } - * - * type Props = { - * productCategoryId: string - * } - * - * const Category = ({ - * productCategoryId - * }: Props) => { - * const deleteProducts = useAdminDeleteProductsFromCategory( - * productCategoryId - * ) - * // ... - * - * const handleDeleteProducts = ( - * productIds: ProductsData[] - * ) => { - * deleteProducts.mutate({ - * product_ids: productIds - * }, { - * onSuccess: ({ product_category }) => { - * console.log(product_category.products) - * } - * }) - * } - * - * // ... - * } - * - * export default Category - * - * @customNamespace Hooks.Admin.Product Categories - * @category Mutations - */ -export const useAdminDeleteProductsFromCategory = ( - /** - * The product category's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminDeleteProductCategoriesCategoryProductsBatchReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminDeleteProductCategoriesCategoryProductsBatchReq) => { - return client.admin.productCategories.removeProducts(id, payload) - }, - buildOptions( - queryClient, - [ - adminProductCategoryKeys.lists(), - adminProductCategoryKeys.detail(id), - adminProductKeys.list({ product_category_id: [id] }), - ], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/product-categories/queries.ts b/packages/medusa-react/src/hooks/admin/product-categories/queries.ts deleted file mode 100644 index 1e08f456c2..0000000000 --- a/packages/medusa-react/src/hooks/admin/product-categories/queries.ts +++ /dev/null @@ -1,253 +0,0 @@ -import { - AdminGetProductCategoriesParams, - AdminProductCategoriesListRes, - AdminGetProductCategoryParams, - AdminProductCategoriesCategoryRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" - -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const ADMIN_PRODUCT_CATEGORIES_QUERY_KEY = `product_categories` as const -export const adminProductCategoryKeys = queryKeysFactory( - ADMIN_PRODUCT_CATEGORIES_QUERY_KEY -) -type ProductCategoryQueryKeys = typeof adminProductCategoryKeys - -/** - * This hook - * - * @example - * To list product categories: - * - * ```tsx - * import React from "react" - * import { useAdminProductCategories } from "medusa-react" - * - * function Categories() { - * const { - * product_categories, - * isLoading - * } = useAdminProductCategories() - * - * return ( - *
- * {isLoading && Loading...} - * {product_categories && !product_categories.length && ( - * No Categories - * )} - * {product_categories && product_categories.length > 0 && ( - *
    - * {product_categories.map( - * (category) => ( - *
  • {category.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Categories - * ``` - * - * To specify relations that should be retrieved within the product category: - * - * ```tsx - * import React from "react" - * import { useAdminProductCategories } from "medusa-react" - * - * function Categories() { - * const { - * product_categories, - * isLoading - * } = useAdminProductCategories({ - * expand: "category_children" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {product_categories && !product_categories.length && ( - * No Categories - * )} - * {product_categories && product_categories.length > 0 && ( - *
    - * {product_categories.map( - * (category) => ( - *
  • {category.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Categories - * ``` - * - * By default, only the first `100` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminProductCategories } from "medusa-react" - * - * function Categories() { - * const { - * product_categories, - * limit, - * offset, - * isLoading - * } = useAdminProductCategories({ - * expand: "category_children", - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {product_categories && !product_categories.length && ( - * No Categories - * )} - * {product_categories && product_categories.length > 0 && ( - *
    - * {product_categories.map( - * (category) => ( - *
  • {category.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Categories - * ``` - * - * @customNamespace Hooks.Admin.Product Categories - * @category Queries - */ -export const useAdminProductCategories = ( - /** - * Filters and pagination configurations to apply on the retrieved product categories. - */ - query?: AdminGetProductCategoriesParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminProductCategoryKeys.list(query), - () => client.admin.productCategories.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a product category's details. - * - * @example - * A simple example that retrieves an order by its ID: - * - * ```tsx - * import React from "react" - * import { useAdminProductCategory } from "medusa-react" - * - * type Props = { - * productCategoryId: string - * } - * - * const Category = ({ - * productCategoryId - * }: Props) => { - * const { - * product_category, - * isLoading, - * } = useAdminProductCategory(productCategoryId) - * - * return ( - *
- * {isLoading && Loading...} - * {product_category && ( - * {product_category.name} - * )} - * - *
- * ) - * } - * - * export default Category - * ``` - * - * To specify relations that should be retrieved: - * - * ```tsx - * import React from "react" - * import { useAdminProductCategory } from "medusa-react" - * - * type Props = { - * productCategoryId: string - * } - * - * const Category = ({ - * productCategoryId - * }: Props) => { - * const { - * product_category, - * isLoading, - * } = useAdminProductCategory(productCategoryId, { - * expand: "category_children" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {product_category && ( - * {product_category.name} - * )} - * - *
- * ) - * } - * - * export default Category - * ``` - * - * @customNamespace Hooks.Admin.Product Categories - * @category Queries - */ -export const useAdminProductCategory = ( - /** - * The product category's ID. - */ - id: string, - /** - * Configurations to apply on the retrieved product category. - */ - query?: AdminGetProductCategoryParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminProductCategoryKeys.detail(id), - () => client.admin.productCategories.retrieve(id, query), - options - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/product-tags/index.ts b/packages/medusa-react/src/hooks/admin/product-tags/index.ts deleted file mode 100644 index 5b817c8445..0000000000 --- a/packages/medusa-react/src/hooks/admin/product-tags/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Product Tag API Routes](https://docs.medusajs.com/api/admin#product-tags). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Product tags are string values created when you create or update a product with a new tag. - * Products can have more than one tag, and products can share tags. This allows admins to associate products to similar tags that can be used to filter products. - * - * @customNamespace Hooks.Admin.Product Tags - */ - -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/admin/product-tags/queries.ts b/packages/medusa-react/src/hooks/admin/product-tags/queries.ts deleted file mode 100644 index 185a27cecb..0000000000 --- a/packages/medusa-react/src/hooks/admin/product-tags/queries.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { - AdminGetProductTagsParams, - AdminProductTagsListRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_PRODUCT_TAGS_QUERY_KEY = `admin_product_tags` as const - -export const adminProductTagKeys = queryKeysFactory( - ADMIN_PRODUCT_TAGS_QUERY_KEY -) - -type ProductQueryKeys = typeof adminProductTagKeys - -/** - * This hook retrieves a list of product tags. The product tags can be filtered by fields such as `q` or `value` passed - * in the `query` parameter. The product tags can also be sorted or paginated. - * - * @example - * To list product tags: - * - * ```tsx - * import React from "react" - * import { useAdminProductTags } from "medusa-react" - * - * function ProductTags() { - * const { - * product_tags, - * isLoading - * } = useAdminProductTags() - * - * return ( - *
- * {isLoading && Loading...} - * {product_tags && !product_tags.length && ( - * No Product Tags - * )} - * {product_tags && product_tags.length > 0 && ( - *
    - * {product_tags.map( - * (tag) => ( - *
  • {tag.value}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default ProductTags - * ``` - * - * By default, only the first `10` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminProductTags } from "medusa-react" - * - * function ProductTags() { - * const { - * product_tags, - * limit, - * offset, - * isLoading - * } = useAdminProductTags({ - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {product_tags && !product_tags.length && ( - * No Product Tags - * )} - * {product_tags && product_tags.length > 0 && ( - *
    - * {product_tags.map( - * (tag) => ( - *
  • {tag.value}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default ProductTags - * ``` - * - * @customNamespace Hooks.Admin.Product Tags - * @category Queries - */ -export const useAdminProductTags = ( - /** - * Filters and pagination configurations to apply on the retrieved product tags. - */ - query?: AdminGetProductTagsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminProductTagKeys.list(query), - () => client.admin.productTags.list(query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/product-types/index.ts b/packages/medusa-react/src/hooks/admin/product-types/index.ts deleted file mode 100644 index 7c2fc525c9..0000000000 --- a/packages/medusa-react/src/hooks/admin/product-types/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Product Type API Routes](https://docs.medusajs.com/api/admin#product-types). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Product types are string values created when you create or update a product with a new type. - * Products can have one type, and products can share types. This allows admins to associate products with a type that can be used to filter products. - * - * @customNamespace Hooks.Admin.Product Types - */ - -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/admin/product-types/queries.ts b/packages/medusa-react/src/hooks/admin/product-types/queries.ts deleted file mode 100644 index 8ed69b69e8..0000000000 --- a/packages/medusa-react/src/hooks/admin/product-types/queries.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { - AdminGetProductTypesParams, - AdminProductTypesListRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_PRODUCT_TYPES_QUERY_KEY = `admin_product_types` as const - -export const adminProductTypeKeys = queryKeysFactory( - ADMIN_PRODUCT_TYPES_QUERY_KEY -) - -type ProductTypesQueryKeys = typeof adminProductTypeKeys - -/** - * This hook retrieves a list of product types. The product types can be filtered by fields such as `q` or `value` passed in the `query` parameter. - * The product types can also be sorted or paginated. - * - * @example - * To list product types: - * - * ```tsx - * import React from "react" - * import { useAdminProductTypes } from "medusa-react" - * - * function ProductTypes() { - * const { - * product_types, - * isLoading - * } = useAdminProductTypes() - * - * return ( - *
- * {isLoading && Loading...} - * {product_types && !product_types.length && ( - * No Product Tags - * )} - * {product_types && product_types.length > 0 && ( - *
    - * {product_types.map( - * (type) => ( - *
  • {type.value}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default ProductTypes - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminProductTypes } from "medusa-react" - * - * function ProductTypes() { - * const { - * product_types, - * limit, - * offset, - * isLoading - * } = useAdminProductTypes({ - * limit: 10, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {product_types && !product_types.length && ( - * No Product Tags - * )} - * {product_types && product_types.length > 0 && ( - *
    - * {product_types.map( - * (type) => ( - *
  • {type.value}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default ProductTypes - * ``` - * - * @customNamespace Hooks.Admin.Product Types - * @category Queries - */ -export const useAdminProductTypes = ( - /** - * Filters and pagination configurations to apply on the retrieved product types. - */ - query?: AdminGetProductTypesParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminProductTypeKeys.list(query), - () => client.admin.productTypes.list(query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/products/index.ts b/packages/medusa-react/src/hooks/admin/products/index.ts deleted file mode 100644 index 3a526ea996..0000000000 --- a/packages/medusa-react/src/hooks/admin/products/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Product API Routes](https://docs.medusajs.com/api/admin#products). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Products are saleable items in a store. This also includes [saleable gift cards](https://docs.medusajs.com/modules/gift-cards/admin/manage-gift-cards#manage-gift-card-product) in a store. - * - * Related Guide: [How to manage products](https://docs.medusajs.com/modules/products/admin/manage-products). - * - * @customNamespace Hooks.Admin.Products - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/products/mutations.ts b/packages/medusa-react/src/hooks/admin/products/mutations.ts deleted file mode 100644 index 4da1796cb1..0000000000 --- a/packages/medusa-react/src/hooks/admin/products/mutations.ts +++ /dev/null @@ -1,610 +0,0 @@ -import { - AdminPostProductsProductOptionsOption, - AdminPostProductsProductOptionsReq, - AdminPostProductsProductReq, - AdminPostProductsProductVariantsReq, - AdminPostProductsProductVariantsVariantReq, - AdminPostProductsReq, - AdminProductsDeleteOptionRes, - AdminProductsDeleteRes, - AdminProductsDeleteVariantRes, - AdminProductsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminProductKeys } from "./queries" - -/** - * This hook creates a new Product. This hook can also be used to create a gift card if the `is_giftcard` field is set to `true`. - * - * @example - * import React from "react" - * import { useAdminCreateProduct } from "medusa-react" - * - * type CreateProductData = { - * title: string - * is_giftcard: boolean - * discountable: boolean - * options: { - * title: string - * }[] - * variants: { - * title: string - * prices: { - * amount: number - * currency_code :string - * }[] - * options: { - * value: string - * }[] - * }[], - * collection_id: string - * categories: { - * id: string - * }[] - * type: { - * value: string - * } - * tags: { - * value: string - * }[] - * } - * - * const CreateProduct = () => { - * const createProduct = useAdminCreateProduct() - * // ... - * - * const handleCreate = (productData: CreateProductData) => { - * createProduct.mutate(productData, { - * onSuccess: ({ product }) => { - * console.log(product.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateProduct - * - * @customNamespace Hooks.Admin.Products - * @category Mutations - */ -export const useAdminCreateProduct = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostProductsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostProductsReq) => client.admin.products.create(payload), - buildOptions(queryClient, adminProductKeys.lists(), options) - ) -} - -/** - * This hook updates a Product's details. - * - * @example - * import React from "react" - * import { useAdminUpdateProduct } from "medusa-react" - * - * type Props = { - * productId: string - * } - * - * const Product = ({ productId }: Props) => { - * const updateProduct = useAdminUpdateProduct( - * productId - * ) - * // ... - * - * const handleUpdate = ( - * title: string - * ) => { - * updateProduct.mutate({ - * title, - * }, { - * onSuccess: ({ product }) => { - * console.log(product.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Product - * - * @customNamespace Hooks.Admin.Products - * @category Mutations - */ -export const useAdminUpdateProduct = ( - /** - * The product's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostProductsProductReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostProductsProductReq) => - client.admin.products.update(id, payload), - buildOptions( - queryClient, - [adminProductKeys.lists(), adminProductKeys.detail(id)], - options - ) - ) -} - -/** - * This hook deletes a product and its associated product variants and options. - * - * @example - * import React from "react" - * import { useAdminDeleteProduct } from "medusa-react" - * - * type Props = { - * productId: string - * } - * - * const Product = ({ productId }: Props) => { - * const deleteProduct = useAdminDeleteProduct( - * productId - * ) - * // ... - * - * const handleDelete = () => { - * deleteProduct.mutate(void 0, { - * onSuccess: ({ id, object, deleted}) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Product - * - * @customNamespace Hooks.Admin.Products - * @category Mutations - */ -export const useAdminDeleteProduct = ( - /** - * The product's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.products.delete(id), - buildOptions( - queryClient, - [adminProductKeys.lists(), adminProductKeys.detail(id)], - options - ) - ) -} - -/** - * This hook creates a product variant associated with a product. Each product variant must have a unique combination of product option values. - * - * @example - * import React from "react" - * import { useAdminCreateVariant } from "medusa-react" - * - * type CreateVariantData = { - * title: string - * prices: { - * amount: number - * currency_code: string - * }[] - * options: { - * option_id: string - * value: string - * }[] - * } - * - * type Props = { - * productId: string - * } - * - * const CreateProductVariant = ({ productId }: Props) => { - * const createVariant = useAdminCreateVariant( - * productId - * ) - * // ... - * - * const handleCreate = ( - * variantData: CreateVariantData - * ) => { - * createVariant.mutate(variantData, { - * onSuccess: ({ product }) => { - * console.log(product.variants) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateProductVariant - * - * @customNamespace Hooks.Admin.Products - * @category Mutations - */ -export const useAdminCreateVariant = ( - /** - * The product's ID. - */ - productId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostProductsProductVariantsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostProductsProductVariantsReq) => - client.admin.products.createVariant(productId, payload), - buildOptions( - queryClient, - [adminProductKeys.lists(), adminProductKeys.detail(productId)], - options - ) - ) -} - -export type AdminUpdateVariantReq = AdminPostProductsProductVariantsVariantReq & { - /** - * The product variant's ID. - */ - variant_id: string -} - -/** - * This hook updates a product variant's details. - * - * @example - * import React from "react" - * import { useAdminUpdateVariant } from "medusa-react" - * - * type Props = { - * productId: string - * variantId: string - * } - * - * const ProductVariant = ({ - * productId, - * variantId - * }: Props) => { - * const updateVariant = useAdminUpdateVariant( - * productId - * ) - * // ... - * - * const handleUpdate = (title: string) => { - * updateVariant.mutate({ - * variant_id: variantId, - * title, - * }, { - * onSuccess: ({ product }) => { - * console.log(product.variants) - * } - * }) - * } - * - * // ... - * } - * - * export default ProductVariant - * - * @customNamespace Hooks.Admin.Products - * @category Mutations - */ -export const useAdminUpdateVariant = ( - /** - * The product's ID. - */ - productId: string, - options?: UseMutationOptions< - Response, - Error, - AdminUpdateVariantReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - ({ - variant_id, - ...payload - }: AdminUpdateVariantReq) => - client.admin.products.updateVariant(productId, variant_id, payload), - buildOptions( - queryClient, - [adminProductKeys.lists(), adminProductKeys.detail(productId)], - options - ) - ) -} - -/** - * This hook deletes a product variant. - * - * @typeParamDefinition string - The ID of the product variant to delete. - * - * @example - * import React from "react" - * import { useAdminDeleteVariant } from "medusa-react" - * - * type Props = { - * productId: string - * variantId: string - * } - * - * const ProductVariant = ({ - * productId, - * variantId - * }: Props) => { - * const deleteVariant = useAdminDeleteVariant( - * productId - * ) - * // ... - * - * const handleDelete = () => { - * deleteVariant.mutate(variantId, { - * onSuccess: ({ variant_id, object, deleted, product }) => { - * console.log(product.variants) - * } - * }) - * } - * - * // ... - * } - * - * export default ProductVariant - * - * @customNamespace Hooks.Admin.Products - * @category Mutations - */ -export const useAdminDeleteVariant = ( - /** - * The product's ID. - */ - productId: string, - options?: UseMutationOptions< - Response, - Error, - string - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (variantId: string) => - client.admin.products.deleteVariant(productId, variantId), - buildOptions( - queryClient, - [adminProductKeys.lists(), adminProductKeys.detail(productId)], - options - ) - ) -} - -/** - * This hook adds a product option to a product. - * - * @example - * import React from "react" - * import { useAdminCreateProductOption } from "medusa-react" - * - * type Props = { - * productId: string - * } - * - * const CreateProductOption = ({ productId }: Props) => { - * const createOption = useAdminCreateProductOption( - * productId - * ) - * // ... - * - * const handleCreate = ( - * title: string - * ) => { - * createOption.mutate({ - * title - * }, { - * onSuccess: ({ product }) => { - * console.log(product.options) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateProductOption - * - * @customNamespace Hooks.Admin.Products - * @category Mutations - */ -export const useAdminCreateProductOption = ( - /** - * The product's ID. - */ - productId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostProductsProductOptionsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostProductsProductOptionsReq) => - client.admin.products.addOption(productId, payload), - buildOptions(queryClient, adminProductKeys.detail(productId), options) - ) -} - -export type AdminUpdateProductOptionReq = AdminPostProductsProductOptionsOption & { - /** - * The ID of the product option to update. - */ - option_id: string -} - -/** - * This hook updates a product option's details. - * - * @example - * import React from "react" - * import { useAdminUpdateProductOption } from "medusa-react" - * - * type Props = { - * productId: string - * optionId: string - * } - * - * const ProductOption = ({ - * productId, - * optionId - * }: Props) => { - * const updateOption = useAdminUpdateProductOption( - * productId - * ) - * // ... - * - * const handleUpdate = ( - * title: string - * ) => { - * updateOption.mutate({ - * option_id: optionId, - * title, - * }, { - * onSuccess: ({ product }) => { - * console.log(product.options) - * } - * }) - * } - * - * // ... - * } - * - * export default ProductOption - * - * @customNamespace Hooks.Admin.Products - * @category Mutations - */ -export const useAdminUpdateProductOption = ( - /** - * The product's ID. - */ - productId: string, - options?: UseMutationOptions< - Response, - Error, - AdminUpdateProductOptionReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - ({ - option_id, - ...payload - }: AdminUpdateProductOptionReq) => - client.admin.products.updateOption(productId, option_id, payload), - buildOptions(queryClient, adminProductKeys.detail(productId), options) - ) -} - -/** - * This hook deletes a product option. If there are product variants that use this product option, - * they must be deleted before deleting the product option. - * - * @typeParamDefinition string - The ID of the product option to delete. - * - * @example - * import React from "react" - * import { useAdminDeleteProductOption } from "medusa-react" - * - * type Props = { - * productId: string - * optionId: string - * } - * - * const ProductOption = ({ - * productId, - * optionId - * }: Props) => { - * const deleteOption = useAdminDeleteProductOption( - * productId - * ) - * // ... - * - * const handleDelete = () => { - * deleteOption.mutate(optionId, { - * onSuccess: ({ option_id, object, deleted, product }) => { - * console.log(product.options) - * } - * }) - * } - * - * // ... - * } - * - * export default ProductOption - * - * @customNamespace Hooks.Admin.Products - * @category Mutations - */ -export const useAdminDeleteProductOption = ( - /** - * The product's ID. - */ - productId: string, - options?: UseMutationOptions< - Response, - Error, - string - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (optionId: string) => - client.admin.products.deleteOption(productId, optionId), - buildOptions(queryClient, adminProductKeys.detail(productId), options) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/products/queries.ts b/packages/medusa-react/src/hooks/admin/products/queries.ts deleted file mode 100644 index d4a62d1afb..0000000000 --- a/packages/medusa-react/src/hooks/admin/products/queries.ts +++ /dev/null @@ -1,274 +0,0 @@ -import { - AdminGetProductParams, - AdminGetProductsParams, - AdminGetProductsVariantsParams, - AdminProductsListRes, - AdminProductsListTagsRes, - AdminProductsListVariantsRes, - AdminProductsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_PRODUCTS_QUERY_KEY = `admin_products` as const - -export const adminProductKeys = { - ...queryKeysFactory(ADMIN_PRODUCTS_QUERY_KEY), - detailVariants(id: string, query?: any) { - return [ - ...this.detail(id), - "variants" as const, - { ...(query || {}) }, - ] as const - }, -} - -type ProductQueryKeys = typeof adminProductKeys - -/** - * This hook retrieves a list of products. The products can be filtered by fields such as `q` or `status` passed in - * the `query` parameter. The products can also be sorted or paginated. - * - * @example - * To list products: - * - * ```tsx - * import React from "react" - * import { useAdminProducts } from "medusa-react" - * - * const Products = () => { - * const { products, isLoading } = useAdminProducts() - * - * return ( - *
- * {isLoading && Loading...} - * {products && !products.length && No Products} - * {products && products.length > 0 && ( - *
    - * {products.map((product) => ( - *
  • {product.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Products - * ``` - * - * To specify relations that should be retrieved within the products: - * - * ```tsx - * import React from "react" - * import { useAdminProducts } from "medusa-react" - * - * const Products = () => { - * const { products, isLoading } = useAdminProducts({ - * expand: "images" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {products && !products.length && No Products} - * {products && products.length > 0 && ( - *
    - * {products.map((product) => ( - *
  • {product.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Products - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminProducts } from "medusa-react" - * - * const Products = () => { - * const { - * products, - * limit, - * offset, - * isLoading - * } = useAdminProducts({ - * expand: "images", - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {products && !products.length && No Products} - * {products && products.length > 0 && ( - *
    - * {products.map((product) => ( - *
  • {product.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Products - * ``` - * - * @customNamespace Hooks.Admin.Products - * @category Queries - */ -export const useAdminProducts = ( - /** - * Filters and pagination configurations to apply on the retrieved products. - */ - query?: AdminGetProductsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminProductKeys.list(query), - () => client.admin.products.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a product's details. - * - * @example - * import React from "react" - * import { useAdminProduct } from "medusa-react" - * - * type Props = { - * productId: string - * } - * - * const Product = ({ productId }: Props) => { - * const { - * product, - * isLoading, - * } = useAdminProduct(productId) - * - * return ( - *
- * {isLoading && Loading...} - * {product && {product.title}} - * - *
- * ) - * } - * - * export default Product - * - * @customNamespace Hooks.Admin.Products - * @category Queries - */ -export const useAdminProduct = ( - /** - * The product's ID. - */ - id: string, - /** - * Configurations to apply on the retrieved product. - */ - query?: AdminGetProductParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminProductKeys.detail(id), - () => client.admin.products.retrieve(id, query), - options - ) - return { ...data, ...rest } as const -} - -export const useAdminProductVariants = ( - /** - * The product's ID. - */ - id: string, - /** - * Configurations to apply on the retrieved product variants. - */ - query?: AdminGetProductsVariantsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminProductKeys.detailVariants(id, query), - () => client.admin.products.listVariants(id, query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a list of Product Tags with how many times each is used in products. - * - * @example - * import React from "react" - * import { useAdminProductTagUsage } from "medusa-react" - * - * const ProductTags = (productId: string) => { - * const { tags, isLoading } = useAdminProductTagUsage() - * - * return ( - *
- * {isLoading && Loading...} - * {tags && !tags.length && No Product Tags} - * {tags && tags.length > 0 && ( - *
    - * {tags.map((tag) => ( - *
  • {tag.value} - {tag.usage_count}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ProductTags - * - * @customNamespace Hooks.Admin.Products - * @category Queries - */ -export const useAdminProductTagUsage = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminProductKeys.detail("tags"), - () => client.admin.products.listTags(), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/publishable-api-keys/index.ts b/packages/medusa-react/src/hooks/admin/publishable-api-keys/index.ts deleted file mode 100644 index d893bbfb0f..0000000000 --- a/packages/medusa-react/src/hooks/admin/publishable-api-keys/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Publishable API Key API Routes](https://docs.medusajs.com/api/admin#publishable-api-keys). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Publishable API Keys can be used to scope Store API calls with an API key, determining what resources are retrieved when querying the API. - * For example, a publishable API key can be associated with one or more sales channels. - * - * When it is passed in the header of a request to the List Product store API Route, - * the sales channels are inferred from the key and only products associated with those sales channels are retrieved. - * - * Admins can manage publishable API keys and their associated resources. Currently, only Sales Channels are supported as a resource. - * - * Related Guide: [How to manage publishable API keys](https://docs.medusajs.com/development/publishable-api-keys/admin/manage-publishable-api-keys). - * - * @customNamespace Hooks.Admin.Publishable API Keys - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/publishable-api-keys/mutations.ts b/packages/medusa-react/src/hooks/admin/publishable-api-keys/mutations.ts deleted file mode 100644 index 1ae616a140..0000000000 --- a/packages/medusa-react/src/hooks/admin/publishable-api-keys/mutations.ts +++ /dev/null @@ -1,389 +0,0 @@ -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" - -import { - AdminDeletePublishableApiKeySalesChannelsBatchReq, - AdminPostPublishableApiKeySalesChannelsBatchReq, - AdminPostPublishableApiKeysPublishableApiKeyReq, - AdminPostPublishableApiKeysReq, - AdminPublishableApiKeyDeleteRes, - AdminPublishableApiKeysRes, -} from "@medusajs/medusa" - -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminPublishableApiKeysKeys } from "./queries" - -/** - * This hook creates a publishable API key. - * - * @example - * import React from "react" - * import { useAdminCreatePublishableApiKey } from "medusa-react" - * - * const CreatePublishableApiKey = () => { - * const createKey = useAdminCreatePublishableApiKey() - * // ... - * - * const handleCreate = (title: string) => { - * createKey.mutate({ - * title, - * }, { - * onSuccess: ({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreatePublishableApiKey - * - * @customNamespace Hooks.Admin.Publishable API Keys - * @category Mutations - */ -export const useAdminCreatePublishableApiKey = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostPublishableApiKeysReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostPublishableApiKeysReq) => - client.admin.publishableApiKeys.create(payload), - buildOptions(queryClient, [adminPublishableApiKeysKeys.lists()], options) - ) -} - -/** - * This hook updates a publishable API key's details. - * - * @example - * import React from "react" - * import { useAdminUpdatePublishableApiKey } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const PublishableApiKey = ({ - * publishableApiKeyId - * }: Props) => { - * const updateKey = useAdminUpdatePublishableApiKey( - * publishableApiKeyId - * ) - * // ... - * - * const handleUpdate = (title: string) => { - * updateKey.mutate({ - * title, - * }, { - * onSuccess: ({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * } - * }) - * } - * - * // ... - * } - * - * export default PublishableApiKey - * - * @customNamespace Hooks.Admin.Publishable API Keys - * @category Mutations - */ -export const useAdminUpdatePublishableApiKey = ( - /** - * The publishable API key's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostPublishableApiKeysPublishableApiKeyReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostPublishableApiKeysPublishableApiKeyReq) => - client.admin.publishableApiKeys.update(id, payload), - buildOptions( - queryClient, - [ - adminPublishableApiKeysKeys.lists(), - adminPublishableApiKeysKeys.detail(id), - adminPublishableApiKeysKeys.details(), - ], - options - ) - ) -} - -/** - * This hook deletes a publishable API key. Associated resources, such as sales channels, are not deleted. - * - * @example - * import React from "react" - * import { useAdminDeletePublishableApiKey } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const PublishableApiKey = ({ - * publishableApiKeyId - * }: Props) => { - * const deleteKey = useAdminDeletePublishableApiKey( - * publishableApiKeyId - * ) - * // ... - * - * const handleDelete = () => { - * deleteKey.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default PublishableApiKey - * - * @customNamespace Hooks.Admin.Publishable API Keys - * @category Mutations - */ -export const useAdminDeletePublishableApiKey = ( - /** - * The publishable API key's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - void - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.publishableApiKeys.delete(id), - buildOptions( - queryClient, - [ - adminPublishableApiKeysKeys.detail(id), - adminPublishableApiKeysKeys.lists(), - ], - options - ) - ) -} - -/** - * This hook revokes a publishable API key. Revoking the publishable API Key can't be undone, and the key can't be used in future requests. - * - * @example - * import React from "react" - * import { useAdminRevokePublishableApiKey } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const PublishableApiKey = ({ - * publishableApiKeyId - * }: Props) => { - * const revokeKey = useAdminRevokePublishableApiKey( - * publishableApiKeyId - * ) - * // ... - * - * const handleRevoke = () => { - * revokeKey.mutate(void 0, { - * onSuccess: ({ publishable_api_key }) => { - * console.log(publishable_api_key.revoked_at) - * } - * }) - * } - * - * // ... - * } - * - * export default PublishableApiKey - * - * @customNamespace Hooks.Admin.Publishable API Keys - * @category Mutations - */ -export const useAdminRevokePublishableApiKey = ( - /** - * The publishable API key's ID. - */ - id: string, - options?: UseMutationOptions, Error> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.publishableApiKeys.revoke(id), - buildOptions( - queryClient, - [ - adminPublishableApiKeysKeys.lists(), - adminPublishableApiKeysKeys.detail(id), - ], - options - ) - ) -} - -/** - * This hook adds a list of sales channels to a publishable API key. - * - * @example - * import React from "react" - * import { - * useAdminAddPublishableKeySalesChannelsBatch, - * } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const PublishableApiKey = ({ - * publishableApiKeyId - * }: Props) => { - * const addSalesChannels = - * useAdminAddPublishableKeySalesChannelsBatch( - * publishableApiKeyId - * ) - * // ... - * - * const handleAdd = (salesChannelId: string) => { - * addSalesChannels.mutate({ - * sales_channel_ids: [ - * { - * id: salesChannelId, - * }, - * ], - * }, { - * onSuccess: ({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * } - * }) - * } - * - * // ... - * } - * - * export default PublishableApiKey - * - * @customNamespace Hooks.Admin.Publishable API Keys - * @category Mutations - */ -export const useAdminAddPublishableKeySalesChannelsBatch = ( - /** - * The publishable API key's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostPublishableApiKeySalesChannelsBatchReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostPublishableApiKeySalesChannelsBatchReq) => - client.admin.publishableApiKeys.addSalesChannelsBatch(id, payload), - buildOptions( - queryClient, - [adminPublishableApiKeysKeys.detailSalesChannels(id)], - options - ) - ) -} - -/** - * This hook removes a list of sales channels from a publishable API key. This doesn't delete the sales channels and only - * removes the association between them and the publishable API key. - * - * @example - * import React from "react" - * import { - * useAdminRemovePublishableKeySalesChannelsBatch, - * } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const PublishableApiKey = ({ - * publishableApiKeyId - * }: Props) => { - * const deleteSalesChannels = - * useAdminRemovePublishableKeySalesChannelsBatch( - * publishableApiKeyId - * ) - * // ... - * - * const handleDelete = (salesChannelId: string) => { - * deleteSalesChannels.mutate({ - * sales_channel_ids: [ - * { - * id: salesChannelId, - * }, - * ], - * }, { - * onSuccess: ({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * } - * }) - * } - * - * // ... - * } - * - * export default PublishableApiKey - * - * @customNamespace Hooks.Admin.Publishable API Keys - * @category Mutations - */ -export const useAdminRemovePublishableKeySalesChannelsBatch = ( - /** - * The publishable API key's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminDeletePublishableApiKeySalesChannelsBatchReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminDeletePublishableApiKeySalesChannelsBatchReq) => - client.admin.publishableApiKeys.deleteSalesChannelsBatch(id, payload), - buildOptions( - queryClient, - [adminPublishableApiKeysKeys.detailSalesChannels(id)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/publishable-api-keys/queries.ts b/packages/medusa-react/src/hooks/admin/publishable-api-keys/queries.ts deleted file mode 100644 index 331a971780..0000000000 --- a/packages/medusa-react/src/hooks/admin/publishable-api-keys/queries.ts +++ /dev/null @@ -1,260 +0,0 @@ -import { - AdminPublishableApiKeysListRes, - AdminPublishableApiKeysListSalesChannelsRes, - AdminPublishableApiKeysRes, - GetPublishableApiKeySalesChannelsParams, - GetPublishableApiKeysParams, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" - -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const ADMIN_PUBLISHABLE_API_KEYS_QUERY_KEY = - `admin_publishable_api_keys` as const - -export const adminPublishableApiKeysKeys = { - ...queryKeysFactory(ADMIN_PUBLISHABLE_API_KEYS_QUERY_KEY), - detailSalesChannels(id: string, query?: any) { - return [ - ...this.detail(id), - "sales_channels" as const, - { ...(query || {}) }, - ] as const - }, -} - -type PublishableApiKeyQueryKeys = typeof adminPublishableApiKeysKeys - -/** - * This hook retrieves a publishable API key's details. - * - * @example - * import React from "react" - * import { - * useAdminPublishableApiKey, - * } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const PublishableApiKey = ({ - * publishableApiKeyId - * }: Props) => { - * const { publishable_api_key, isLoading } = - * useAdminPublishableApiKey( - * publishableApiKeyId - * ) - * - * - * return ( - *
- * {isLoading && Loading...} - * {publishable_api_key && {publishable_api_key.title}} - *
- * ) - * } - * - * export default PublishableApiKey - * - * @customNamespace Hooks.Admin.Publishable API Keys - * @category Queries - */ -export const useAdminPublishableApiKey = ( - /** - * The publishable API key's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminPublishableApiKeysKeys.detail(id), - () => client.admin.publishableApiKeys.retrieve(id), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a list of publishable API keys. The publishable API keys can be filtered by fields such as `q` passed in `query`. - * The publishable API keys can also be paginated. - * - * @example - * To list publishable API keys: - * - * ```tsx - * import React from "react" - * import { PublishableApiKey } from "@medusajs/medusa" - * import { useAdminPublishableApiKeys } from "medusa-react" - * - * const PublishableApiKeys = () => { - * const { publishable_api_keys, isLoading } = - * useAdminPublishableApiKeys() - * - * return ( - *
- * {isLoading && Loading...} - * {publishable_api_keys && !publishable_api_keys.length && ( - * No Publishable API Keys - * )} - * {publishable_api_keys && - * publishable_api_keys.length > 0 && ( - *
    - * {publishable_api_keys.map( - * (publishableApiKey: PublishableApiKey) => ( - *
  • - * {publishableApiKey.title} - *
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default PublishableApiKeys - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { PublishableApiKey } from "@medusajs/medusa" - * import { useAdminPublishableApiKeys } from "medusa-react" - * - * const PublishableApiKeys = () => { - * const { - * publishable_api_keys, - * limit, - * offset, - * isLoading - * } = - * useAdminPublishableApiKeys({ - * limit: 50, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {publishable_api_keys && !publishable_api_keys.length && ( - * No Publishable API Keys - * )} - * {publishable_api_keys && - * publishable_api_keys.length > 0 && ( - *
    - * {publishable_api_keys.map( - * (publishableApiKey: PublishableApiKey) => ( - *
  • - * {publishableApiKey.title} - *
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default PublishableApiKeys - * ``` - * - * @customNamespace Hooks.Admin.Publishable API Keys - * @category Queries - */ -export const useAdminPublishableApiKeys = ( - /** - * Filters and pagination configurations to apply on the retrieved publishable API keys. - */ - query?: GetPublishableApiKeysParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminPublishableApiKeysKeys.list(query), - () => client.admin.publishableApiKeys.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook lists the sales channels associated with a publishable API key. The sales channels can be - * filtered by fields such as `q` passed in the `query` parameter. - * - * @example - * import React from "react" - * import { - * useAdminPublishableApiKeySalesChannels, - * } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const SalesChannels = ({ - * publishableApiKeyId - * }: Props) => { - * const { sales_channels, isLoading } = - * useAdminPublishableApiKeySalesChannels( - * publishableApiKeyId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {sales_channels && !sales_channels.length && ( - * No Sales Channels - * )} - * {sales_channels && sales_channels.length > 0 && ( - *
    - * {sales_channels.map((salesChannel) => ( - *
  • {salesChannel.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default SalesChannels - * - * @customNamespace Hooks.Admin.Publishable API Keys - * @category Queries - */ -export const useAdminPublishableApiKeySalesChannels = ( - /** - * The publishable API Key's ID. - */ - id: string, - /** - * Filters to apply on the retrieved sales channels. - */ - query?: GetPublishableApiKeySalesChannelsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminPublishableApiKeysKeys.detailSalesChannels(id, query), - () => client.admin.publishableApiKeys.listSalesChannels(id, query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/regions/index.ts b/packages/medusa-react/src/hooks/admin/regions/index.ts deleted file mode 100644 index 5c5b12abe4..0000000000 --- a/packages/medusa-react/src/hooks/admin/regions/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Region API Routes](https://docs.medusajs.com/api/admin#regions). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Regions are different countries or geographical regions that the commerce store serves customers in. - * Admins can manage these regions, their providers, and more. - * - * Related Guide: [How to manage regions](https://docs.medusajs.com/modules/regions-and-currencies/admin/manage-regions). - * - * @customNamespace Hooks.Admin.Regions - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/regions/mutations.ts b/packages/medusa-react/src/hooks/admin/regions/mutations.ts deleted file mode 100644 index 20a88f6087..0000000000 --- a/packages/medusa-react/src/hooks/admin/regions/mutations.ts +++ /dev/null @@ -1,533 +0,0 @@ -import { - AdminPostRegionsRegionCountriesReq, - AdminPostRegionsRegionFulfillmentProvidersReq, - AdminPostRegionsRegionPaymentProvidersReq, - AdminPostRegionsRegionReq, - AdminPostRegionsReq, - AdminRegionsDeleteRes, - AdminRegionsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminRegionKeys } from "./queries" - -/** - * This hook creates a region. - * - * @example - * import React from "react" - * import { useAdminCreateRegion } from "medusa-react" - * - * type CreateData = { - * name: string - * currency_code: string - * tax_rate: number - * payment_providers: string[] - * fulfillment_providers: string[] - * countries: string[] - * } - * - * const CreateRegion = () => { - * const createRegion = useAdminCreateRegion() - * // ... - * - * const handleCreate = (regionData: CreateData) => { - * createRegion.mutate(regionData, { - * onSuccess: ({ region }) => { - * console.log(region.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateRegion - * - * @customNamespace Hooks.Admin.Regions - * @category Mutations - */ -export const useAdminCreateRegion = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostRegionsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostRegionsReq) => client.admin.regions.create(payload), - buildOptions(queryClient, adminRegionKeys.lists(), options) - ) -} - -/** - * This hook updates a region's details. - * - * @example - * import React from "react" - * import { useAdminUpdateRegion } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const updateRegion = useAdminUpdateRegion(regionId) - * // ... - * - * const handleUpdate = ( - * countries: string[] - * ) => { - * updateRegion.mutate({ - * countries, - * }, { - * onSuccess: ({ region }) => { - * console.log(region.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - * @customNamespace Hooks.Admin.Regions - * @category Mutations - */ -export const useAdminUpdateRegion = ( - /** - * The region's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostRegionsRegionReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostRegionsRegionReq) => - client.admin.regions.update(id, payload), - buildOptions( - queryClient, - [adminRegionKeys.lists(), adminRegionKeys.detail(id)], - options - ) - ) -} - -/** - * This hook deletes a region. Associated resources, such as providers or currencies are not deleted. Associated tax rates are deleted. - * - * @example - * import React from "react" - * import { useAdminDeleteRegion } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const deleteRegion = useAdminDeleteRegion(regionId) - * // ... - * - * const handleDelete = () => { - * deleteRegion.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - * @customNamespace Hooks.Admin.Regions - * @category Mutations - */ -export const useAdminDeleteRegion = ( - /** - * The region's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.regions.delete(id), - buildOptions( - queryClient, - [adminRegionKeys.lists(), adminRegionKeys.detail(id)], - options - ) - ) -} - -/** - * This hook adds a country to the list of countries in a region. - * - * @example - * import React from "react" - * import { useAdminRegionAddCountry } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const addCountry = useAdminRegionAddCountry(regionId) - * // ... - * - * const handleAddCountry = ( - * countryCode: string - * ) => { - * addCountry.mutate({ - * country_code: countryCode - * }, { - * onSuccess: ({ region }) => { - * console.log(region.countries) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - * @customNamespace Hooks.Admin.Regions - * @category Mutations - */ -export const useAdminRegionAddCountry = ( - /** - * The region's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostRegionsRegionCountriesReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostRegionsRegionCountriesReq) => - client.admin.regions.addCountry(id, payload), - buildOptions(queryClient, adminRegionKeys.detail(id), options) - ) -} - -/** - * This hook deletes a country from the list of countries in a region. The country will still be available in the system, and it can be used in other regions. - * - * @typeParamDefinition string - The code of the country to delete from the region. - * - * @example - * import React from "react" - * import { useAdminRegionRemoveCountry } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const removeCountry = useAdminRegionRemoveCountry(regionId) - * // ... - * - * const handleRemoveCountry = ( - * countryCode: string - * ) => { - * removeCountry.mutate(countryCode, { - * onSuccess: ({ region }) => { - * console.log(region.countries) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - * @customNamespace Hooks.Admin.Regions - * @category Mutations - */ -export const useAdminRegionRemoveCountry = ( - /** - * The region's ID. - */ - id: string, - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (country_code: string) => - client.admin.regions.deleteCountry(id, country_code), - buildOptions(queryClient, adminRegionKeys.detail(id), options) - ) -} - -/** - * This hook adds a fulfillment provider to the list of fulfullment providers in a region. - * - * @example - * import React from "react" - * import { - * useAdminRegionAddFulfillmentProvider - * } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const addFulfillmentProvider = - * useAdminRegionAddFulfillmentProvider(regionId) - * // ... - * - * const handleAddFulfillmentProvider = ( - * providerId: string - * ) => { - * addFulfillmentProvider.mutate({ - * provider_id: providerId - * }, { - * onSuccess: ({ region }) => { - * console.log(region.fulfillment_providers) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - * @customNamespace Hooks.Admin.Regions - * @category Mutations - */ -export const useAdminRegionAddFulfillmentProvider = ( - /** - * The region's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostRegionsRegionFulfillmentProvidersReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostRegionsRegionFulfillmentProvidersReq) => - client.admin.regions.addFulfillmentProvider(id, payload), - buildOptions(queryClient, adminRegionKeys.detail(id), options) - ) -} - -/** - * This hook deletes a fulfillment provider from a region. The fulfillment provider will still be available for usage in other regions. - * - * @typeParamDefinition string - The fulfillment provider's ID to delete from the region. - * - * @example - * import React from "react" - * import { - * useAdminRegionDeleteFulfillmentProvider - * } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const removeFulfillmentProvider = - * useAdminRegionDeleteFulfillmentProvider(regionId) - * // ... - * - * const handleRemoveFulfillmentProvider = ( - * providerId: string - * ) => { - * removeFulfillmentProvider.mutate(providerId, { - * onSuccess: ({ region }) => { - * console.log(region.fulfillment_providers) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - * @customNamespace Hooks.Admin.Regions - * @category Mutations - */ -export const useAdminRegionDeleteFulfillmentProvider = ( - /** - * The region's ID. - */ - id: string, - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (provider_id: string) => - client.admin.regions.deleteFulfillmentProvider(id, provider_id), - buildOptions(queryClient, adminRegionKeys.detail(id), options) - ) -} - -/** - * This hook adds a payment provider to the list of payment providers in a region. - * - * @example - * import React from "react" - * import { - * useAdminRegionAddPaymentProvider - * } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const addPaymentProvider = - * useAdminRegionAddPaymentProvider(regionId) - * // ... - * - * const handleAddPaymentProvider = ( - * providerId: string - * ) => { - * addPaymentProvider.mutate({ - * provider_id: providerId - * }, { - * onSuccess: ({ region }) => { - * console.log(region.payment_providers) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - * @customNamespace Hooks.Admin.Regions - * @category Mutations - */ -export const useAdminRegionAddPaymentProvider = ( - /** - * The region's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostRegionsRegionPaymentProvidersReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostRegionsRegionPaymentProvidersReq) => - client.admin.regions.addPaymentProvider(id, payload), - buildOptions(queryClient, adminRegionKeys.detail(id), options) - ) -} - -/** - * This hook deletes a payment provider from a region. The payment provider will still be available for usage in other regions. - * - * @typeParamDefinition string - The ID of the payment provider to delete from the region. - * - * @example - * import React from "react" - * import { - * useAdminRegionDeletePaymentProvider - * } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const removePaymentProvider = - * useAdminRegionDeletePaymentProvider(regionId) - * // ... - * - * const handleRemovePaymentProvider = ( - * providerId: string - * ) => { - * removePaymentProvider.mutate(providerId, { - * onSuccess: ({ region }) => { - * console.log(region.payment_providers) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - * @customNamespace Hooks.Admin.Regions - * @category Mutations - */ -export const useAdminRegionDeletePaymentProvider = ( - /** - * The region's ID. - */ - id: string, - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (provider_id: string) => - client.admin.regions.deletePaymentProvider(id, provider_id), - buildOptions(queryClient, adminRegionKeys.detail(id), options) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/regions/queries.ts b/packages/medusa-react/src/hooks/admin/regions/queries.ts deleted file mode 100644 index 61b9c57d8e..0000000000 --- a/packages/medusa-react/src/hooks/admin/regions/queries.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { - AdminGetRegionsParams, - AdminGetRegionsRegionFulfillmentOptionsRes, - AdminRegionsListRes, - AdminRegionsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_REGIONS_QUERY_KEY = `admin_regions` as const - -export const adminRegionKeys = queryKeysFactory(ADMIN_REGIONS_QUERY_KEY) - -type RegionQueryKeys = typeof adminRegionKeys - -/** - * This hook retrieves a list of Regions. The regions can be filtered by fields such as `created_at` passed in the `query` parameter. - * The regions can also be paginated. - * - * @example - * To list regions: - * - * ```tsx - * import React from "react" - * import { useAdminRegions } from "medusa-react" - * - * const Regions = () => { - * const { regions, isLoading } = useAdminRegions() - * - * return ( - *
- * {isLoading && Loading...} - * {regions && !regions.length && No Regions} - * {regions && regions.length > 0 && ( - *
    - * {regions.map((region) => ( - *
  • {region.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Regions - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminRegions } from "medusa-react" - * - * const Regions = () => { - * const { - * regions, - * limit, - * offset, - * isLoading - * } = useAdminRegions({ - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {regions && !regions.length && No Regions} - * {regions && regions.length > 0 && ( - *
    - * {regions.map((region) => ( - *
  • {region.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Regions - * ``` - * - * @customNamespace Hooks.Admin.Regions - * @category Queries - */ -export const useAdminRegions = ( - /** - * Filters and pagination configurations to apply on the retrieved regions. - */ - query?: AdminGetRegionsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminRegionKeys.list(query), - () => client.admin.regions.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a region's details. - * - * @example - * import React from "react" - * import { useAdminRegion } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const { region, isLoading } = useAdminRegion( - * regionId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {region && {region.name}} - *
- * ) - * } - * - * export default Region - * - * @customNamespace Hooks.Admin.Regions - * @category Queries - */ -export const useAdminRegion = ( - /** - * The region's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminRegionKeys.detail(id), - () => client.admin.regions.retrieve(id), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a list of fulfillment options available in a region. - * - * @example - * import React from "react" - * import { - * useAdminRegionFulfillmentOptions - * } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const { - * fulfillment_options, - * isLoading - * } = useAdminRegionFulfillmentOptions( - * regionId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {fulfillment_options && !fulfillment_options.length && ( - * No Regions - * )} - * {fulfillment_options && - * fulfillment_options.length > 0 && ( - *
    - * {fulfillment_options.map((option) => ( - *
  • - * {option.provider_id} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Region - * - * @customNamespace Hooks.Admin.Regions - * @category Queries - */ -export const useAdminRegionFulfillmentOptions = ( - /** - * The region's ID. - */ - regionId: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminRegionKeys.detail(`${regionId}_fullfillment-options`), - () => client.admin.regions.retrieveFulfillmentOptions(regionId), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/reservations/index.ts b/packages/medusa-react/src/hooks/admin/reservations/index.ts deleted file mode 100644 index fc48b511b0..0000000000 --- a/packages/medusa-react/src/hooks/admin/reservations/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Reservation API Routes](https://docs.medusajs.com/api/admin#reservations). - * To use these hooks, make sure to install the - * [@medusajs/inventory](https://docs.medusajs.com/modules/multiwarehouse/install-modules#inventory-module) module in your Medusa backend. - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Reservations, provided by the [Inventory Module](https://docs.medusajs.com/modules/multiwarehouse/inventory-module), - * are quantities of an item that are reserved, typically when an order is placed but not yet fulfilled. - * Reservations can be associated with any resources, but commonly with line items of an order. - * - * Related Guide: [How to manage item allocations in orders](https://docs.medusajs.com/modules/multiwarehouse/admin/manage-item-allocations-in-orders). - * - * @customNamespace Hooks.Admin.Reservations - */ - -export * from "./mutations" -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/admin/reservations/mutations.ts b/packages/medusa-react/src/hooks/admin/reservations/mutations.ts deleted file mode 100644 index 6f1813c10b..0000000000 --- a/packages/medusa-react/src/hooks/admin/reservations/mutations.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { - AdminPostReservationsReq, - AdminPostReservationsReservationReq, - AdminReservationsDeleteRes, - AdminReservationsRes, -} from "@medusajs/medusa" -import { - UseMutationOptions, - useMutation, - useQueryClient, -} from "@tanstack/react-query" - -import { Response } from "@medusajs/medusa-js" -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminInventoryItemsKeys } from "../inventory-item" -import { adminVariantKeys } from "../variants" -import { adminReservationsKeys } from "./queries" - -/** - * This hook creates a reservation which can be associated with any resource, such as an order's line item. - * - * @example - * import React from "react" - * import { useAdminCreateReservation } from "medusa-react" - * - * const CreateReservation = () => { - * const createReservation = useAdminCreateReservation() - * // ... - * - * const handleCreate = ( - * locationId: string, - * inventoryItemId: string, - * quantity: number - * ) => { - * createReservation.mutate({ - * location_id: locationId, - * inventory_item_id: inventoryItemId, - * quantity, - * }, { - * onSuccess: ({ reservation }) => { - * console.log(reservation.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateReservation - * - * @customNamespace Hooks.Admin.Reservations - * @category Mutations - */ -export const useAdminCreateReservation = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostReservationsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostReservationsReq) => - client.admin.reservations.create(payload), - buildOptions( - queryClient, - [adminReservationsKeys.lists(), adminVariantKeys.all], - options - ) - ) -} - -/** - * This hook updates a reservation's details. - * - * @example - * import React from "react" - * import { useAdminUpdateReservation } from "medusa-react" - * - * type Props = { - * reservationId: string - * } - * - * const Reservation = ({ reservationId }: Props) => { - * const updateReservation = useAdminUpdateReservation( - * reservationId - * ) - * // ... - * - * const handleUpdate = ( - * quantity: number - * ) => { - * updateReservation.mutate({ - * quantity, - * }) - * } - * - * // ... - * } - * - * export default Reservation - * - * @customNamespace Hooks.Admin.Reservations - * @category Mutations - */ -export const useAdminUpdateReservation = ( - /** - * The reservation's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostReservationsReservationReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostReservationsReservationReq) => - client.admin.reservations.update(id, payload), - buildOptions( - queryClient, - [ - adminReservationsKeys.lists(), - adminReservationsKeys.detail(id), - adminVariantKeys.all, - adminInventoryItemsKeys.details() - ], - options - ) - ) -} - -/** - * This hook deletes a reservation. Associated resources, such as the line item, will not be deleted. - * - * @example - * import React from "react" - * import { useAdminDeleteReservation } from "medusa-react" - * - * type Props = { - * reservationId: string - * } - * - * const Reservation = ({ reservationId }: Props) => { - * const deleteReservation = useAdminDeleteReservation( - * reservationId - * ) - * // ... - * - * const handleDelete = () => { - * deleteReservation.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Reservation - * - * @customNamespace Hooks.Admin.Reservations - * @category Mutations - */ -export const useAdminDeleteReservation = ( - /** - * The reservation's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - void - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.reservations.delete(id), - buildOptions( - queryClient, - [ - adminReservationsKeys.lists(), - adminReservationsKeys.detail(id), - adminVariantKeys.all, - ], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/reservations/queries.ts b/packages/medusa-react/src/hooks/admin/reservations/queries.ts deleted file mode 100644 index 785a082596..0000000000 --- a/packages/medusa-react/src/hooks/admin/reservations/queries.ts +++ /dev/null @@ -1,202 +0,0 @@ -import { - AdminGetReservationsParams, - AdminReservationsListRes, - AdminReservationsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const ADMIN_RESERVATIONS_QUERY_KEY = `admin_reservations` as const - -export const adminReservationsKeys = queryKeysFactory( - ADMIN_RESERVATIONS_QUERY_KEY -) - -type ReservationsQueryKeys = typeof adminReservationsKeys - -/** - * This hook retrieves a list of reservations. The reservations can be filtered by fields such as `location_id` or `quantity` - * passed in the `query` parameter. The reservations can also be paginated. - * - * @example - * To list reservations: - * - * ```tsx - * import React from "react" - * import { useAdminReservations } from "medusa-react" - * - * const Reservations = () => { - * const { reservations, isLoading } = useAdminReservations() - * - * return ( - *
- * {isLoading && Loading...} - * {reservations && !reservations.length && ( - * No Reservations - * )} - * {reservations && reservations.length > 0 && ( - *
    - * {reservations.map((reservation) => ( - *
  • {reservation.quantity}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Reservations - * ``` - * - * To specify relations that should be retrieved within the reservations: - * - * ```tsx - * import React from "react" - * import { useAdminReservations } from "medusa-react" - * - * const Reservations = () => { - * const { - * reservations, - * isLoading - * } = useAdminReservations({ - * expand: "location" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {reservations && !reservations.length && ( - * No Reservations - * )} - * {reservations && reservations.length > 0 && ( - *
    - * {reservations.map((reservation) => ( - *
  • {reservation.quantity}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Reservations - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminReservations } from "medusa-react" - * - * const Reservations = () => { - * const { - * reservations, - * limit, - * offset, - * isLoading - * } = useAdminReservations({ - * expand: "location", - * limit: 10, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {reservations && !reservations.length && ( - * No Reservations - * )} - * {reservations && reservations.length > 0 && ( - *
    - * {reservations.map((reservation) => ( - *
  • {reservation.quantity}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Reservations - * ``` - * - * @customNamespace Hooks.Admin.Reservations - * @category Queries - */ -export const useAdminReservations = ( - /** - * Filters and pagination parameters to apply on the retrieved reservations. - */ - query?: AdminGetReservationsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - - const { data, ...rest } = useQuery( - adminReservationsKeys.list(query), - () => client.admin.reservations.list(query), - { ...options } - ) - - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a reservation's details. - * - * @example - * import React from "react" - * import { useAdminReservation } from "medusa-react" - * - * type Props = { - * reservationId: string - * } - * - * const Reservation = ({ reservationId }: Props) => { - * const { reservation, isLoading } = useAdminReservation( - * reservationId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {reservation && ( - * {reservation.inventory_item_id} - * )} - *
- * ) - * } - * - * export default Reservation - * - * @customNamespace Hooks.Admin.Reservations - * @category Queries - */ -export const useAdminReservation = ( - /** - * The reservation's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - - const { data, ...rest } = useQuery( - adminReservationsKeys.detail(id), - () => client.admin.reservations.retrieve(id), - options - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/return-reasons/index.ts b/packages/medusa-react/src/hooks/admin/return-reasons/index.ts deleted file mode 100644 index 1e038c375b..0000000000 --- a/packages/medusa-react/src/hooks/admin/return-reasons/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Return Reason API Routes](https://docs.medusajs.com/api/admin#return-reasons). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Return reasons are key-value pairs that are used to specify why an order return is being created. - * Admins can manage available return reasons, and they can be used by both admins and customers when creating a return. - * - * Related Guide: [How to manage return reasons](https://docs.medusajs.com/modules/orders/admin/manage-returns#manage-return-reasons). - * - * @customNamespace Hooks.Admin.Return Reasons - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/return-reasons/mutations.ts b/packages/medusa-react/src/hooks/admin/return-reasons/mutations.ts deleted file mode 100644 index bd3f608ff8..0000000000 --- a/packages/medusa-react/src/hooks/admin/return-reasons/mutations.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { - AdminPostReturnReasonsReasonReq, - AdminPostReturnReasonsReq, - AdminReturnReasonsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminReturnReasonKeys } from "./queries" - -/** - * This hook creates a return reason. - * - * @example - * import React from "react" - * import { useAdminCreateReturnReason } from "medusa-react" - * - * const CreateReturnReason = () => { - * const createReturnReason = useAdminCreateReturnReason() - * // ... - * - * const handleCreate = ( - * label: string, - * value: string - * ) => { - * createReturnReason.mutate({ - * label, - * value, - * }, { - * onSuccess: ({ return_reason }) => { - * console.log(return_reason.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateReturnReason - * - * @customNamespace Hooks.Admin.Return Reasons - * @category Mutations - */ -export const useAdminCreateReturnReason = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostReturnReasonsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostReturnReasonsReq) => - client.admin.returnReasons.create(payload), - buildOptions(queryClient, adminReturnReasonKeys.lists(), options) - ) -} - -/** - * This hook updates a return reason's details. - * - * @example - * import React from "react" - * import { useAdminUpdateReturnReason } from "medusa-react" - * - * type Props = { - * returnReasonId: string - * } - * - * const ReturnReason = ({ returnReasonId }: Props) => { - * const updateReturnReason = useAdminUpdateReturnReason( - * returnReasonId - * ) - * // ... - * - * const handleUpdate = ( - * label: string - * ) => { - * updateReturnReason.mutate({ - * label, - * }, { - * onSuccess: ({ return_reason }) => { - * console.log(return_reason.label) - * } - * }) - * } - * - * // ... - * } - * - * export default ReturnReason - * - * @customNamespace Hooks.Admin.Return Reasons - * @category Mutations - */ -export const useAdminUpdateReturnReason = ( - /** - * The return reason's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostReturnReasonsReasonReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostReturnReasonsReasonReq) => - client.admin.returnReasons.update(id, payload), - buildOptions( - queryClient, - [adminReturnReasonKeys.detail(id), adminReturnReasonKeys.lists()], - options - ) - ) -} - -/** - * This hook deletes a return reason. - * - * @example - * import React from "react" - * import { useAdminDeleteReturnReason } from "medusa-react" - * - * type Props = { - * returnReasonId: string - * } - * - * const ReturnReason = ({ returnReasonId }: Props) => { - * const deleteReturnReason = useAdminDeleteReturnReason( - * returnReasonId - * ) - * // ... - * - * const handleDelete = () => { - * deleteReturnReason.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default ReturnReason - * - * @customNamespace Hooks.Admin.Return Reasons - * @category Mutations - */ -export const useAdminDeleteReturnReason = ( - /** - * The return reason's ID. - */ - id: string, - options?: UseMutationOptions -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.returnReasons.delete(id), - buildOptions( - queryClient, - [adminReturnReasonKeys.detail(id), adminReturnReasonKeys.lists()], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/return-reasons/queries.ts b/packages/medusa-react/src/hooks/admin/return-reasons/queries.ts deleted file mode 100644 index e070214684..0000000000 --- a/packages/medusa-react/src/hooks/admin/return-reasons/queries.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { - AdminReturnReasonsListRes, - AdminReturnReasonsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_RETURNS_REASONS_QUERY_KEY = `admin_return_reasons` as const - -export const adminReturnReasonKeys = queryKeysFactory( - ADMIN_RETURNS_REASONS_QUERY_KEY -) - -type ReturnReasonQueryKeys = typeof adminReturnReasonKeys - -/** - * This hook retrieves a list of return reasons. - * - * @example - * import React from "react" - * import { useAdminReturnReasons } from "medusa-react" - * - * const ReturnReasons = () => { - * const { return_reasons, isLoading } = useAdminReturnReasons() - * - * return ( - *
- * {isLoading && Loading...} - * {return_reasons && !return_reasons.length && ( - * No Return Reasons - * )} - * {return_reasons && return_reasons.length > 0 && ( - *
    - * {return_reasons.map((reason) => ( - *
  • - * {reason.label}: {reason.value} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ReturnReasons - * - * @customNamespace Hooks.Admin.Return Reasons - * @category Queries - */ -export const useAdminReturnReasons = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminReturnReasonKeys.lists(), - () => client.admin.returnReasons.list(), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a return reason's details. - * - * @example - * import React from "react" - * import { useAdminReturnReason } from "medusa-react" - * - * type Props = { - * returnReasonId: string - * } - * - * const ReturnReason = ({ returnReasonId }: Props) => { - * const { return_reason, isLoading } = useAdminReturnReason( - * returnReasonId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {return_reason && {return_reason.label}} - *
- * ) - * } - * - * export default ReturnReason - * - * @customNamespace Hooks.Admin.Return Reasons - * @category Queries - */ -export const useAdminReturnReason = ( - /** - * The return reason's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminReturnReasonKeys.detail(id), - () => client.admin.returnReasons.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/returns/index.ts b/packages/medusa-react/src/hooks/admin/returns/index.ts deleted file mode 100644 index 065434d59a..0000000000 --- a/packages/medusa-react/src/hooks/admin/returns/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Return API Routes](https://docs.medusajs.com/api/admin#returns). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A return can be created by a customer or an admin to return items in an order. - * Admins can manage these returns and change their state. - * - * Related Guide: [How to manage returns](https://docs.medusajs.com/modules/orders/admin/manage-returns). - * - * @customNamespace Hooks.Admin.Returns - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/returns/mutations.ts b/packages/medusa-react/src/hooks/admin/returns/mutations.ts deleted file mode 100644 index 6dceb63c54..0000000000 --- a/packages/medusa-react/src/hooks/admin/returns/mutations.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { - AdminPostReturnsReturnReceiveReq, - AdminReturnsCancelRes, - AdminReturnsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminReturnKeys } from "./queries" - -/** - * This hook marks a return as received. This also updates the status of associated order, claim, or swap accordingly. - * - * @example - * import React from "react" - * import { useAdminReceiveReturn } from "medusa-react" - * - * type ReceiveReturnData = { - * items: { - * item_id: string - * quantity: number - * }[] - * } - * - * type Props = { - * returnId: string - * } - * - * const Return = ({ returnId }: Props) => { - * const receiveReturn = useAdminReceiveReturn( - * returnId - * ) - * // ... - * - * const handleReceive = (data: ReceiveReturnData) => { - * receiveReturn.mutate(data, { - * onSuccess: ({ return: dataReturn }) => { - * console.log(dataReturn.status) - * } - * }) - * } - * - * // ... - * } - * - * export default Return - * - * @customNamespace Hooks.Admin.Returns - * @category Mutations - */ -export const useAdminReceiveReturn = ( - /** - * The return's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostReturnsReturnReceiveReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload) => client.admin.returns.receive(id, payload), - buildOptions( - queryClient, - [adminReturnKeys.detail(id), adminReturnKeys.list()], - options - ) - ) -} - -/** - * This hook registers a return as canceled. The return can be associated with an order, claim, or swap. - * - * @example - * import React from "react" - * import { useAdminCancelReturn } from "medusa-react" - * - * type Props = { - * returnId: string - * } - * - * const Return = ({ returnId }: Props) => { - * const cancelReturn = useAdminCancelReturn( - * returnId - * ) - * // ... - * - * const handleCancel = () => { - * cancelReturn.mutate(void 0, { - * onSuccess: ({ order }) => { - * console.log(order.returns) - * } - * }) - * } - * - * // ... - * } - * - * export default Return - * - * @customNamespace Hooks.Admin.Returns - * @category Mutations - */ -export const useAdminCancelReturn = ( - /** - * The return's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.returns.cancel(id), - buildOptions( - queryClient, - [adminReturnKeys.detail(id), adminReturnKeys.list()], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/returns/queries.ts b/packages/medusa-react/src/hooks/admin/returns/queries.ts deleted file mode 100644 index e226117031..0000000000 --- a/packages/medusa-react/src/hooks/admin/returns/queries.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { AdminReturnsListRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_RETURNS_QUERY_KEY = `admin_returns` as const - -export const adminReturnKeys = queryKeysFactory(ADMIN_RETURNS_QUERY_KEY) - -type ReturnQueryKeys = typeof adminReturnKeys - -/** - * This hook retrieves a list of Returns. The returns can be paginated. - * - * @example - * import React from "react" - * import { useAdminReturns } from "medusa-react" - * - * const Returns = () => { - * const { returns, isLoading } = useAdminReturns() - * - * return ( - *
- * {isLoading && Loading...} - * {returns && !returns.length && ( - * No Returns - * )} - * {returns && returns.length > 0 && ( - *
    - * {returns.map((returnData) => ( - *
  • - * {returnData.status} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Returns - * - * @customNamespace Hooks.Admin.Returns - * @category Queries - */ -export const useAdminReturns = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminReturnKeys.lists(), - () => client.admin.returns.list(), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/sales-channels/index.ts b/packages/medusa-react/src/hooks/admin/sales-channels/index.ts deleted file mode 100644 index 154e17823b..0000000000 --- a/packages/medusa-react/src/hooks/admin/sales-channels/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Sales Channel API Routes](https://docs.medusajs.com/api/admin#sales-channels). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A sales channel indicates a channel where products can be sold in. For example, a webshop or a mobile app. - * Admins can manage sales channels and the products available in them. - * - * Related Guide: [How to manage sales channels](https://docs.medusajs.com/modules/sales-channels/admin/manage). - * - * @customNamespace Hooks.Admin.Sales Channels - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/sales-channels/mutations.ts b/packages/medusa-react/src/hooks/admin/sales-channels/mutations.ts deleted file mode 100644 index 53f327bb3d..0000000000 --- a/packages/medusa-react/src/hooks/admin/sales-channels/mutations.ts +++ /dev/null @@ -1,468 +0,0 @@ -import { - AdminDeleteSalesChannelsChannelProductsBatchReq, - AdminPostSalesChannelsChannelProductsBatchReq, - AdminPostSalesChannelsReq, - AdminPostSalesChannelsSalesChannelReq, - AdminSalesChannelsDeleteRes, - AdminSalesChannelsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" - -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminProductKeys } from "../products" -import { adminStockLocationsKeys } from "../stock-locations" -import { adminSalesChannelsKeys } from "./queries" - -/** - * This hook creates a sales channel. - * - * @example - * import React from "react" - * import { useAdminCreateSalesChannel } from "medusa-react" - * - * const CreateSalesChannel = () => { - * const createSalesChannel = useAdminCreateSalesChannel() - * // ... - * - * const handleCreate = (name: string, description: string) => { - * createSalesChannel.mutate({ - * name, - * description, - * }, { - * onSuccess: ({ sales_channel }) => { - * console.log(sales_channel.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateSalesChannel - * - * @customNamespace Hooks.Admin.Sales Channels - * @category Mutations - */ -export const useAdminCreateSalesChannel = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostSalesChannelsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostSalesChannelsReq) => - client.admin.salesChannels.create(payload), - buildOptions(queryClient, [adminSalesChannelsKeys.list()], options) - ) -} - -/** - * This hook updates a sales channel's details. - * - * @example - * import React from "react" - * import { useAdminUpdateSalesChannel } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const updateSalesChannel = useAdminUpdateSalesChannel( - * salesChannelId - * ) - * // ... - * - * const handleUpdate = ( - * is_disabled: boolean - * ) => { - * updateSalesChannel.mutate({ - * is_disabled, - * }, { - * onSuccess: ({ sales_channel }) => { - * console.log(sales_channel.is_disabled) - * } - * }) - * } - * - * // ... - * } - * - * export default SalesChannel - * - * @customNamespace Hooks.Admin.Sales Channels - * @category Mutations - */ -export const useAdminUpdateSalesChannel = ( - /** - * The sales channel's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostSalesChannelsSalesChannelReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostSalesChannelsSalesChannelReq) => - client.admin.salesChannels.update(id, payload), - buildOptions( - queryClient, - [adminSalesChannelsKeys.lists(), adminSalesChannelsKeys.detail(id)], - options - ) - ) -} - -/** - * This hook deletes a sales channel. Associated products, stock locations, and other resources are not deleted. - * - * @example - * import React from "react" - * import { useAdminDeleteSalesChannel } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const deleteSalesChannel = useAdminDeleteSalesChannel( - * salesChannelId - * ) - * // ... - * - * const handleDelete = () => { - * deleteSalesChannel.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default SalesChannel - * - * @customNamespace Hooks.Admin.Sales Channels - * @category Mutations - */ -export const useAdminDeleteSalesChannel = ( - /** - * The sales channel's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - void - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - () => client.admin.salesChannels.delete(id), - buildOptions( - queryClient, - [adminSalesChannelsKeys.lists(), adminSalesChannelsKeys.detail(id)], - options - ) - ) -} - -/** - * This hook removes a list of products from a sales channel. This doesn't delete the product. It only removes the - * association between the product and the sales channel. - * - * @example - * import React from "react" - * import { - * useAdminDeleteProductsFromSalesChannel, - * } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const deleteProducts = useAdminDeleteProductsFromSalesChannel( - * salesChannelId - * ) - * // ... - * - * const handleDeleteProducts = (productId: string) => { - * deleteProducts.mutate({ - * product_ids: [ - * { - * id: productId, - * }, - * ], - * }, { - * onSuccess: ({ sales_channel }) => { - * console.log(sales_channel.id) - * } - * }) - * } - * - * // ... - * } - * - * export default SalesChannel - * - * @customNamespace Hooks.Admin.Sales Channels - * @category Mutations - */ -export const useAdminDeleteProductsFromSalesChannel = ( - /** - * The sales channel's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminDeleteSalesChannelsChannelProductsBatchReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminDeleteSalesChannelsChannelProductsBatchReq) => { - return client.admin.salesChannels.removeProducts(id, payload) - }, - buildOptions( - queryClient, - [ - adminSalesChannelsKeys.lists(), - adminSalesChannelsKeys.detail(id), - adminProductKeys.list({ sales_channel_id: [id] }), - ], - options - ) - ) -} - -/** - * This hook adds a list of products to a sales channel. - * - * @example - * import React from "react" - * import { useAdminAddProductsToSalesChannel } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const addProducts = useAdminAddProductsToSalesChannel( - * salesChannelId - * ) - * // ... - * - * const handleAddProducts = (productId: string) => { - * addProducts.mutate({ - * product_ids: [ - * { - * id: productId, - * }, - * ], - * }, { - * onSuccess: ({ sales_channel }) => { - * console.log(sales_channel.id) - * } - * }) - * } - * - * // ... - * } - * - * export default SalesChannel - * - * @customNamespace Hooks.Admin.Sales Channels - * @category Mutations - */ -export const useAdminAddProductsToSalesChannel = ( - /** - * The sales channel's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostSalesChannelsChannelProductsBatchReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostSalesChannelsChannelProductsBatchReq) => { - return client.admin.salesChannels.addProducts(id, payload) - }, - buildOptions( - queryClient, - [ - adminSalesChannelsKeys.lists(), - adminSalesChannelsKeys.detail(id), - adminProductKeys.list({ sales_channel_id: [id] }), - ], - options - ) - ) -} - -/** - * This hook associates a stock location with a sales channel. It requires the - * [@medusajs/stock-location](https://docs.medusajs.com/modules/multiwarehouse/install-modules#stock-location-module) module to be installed in - * your Medusa backend. - * - * @example - * import React from "react" - * import { - * useAdminAddLocationToSalesChannel - * } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const addLocation = useAdminAddLocationToSalesChannel() - * // ... - * - * const handleAddLocation = (locationId: string) => { - * addLocation.mutate({ - * sales_channel_id: salesChannelId, - * location_id: locationId - * }, { - * onSuccess: ({ sales_channel }) => { - * console.log(sales_channel.locations) - * } - * }) - * } - * - * // ... - * } - * - * export default SalesChannel - * - * @customNamespace Hooks.Admin.Sales Channels - * @category Mutations - */ -export const useAdminAddLocationToSalesChannel = ( - options?: UseMutationOptions< - Response, - Error, - { - /** - * The sales channel's ID. - */ - sales_channel_id: string - /** - * The location's ID. - */ - location_id: string - } - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation(({ sales_channel_id, location_id }) => { - return client.admin.salesChannels.addLocation(sales_channel_id, { - location_id, - }) - }, buildOptions( - queryClient, - [ - adminSalesChannelsKeys.lists(), - adminSalesChannelsKeys.details(), - adminStockLocationsKeys.all - ], - options - ) - ) -} - -/** - * This hook removes a stock location from a sales channel. This only removes the association between the stock - * location and the sales channel. It does not delete the stock location. This hook requires the - * [@medusajs/stock-location](https://docs.medusajs.com/modules/multiwarehouse/install-modules#stock-location-module) module to be installed in - * your Medusa backend. - * - * @example - * import React from "react" - * import { - * useAdminRemoveLocationFromSalesChannel - * } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const removeLocation = useAdminRemoveLocationFromSalesChannel() - * // ... - * - * const handleRemoveLocation = (locationId: string) => { - * removeLocation.mutate({ - * sales_channel_id: salesChannelId, - * location_id: locationId - * }, { - * onSuccess: ({ sales_channel }) => { - * console.log(sales_channel.locations) - * } - * }) - * } - * - * // ... - * } - * - * export default SalesChannel - * - * @customNamespace Hooks.Admin.Sales Channels - * @category Mutations - */ -export const useAdminRemoveLocationFromSalesChannel = ( - options?: UseMutationOptions< - Response, - Error, - { - /** - * The sales channel's ID. - */ - sales_channel_id: string - /** - * The location's ID. - */ - location_id: string - } - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation(({ sales_channel_id, location_id }) => { - return client.admin.salesChannels.removeLocation(sales_channel_id, { - location_id, - }) - }, buildOptions( - queryClient, - [ - adminSalesChannelsKeys.lists(), - adminSalesChannelsKeys.details(), - adminStockLocationsKeys.all - ], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/sales-channels/queries.ts b/packages/medusa-react/src/hooks/admin/sales-channels/queries.ts deleted file mode 100644 index dc5cfb8440..0000000000 --- a/packages/medusa-react/src/hooks/admin/sales-channels/queries.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { - AdminGetSalesChannelsParams, - AdminSalesChannelsListRes, - AdminSalesChannelsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const ADMIN_SALES_CHANNELS_QUERY_KEY = `admin_sales_channels` as const - -export const adminSalesChannelsKeys = queryKeysFactory( - ADMIN_SALES_CHANNELS_QUERY_KEY -) - -type SalesChannelsQueryKeys = typeof adminSalesChannelsKeys - -/** - * This hook retrieves a sales channel's details. - * - * @example - * import React from "react" - * import { useAdminSalesChannel } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const { - * sales_channel, - * isLoading, - * } = useAdminSalesChannel(salesChannelId) - * - * return ( - *
- * {isLoading && Loading...} - * {sales_channel && {sales_channel.name}} - *
- * ) - * } - * - * export default SalesChannel - * - * @customNamespace Hooks.Admin.Sales Channels - * @category Queries - */ -export const useAdminSalesChannel = ( - /** - * The sales channel's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminSalesChannelsKeys.detail(id), - () => client.admin.salesChannels.retrieve(id), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a list of sales channels. The sales channels can be filtered by fields such as `q` or `name` - * passed in the `query` parameter. The sales channels can also be sorted or paginated. - * - * @example - * To list sales channels: - * - * ```tsx - * import React from "react" - * import { useAdminSalesChannels } from "medusa-react" - * - * const SalesChannels = () => { - * const { sales_channels, isLoading } = useAdminSalesChannels() - * - * return ( - *
- * {isLoading && Loading...} - * {sales_channels && !sales_channels.length && ( - * No Sales Channels - * )} - * {sales_channels && sales_channels.length > 0 && ( - *
    - * {sales_channels.map((salesChannel) => ( - *
  • {salesChannel.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default SalesChannels - * ``` - * - * To specify relations that should be retrieved within the sales channels: - * - * ```tsx - * import React from "react" - * import { useAdminSalesChannels } from "medusa-react" - * - * const SalesChannels = () => { - * const { - * sales_channels, - * isLoading - * } = useAdminSalesChannels({ - * expand: "locations" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {sales_channels && !sales_channels.length && ( - * No Sales Channels - * )} - * {sales_channels && sales_channels.length > 0 && ( - *
    - * {sales_channels.map((salesChannel) => ( - *
  • {salesChannel.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default SalesChannels - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminSalesChannels } from "medusa-react" - * - * const SalesChannels = () => { - * const { - * sales_channels, - * limit, - * offset, - * isLoading - * } = useAdminSalesChannels({ - * expand: "locations", - * limit: 10, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {sales_channels && !sales_channels.length && ( - * No Sales Channels - * )} - * {sales_channels && sales_channels.length > 0 && ( - *
    - * {sales_channels.map((salesChannel) => ( - *
  • {salesChannel.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default SalesChannels - * ``` - * - * @customNamespace Hooks.Admin.Sales Channels - * @category Queries - */ -export const useAdminSalesChannels = ( - /** - * Filters and pagination configurations applied on the retrieved sales channels. - */ - query?: AdminGetSalesChannelsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminSalesChannelsKeys.list(query), - () => client.admin.salesChannels.list(query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/shipping-options/index.ts b/packages/medusa-react/src/hooks/admin/shipping-options/index.ts deleted file mode 100644 index 071b28020f..0000000000 --- a/packages/medusa-react/src/hooks/admin/shipping-options/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Shipping Option API Routes](https://docs.medusajs.com/api/admin#shipping-options). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A shipping option is used to define the available shipping methods during checkout or when creating a return. - * Admins can create an unlimited number of shipping options, each associated with a shipping profile and fulfillment provider, among other resources. - * - * Related Guide: [Shipping Option architecture](https://docs.medusajs.com/modules/carts-and-checkout/shipping#shipping-option). - * - * @customNamespace Hooks.Admin.Shipping Options - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/shipping-options/mutations.ts b/packages/medusa-react/src/hooks/admin/shipping-options/mutations.ts deleted file mode 100644 index 5ff5600f13..0000000000 --- a/packages/medusa-react/src/hooks/admin/shipping-options/mutations.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { - AdminPostShippingOptionsOptionReq, - AdminPostShippingOptionsReq, - AdminShippingOptionsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminShippingOptionKeys } from "./queries" - -/** - * This hook creates a shipping option. - * - * @example - * import React from "react" - * import { useAdminCreateShippingOption } from "medusa-react" - * - * type CreateShippingOption = { - * name: string - * provider_id: string - * data: Record - * price_type: string - * amount: number - * } - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ regionId }: Props) => { - * const createShippingOption = useAdminCreateShippingOption() - * // ... - * - * const handleCreate = ( - * data: CreateShippingOption - * ) => { - * createShippingOption.mutate({ - * ...data, - * region_id: regionId - * }, { - * onSuccess: ({ shipping_option }) => { - * console.log(shipping_option.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - * @customNamespace Hooks.Admin.Shipping Options - * @category Mutations - */ -export const useAdminCreateShippingOption = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostShippingOptionsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostShippingOptionsReq) => - client.admin.shippingOptions.create(payload), - buildOptions(queryClient, adminShippingOptionKeys.lists(), options) - ) -} - -/** - * This hook updates a shipping option's details. - * - * @example - * import React from "react" - * import { useAdminUpdateShippingOption } from "medusa-react" - * - * type Props = { - * shippingOptionId: string - * } - * - * const ShippingOption = ({ shippingOptionId }: Props) => { - * const updateShippingOption = useAdminUpdateShippingOption( - * shippingOptionId - * ) - * // ... - * - * const handleUpdate = ( - * name: string, - * requirements: { - * id: string, - * type: string, - * amount: number - * }[] - * ) => { - * updateShippingOption.mutate({ - * name, - * requirements - * }, { - * onSuccess: ({ shipping_option }) => { - * console.log(shipping_option.requirements) - * } - * }) - * } - * - * // ... - * } - * - * export default ShippingOption - * - * @customNamespace Hooks.Admin.Shipping Options - * @category Mutations - */ -export const useAdminUpdateShippingOption = ( - /** - * The shipping option's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostShippingOptionsOptionReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostShippingOptionsOptionReq) => - client.admin.shippingOptions.update(id, payload), - buildOptions( - queryClient, - [adminShippingOptionKeys.lists(), adminShippingOptionKeys.detail(id)], - options - ) - ) -} - -/** - * This hook deletes a shipping option. Once deleted, it can't be used when creating orders or returns. - * - * @example - * import React from "react" - * import { useAdminDeleteShippingOption } from "medusa-react" - * - * type Props = { - * shippingOptionId: string - * } - * - * const ShippingOption = ({ shippingOptionId }: Props) => { - * const deleteShippingOption = useAdminDeleteShippingOption( - * shippingOptionId - * ) - * // ... - * - * const handleDelete = () => { - * deleteShippingOption.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default ShippingOption - * - * @customNamespace Hooks.Admin.Shipping Options - * @category Mutations - */ -export const useAdminDeleteShippingOption = ( - /** - * The shipping option's ID. - */ - id: string, - options?: UseMutationOptions -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.shippingOptions.delete(id), - buildOptions( - queryClient, - [adminShippingOptionKeys.lists(), adminShippingOptionKeys.detail(id)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/shipping-options/queries.ts b/packages/medusa-react/src/hooks/admin/shipping-options/queries.ts deleted file mode 100644 index 04c1ef1fc2..0000000000 --- a/packages/medusa-react/src/hooks/admin/shipping-options/queries.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { - AdminGetShippingOptionsParams, - AdminShippingOptionsListRes, - AdminShippingOptionsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_SHIPPING_OPTIONS_QUERY_KEY = `admin_shipping_options` as const - -export const adminShippingOptionKeys = queryKeysFactory( - ADMIN_SHIPPING_OPTIONS_QUERY_KEY -) - -type ShippingOptionQueryKeys = typeof adminShippingOptionKeys - -/** - * This hook retrieves a list of shipping options. The shipping options can be filtered by fields such as `region_id` - * or `is_return` passed in the `query` parameter. - * - * @example - * import React from "react" - * import { useAdminShippingOptions } from "medusa-react" - * - * const ShippingOptions = () => { - * const { - * shipping_options, - * isLoading - * } = useAdminShippingOptions() - * - * return ( - *
- * {isLoading && Loading...} - * {shipping_options && !shipping_options.length && ( - * No Shipping Options - * )} - * {shipping_options && shipping_options.length > 0 && ( - *
    - * {shipping_options.map((option) => ( - *
  • {option.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ShippingOptions - * - * @customNamespace Hooks.Admin.Shipping Options - * @category Queries - */ -export const useAdminShippingOptions = ( - /** - * Filters to apply on the retrieved shipping options. - */ - query?: AdminGetShippingOptionsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminShippingOptionKeys.list(query), - () => client.admin.shippingOptions.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a shipping option's details. - * - * @example - * import React from "react" - * import { useAdminShippingOption } from "medusa-react" - * - * type Props = { - * shippingOptionId: string - * } - * - * const ShippingOption = ({ shippingOptionId }: Props) => { - * const { - * shipping_option, - * isLoading - * } = useAdminShippingOption( - * shippingOptionId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {shipping_option && {shipping_option.name}} - *
- * ) - * } - * - * export default ShippingOption - * - * @customNamespace Hooks.Admin.Shipping Options - * @category Queries - */ -export const useAdminShippingOption = ( - /** - * The shipping option's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminShippingOptionKeys.detail(id), - () => client.admin.shippingOptions.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/shipping-profiles/index.ts b/packages/medusa-react/src/hooks/admin/shipping-profiles/index.ts deleted file mode 100644 index 76f5aaf3b9..0000000000 --- a/packages/medusa-react/src/hooks/admin/shipping-profiles/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Shipping Profile API Routes](https://docs.medusajs.com/api/admin#shipping-profiles). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A shipping profile is used to group products that can be shipped in the same manner. - * They are created by the admin and they're not associated with a fulfillment provider. - * - * Related Guide: [Shipping Profile architecture](https://docs.medusajs.com/modules/carts-and-checkout/shipping#shipping-profile). - * - * @customNamespace Hooks.Admin.Shipping Profiles - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/shipping-profiles/mutations.ts b/packages/medusa-react/src/hooks/admin/shipping-profiles/mutations.ts deleted file mode 100644 index b441d1a185..0000000000 --- a/packages/medusa-react/src/hooks/admin/shipping-profiles/mutations.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { - AdminDeleteShippingProfileRes, - AdminPostShippingProfilesProfileReq, - AdminPostShippingProfilesReq, - AdminShippingProfilesRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminShippingProfileKeys } from "./queries" - -/** - * This hook creates a shipping profile. - * - * @example - * import React from "react" - * import { ShippingProfileType } from "@medusajs/medusa" - * import { useAdminCreateShippingProfile } from "medusa-react" - * - * const CreateShippingProfile = () => { - * const createShippingProfile = useAdminCreateShippingProfile() - * // ... - * - * const handleCreate = ( - * name: string, - * type: ShippingProfileType - * ) => { - * createShippingProfile.mutate({ - * name, - * type - * }, { - * onSuccess: ({ shipping_profile }) => { - * console.log(shipping_profile.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateShippingProfile - * - * @customNamespace Hooks.Admin.Shipping Profiles - * @category Mutations - */ -export const useAdminCreateShippingProfile = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostShippingProfilesReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostShippingProfilesReq) => - client.admin.shippingProfiles.create(payload), - buildOptions(queryClient, adminShippingProfileKeys.lists(), options) - ) -} - -/** - * This hook updates a shipping profile's details. - * - * @example - * import React from "react" - * import { ShippingProfileType } from "@medusajs/medusa" - * import { useAdminUpdateShippingProfile } from "medusa-react" - * - * type Props = { - * shippingProfileId: string - * } - * - * const ShippingProfile = ({ shippingProfileId }: Props) => { - * const updateShippingProfile = useAdminUpdateShippingProfile( - * shippingProfileId - * ) - * // ... - * - * const handleUpdate = ( - * name: string, - * type: ShippingProfileType - * ) => { - * updateShippingProfile.mutate({ - * name, - * type - * }, { - * onSuccess: ({ shipping_profile }) => { - * console.log(shipping_profile.name) - * } - * }) - * } - * - * // ... - * } - * - * export default ShippingProfile - * - * @customNamespace Hooks.Admin.Shipping Profiles - * @category Mutations - */ -export const useAdminUpdateShippingProfile = ( - /** - * The shipping profile's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostShippingProfilesProfileReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostShippingProfilesProfileReq) => - client.admin.shippingProfiles.update(id, payload), - buildOptions( - queryClient, - [adminShippingProfileKeys.lists(), adminShippingProfileKeys.detail(id)], - options - ) - ) -} - -/** - * This hook deletes a shipping profile. Associated shipping options are deleted as well. - * - * @example - * import React from "react" - * import { useAdminDeleteShippingProfile } from "medusa-react" - * - * type Props = { - * shippingProfileId: string - * } - * - * const ShippingProfile = ({ shippingProfileId }: Props) => { - * const deleteShippingProfile = useAdminDeleteShippingProfile( - * shippingProfileId - * ) - * // ... - * - * const handleDelete = () => { - * deleteShippingProfile.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default ShippingProfile - * - * @customNamespace Hooks.Admin.Shipping Profiles - * @category Mutations - */ -export const useAdminDeleteShippingProfile = ( - /** - * The shipping profile's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - void - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.shippingProfiles.delete(id), - buildOptions( - queryClient, - [adminShippingProfileKeys.lists(), adminShippingProfileKeys.detail(id)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/shipping-profiles/queries.ts b/packages/medusa-react/src/hooks/admin/shipping-profiles/queries.ts deleted file mode 100644 index f70f6a8742..0000000000 --- a/packages/medusa-react/src/hooks/admin/shipping-profiles/queries.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { - AdminShippingProfilesListRes, - AdminShippingProfilesRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_COLLECTIONS_QUERY_KEY = `admin_shippingProfiles` as const - -export const adminShippingProfileKeys = queryKeysFactory( - ADMIN_COLLECTIONS_QUERY_KEY -) - -type ShippingProfileQueryKeys = typeof adminShippingProfileKeys - -/** - * This hook retrieves a list of shipping profiles. - * - * @example - * import React from "react" - * import { useAdminShippingProfiles } from "medusa-react" - * - * const ShippingProfiles = () => { - * const { - * shipping_profiles, - * isLoading - * } = useAdminShippingProfiles() - * - * return ( - *
- * {isLoading && Loading...} - * {shipping_profiles && !shipping_profiles.length && ( - * No Shipping Profiles - * )} - * {shipping_profiles && shipping_profiles.length > 0 && ( - *
    - * {shipping_profiles.map((profile) => ( - *
  • {profile.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ShippingProfiles - * - * @customNamespace Hooks.Admin.Shipping Profiles - * @category Queries - */ -export const useAdminShippingProfiles = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminShippingProfileKeys.lists(), - () => client.admin.shippingProfiles.list(), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a shipping profile's details. - * - * @example - * import React from "react" - * import { useAdminShippingProfile } from "medusa-react" - * - * type Props = { - * shippingProfileId: string - * } - * - * const ShippingProfile = ({ shippingProfileId }: Props) => { - * const { - * shipping_profile, - * isLoading - * } = useAdminShippingProfile( - * shippingProfileId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {shipping_profile && ( - * {shipping_profile.name} - * )} - *
- * ) - * } - * - * export default ShippingProfile - * - * @customNamespace Hooks.Admin.Shipping Profiles - * @category Queries - */ -export const useAdminShippingProfile = ( - /** - * The shipping option's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminShippingProfileKeys.detail(id), - () => client.admin.shippingProfiles.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/stock-locations/index.ts b/packages/medusa-react/src/hooks/admin/stock-locations/index.ts deleted file mode 100644 index 4dd98aed56..0000000000 --- a/packages/medusa-react/src/hooks/admin/stock-locations/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Stock Location API Routes](https://docs.medusajs.com/api/admin#stock-locations). - * To use these hooks, make sure to install the - * [@medusajs/stock-location](https://docs.medusajs.com/modules/multiwarehouse/install-modules#stock-location-module) module in your Medusa backend. - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A stock location, provided by the [Stock Location module](https://docs.medusajs.com/modules/multiwarehouse/stock-location-module), - * indicates a physical address that stock-kept items, such as physical products, can be stored in. - * An admin can create and manage available stock locations. - * - * Related Guide: [How to manage stock locations](https://docs.medusajs.com/modules/multiwarehouse/admin/manage-stock-locations). - * - * @customNamespace Hooks.Admin.Stock Locations - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/stock-locations/mutations.ts b/packages/medusa-react/src/hooks/admin/stock-locations/mutations.ts deleted file mode 100644 index 3ace5d1e9c..0000000000 --- a/packages/medusa-react/src/hooks/admin/stock-locations/mutations.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { - AdminPostStockLocationsLocationReq, - AdminPostStockLocationsReq, - AdminStockLocationsDeleteRes, - AdminStockLocationsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { adminProductKeys } from "../products" -import { adminVariantKeys } from "../variants" -import { adminStockLocationsKeys } from "./queries" - -/** - * This hook creates a stock location. - * - * @example - * import React from "react" - * import { useAdminCreateStockLocation } from "medusa-react" - * - * const CreateStockLocation = () => { - * const createStockLocation = useAdminCreateStockLocation() - * // ... - * - * const handleCreate = (name: string) => { - * createStockLocation.mutate({ - * name, - * }, { - * onSuccess: ({ stock_location }) => { - * console.log(stock_location.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateStockLocation - * - * @customNamespace Hooks.Admin.Stock Locations - * @category Mutations - */ -export const useAdminCreateStockLocation = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostStockLocationsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostStockLocationsReq) => - client.admin.stockLocations.create(payload), - buildOptions(queryClient, [adminStockLocationsKeys.lists()], options) - ) -} - -/** - * This hook updates a stock location's details. - * - * @example - * import React from "react" - * import { useAdminUpdateStockLocation } from "medusa-react" - * - * type Props = { - * stockLocationId: string - * } - * - * const StockLocation = ({ stockLocationId }: Props) => { - * const updateLocation = useAdminUpdateStockLocation( - * stockLocationId - * ) - * // ... - * - * const handleUpdate = ( - * name: string - * ) => { - * updateLocation.mutate({ - * name - * }, { - * onSuccess: ({ stock_location }) => { - * console.log(stock_location.name) - * } - * }) - * } - * } - * - * export default StockLocation - * - * @customNamespace Hooks.Admin.Stock Locations - * @category Mutations - */ -export const useAdminUpdateStockLocation = ( - /** - * The stock location's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostStockLocationsLocationReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostStockLocationsLocationReq) => - client.admin.stockLocations.update(id, payload), - buildOptions( - queryClient, - [adminStockLocationsKeys.lists(), adminStockLocationsKeys.detail(id)], - options - ) - ) -} - -/** - * This hook deletes a stock location. - * - * @example - * import React from "react" - * import { useAdminDeleteStockLocation } from "medusa-react" - * - * type Props = { - * stockLocationId: string - * } - * - * const StockLocation = ({ stockLocationId }: Props) => { - * const deleteLocation = useAdminDeleteStockLocation( - * stockLocationId - * ) - * // ... - * - * const handleDelete = () => { - * deleteLocation.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * } - * - * export default StockLocation - * - * @customNamespace Hooks.Admin.Stock Locations - * @category Mutations - */ -export const useAdminDeleteStockLocation = ( - /** - * The stock location's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - void - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.stockLocations.delete(id), - buildOptions( - queryClient, - [ - adminStockLocationsKeys.lists(), - adminStockLocationsKeys.detail(id), - adminVariantKeys.all, - adminProductKeys.lists(), - ], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/stock-locations/queries.ts b/packages/medusa-react/src/hooks/admin/stock-locations/queries.ts deleted file mode 100644 index a5db2582fa..0000000000 --- a/packages/medusa-react/src/hooks/admin/stock-locations/queries.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { - AdminGetStockLocationsParams, - AdminStockLocationsListRes, - AdminStockLocationsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const ADMIN_STOCK_LOCATIONS_QUERY_KEY = `admin_stock_locations` as const - -export const adminStockLocationsKeys = queryKeysFactory( - ADMIN_STOCK_LOCATIONS_QUERY_KEY -) - -type StockLocationsQueryKeys = typeof adminStockLocationsKeys - -/** - * This hook retrieves a list of stock locations. The stock locations can be filtered by fields such as `name` or `created_at` passed in the `query` parameter. - * The stock locations can also be sorted or paginated. - * - * @example - * To list stock locations: - * - * ```tsx - * import React from "react" - * import { useAdminStockLocations } from "medusa-react" - * - * function StockLocations() { - * const { - * stock_locations, - * isLoading - * } = useAdminStockLocations() - * - * return ( - *
- * {isLoading && Loading...} - * {stock_locations && !stock_locations.length && ( - * No Locations - * )} - * {stock_locations && stock_locations.length > 0 && ( - *
    - * {stock_locations.map( - * (location) => ( - *
  • {location.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default StockLocations - * ``` - * - * To specify relations that should be retrieved within the stock locations: - * - * ```tsx - * import React from "react" - * import { useAdminStockLocations } from "medusa-react" - * - * function StockLocations() { - * const { - * stock_locations, - * isLoading - * } = useAdminStockLocations({ - * expand: "address" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {stock_locations && !stock_locations.length && ( - * No Locations - * )} - * {stock_locations && stock_locations.length > 0 && ( - *
    - * {stock_locations.map( - * (location) => ( - *
  • {location.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default StockLocations - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminStockLocations } from "medusa-react" - * - * function StockLocations() { - * const { - * stock_locations, - * limit, - * offset, - * isLoading - * } = useAdminStockLocations({ - * expand: "address", - * limit: 10, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {stock_locations && !stock_locations.length && ( - * No Locations - * )} - * {stock_locations && stock_locations.length > 0 && ( - *
    - * {stock_locations.map( - * (location) => ( - *
  • {location.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default StockLocations - * ``` - * - * @customNamespace Hooks.Admin.Stock Locations - * @category Queries - */ -export const useAdminStockLocations = ( - /** - * Filters and pagination configurations to apply on the retrieved stock locations. - */ - query?: AdminGetStockLocationsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - - const { data, ...rest } = useQuery( - adminStockLocationsKeys.list(query), - () => client.admin.stockLocations.list(query), - options - ) - - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a stock location's details. - * - * @example - * import React from "react" - * import { useAdminStockLocation } from "medusa-react" - * - * type Props = { - * stockLocationId: string - * } - * - * const StockLocation = ({ stockLocationId }: Props) => { - * const { - * stock_location, - * isLoading - * } = useAdminStockLocation(stockLocationId) - * - * return ( - *
- * {isLoading && Loading...} - * {stock_location && ( - * {stock_location.name} - * )} - *
- * ) - * } - * - * export default StockLocation - * - * @customNamespace Hooks.Admin.Stock Locations - * @category Queries - */ -export const useAdminStockLocation = ( - /** - * The stock location's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - - const { data, ...rest } = useQuery( - adminStockLocationsKeys.detail(id), - () => client.admin.stockLocations.retrieve(id), - options - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/store/index.ts b/packages/medusa-react/src/hooks/admin/store/index.ts deleted file mode 100644 index 8654acfe30..0000000000 --- a/packages/medusa-react/src/hooks/admin/store/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Store API Routes](https://docs.medusajs.com/api/admin#store). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A store indicates the general configurations and details about the commerce store. By default, there's only one store in the Medusa backend. - * Admins can manage the store and its details or configurations. - * - * @customNamespace Hooks.Admin.Stores - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/store/mutations.ts b/packages/medusa-react/src/hooks/admin/store/mutations.ts deleted file mode 100644 index 1f3e1db1e5..0000000000 --- a/packages/medusa-react/src/hooks/admin/store/mutations.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { AdminPostStoreReq, AdminStoresRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminStoreKeys } from "./queries" - -/** - * This hook updates the store's details. - * - * @example - * import React from "react" - * import { useAdminUpdateStore } from "medusa-react" - * - * function Store() { - * const updateStore = useAdminUpdateStore() - * // ... - * - * const handleUpdate = ( - * name: string - * ) => { - * updateStore.mutate({ - * name - * }, { - * onSuccess: ({ store }) => { - * console.log(store.name) - * } - * }) - * } - * } - * - * export default Store - * - * @customNamespace Hooks.Admin.Stores - * @category Mutations - */ -export const useAdminUpdateStore = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostStoreReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostStoreReq) => client.admin.store.update(payload), - buildOptions(queryClient, adminStoreKeys.details(), options) - ) -} - -/** - * This hook adds a currency code to the available currencies in a store. This doesn't create new currencies, as currencies are defined within the Medusa backend. - * To create a currency, you can [create a migration](https://docs.medusajs.com/development/entities/migrations/create) that inserts the currency into the database. - * - * @typeParamDefinition string - The code of the currency to add to the store. - * - * @example - * import React from "react" - * import { useAdminAddStoreCurrency } from "medusa-react" - * - * const Store = () => { - * const addCurrency = useAdminAddStoreCurrency() - * // ... - * - * const handleAdd = (code: string) => { - * addCurrency.mutate(code, { - * onSuccess: ({ store }) => { - * console.log(store.currencies) - * } - * }) - * } - * - * // ... - * } - * - * export default Store - * - * @customNamespace Hooks.Admin.Stores - * @category Mutations - */ -export const useAdminAddStoreCurrency = ( - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (currency_code: string) => client.admin.store.addCurrency(currency_code), - buildOptions(queryClient, adminStoreKeys.details(), options) - ) -} - -/** - * This hook deletes a currency code from the available currencies in a store. This doesn't completely - * delete the currency and it can be added again later to the store. - * - * @typeParamDefinition string - The code of the currency to remove from the store. - * - * @example - * import React from "react" - * import { useAdminDeleteStoreCurrency } from "medusa-react" - * - * const Store = () => { - * const deleteCurrency = useAdminDeleteStoreCurrency() - * // ... - * - * const handleAdd = (code: string) => { - * deleteCurrency.mutate(code, { - * onSuccess: ({ store }) => { - * console.log(store.currencies) - * } - * }) - * } - * - * // ... - * } - * - * export default Store - * - * @customNamespace Hooks.Admin.Stores - * @category Mutations - */ -export const useAdminDeleteStoreCurrency = ( - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (currency_code: string) => client.admin.store.deleteCurrency(currency_code), - buildOptions(queryClient, adminStoreKeys.details(), options) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/store/queries.ts b/packages/medusa-react/src/hooks/admin/store/queries.ts deleted file mode 100644 index b07439c8f7..0000000000 --- a/packages/medusa-react/src/hooks/admin/store/queries.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { - AdminExtendedStoresRes, - AdminPaymentProvidersList, - AdminTaxProvidersList, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_STORE_QUERY_KEY = `admin_store` as const - -export const adminStoreKeys = queryKeysFactory(ADMIN_STORE_QUERY_KEY) - -type StoreQueryKeys = typeof adminStoreKeys - -/** - * This hook retrieves a list of available payment providers in a store. - * - * @example - * import React from "react" - * import { useAdminStorePaymentProviders } from "medusa-react" - * - * const PaymentProviders = () => { - * const { - * payment_providers, - * isLoading - * } = useAdminStorePaymentProviders() - * - * return ( - *
- * {isLoading && Loading...} - * {payment_providers && !payment_providers.length && ( - * No Payment Providers - * )} - * {payment_providers && - * payment_providers.length > 0 &&( - *
    - * {payment_providers.map((provider) => ( - *
  • {provider.id}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default PaymentProviders - * - * @customNamespace Hooks.Admin.Stores - * @category Queries - */ -export const useAdminStorePaymentProviders = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminStoreKeys.detail("payment_providers"), - () => client.admin.store.listPaymentProviders(), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a list of available tax providers in a store. - * - * @example - * import React from "react" - * import { useAdminStoreTaxProviders } from "medusa-react" - * - * const TaxProviders = () => { - * const { - * tax_providers, - * isLoading - * } = useAdminStoreTaxProviders() - * - * return ( - *
- * {isLoading && Loading...} - * {tax_providers && !tax_providers.length && ( - * No Tax Providers - * )} - * {tax_providers && - * tax_providers.length > 0 &&( - *
    - * {tax_providers.map((provider) => ( - *
  • {provider.id}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default TaxProviders - * - * @customNamespace Hooks.Admin.Stores - * @category Queries - */ -export const useAdminStoreTaxProviders = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminStoreKeys.detail("tax_providers"), - () => client.admin.store.listTaxProviders(), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves the store's details. - * - * @example - * import React from "react" - * import { useAdminStore } from "medusa-react" - * - * const Store = () => { - * const { - * store, - * isLoading - * } = useAdminStore() - * - * return ( - *
- * {isLoading && Loading...} - * {store && {store.name}} - *
- * ) - * } - * - * export default Store - * - * @customNamespace Hooks.Admin.Stores - * @category Queries - */ -export const useAdminStore = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminStoreKeys.details(), - () => client.admin.store.retrieve(), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/swaps/index.ts b/packages/medusa-react/src/hooks/admin/swaps/index.ts deleted file mode 100644 index 0b4942db3c..0000000000 --- a/packages/medusa-react/src/hooks/admin/swaps/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Swap API Routes](https://docs.medusajs.com/api/admin#swaps). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A swap is created by a customer or an admin to exchange an item with a new one. - * Creating a swap implicitely includes creating a return for the item being exchanged. - * - * Related Guide: [How to manage swaps](https://docs.medusajs.com/modules/orders/admin/manage-swaps) - * - * @customNamespace Hooks.Admin.Swaps - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/swaps/mutations.ts b/packages/medusa-react/src/hooks/admin/swaps/mutations.ts deleted file mode 100644 index 01feca30e9..0000000000 --- a/packages/medusa-react/src/hooks/admin/swaps/mutations.ts +++ /dev/null @@ -1,438 +0,0 @@ -import { - AdminOrdersRes, - AdminPostOrdersOrderSwapsReq, - AdminPostOrdersOrderSwapsSwapFulfillmentsReq, - AdminPostOrdersOrderSwapsSwapShipmentsReq, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { adminOrderKeys, adminProductKeys, adminVariantKeys } from ".." -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminSwapKeys } from "./queries" - -/** - * This hook creates a swap for an order. This includes creating a return that is associated with the swap. - * - * @example - * import React from "react" - * import { useAdminCreateSwap } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const CreateSwap = ({ orderId }: Props) => { - * const createSwap = useAdminCreateSwap(orderId) - * // ... - * - * const handleCreate = ( - * returnItems: { - * item_id: string, - * quantity: number - * }[] - * ) => { - * createSwap.mutate({ - * return_items: returnItems - * }, { - * onSuccess: ({ order }) => { - * console.log(order.swaps) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateSwap - * - * @customNamespace Hooks.Admin.Swaps - * @category Mutations - */ -export const useAdminCreateSwap = ( - /** - * The associated order's ID. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostOrdersOrderSwapsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostOrdersOrderSwapsReq) => - client.admin.orders.createSwap(orderId, payload), - buildOptions( - queryClient, - [adminOrderKeys.detail(orderId), adminSwapKeys.lists()], - options - ) - ) -} - -/** - * This hook cancels a swap and change its status. - * - * @typeParamDefinition string - The swap's ID. - * - * @example - * import React from "react" - * import { useAdminCancelSwap } from "medusa-react" - * - * type Props = { - * orderId: string, - * swapId: string - * } - * - * const Swap = ({ - * orderId, - * swapId - * }: Props) => { - * const cancelSwap = useAdminCancelSwap( - * orderId - * ) - * // ... - * - * const handleCancel = () => { - * cancelSwap.mutate(swapId, { - * onSuccess: ({ order }) => { - * console.log(order.swaps) - * } - * }) - * } - * - * // ... - * } - * - * export default Swap - * - * @customNamespace Hooks.Admin.Swaps - * @category Mutations - */ -export const useAdminCancelSwap = ( - /** - * The associated order's ID. - */ - orderId: string, - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (swapId: string) => client.admin.orders.cancelSwap(orderId, swapId), - buildOptions( - queryClient, - [adminOrderKeys.detail(orderId), adminSwapKeys.lists()], - options - ) - ) -} - -export type AdminFulfillSwapReq = AdminPostOrdersOrderSwapsSwapFulfillmentsReq & { - /** - * The swap's ID. - */ - swap_id: string -} - -/** - * This hook creates a Fulfillment for a Swap and change its fulfillment status to `fulfilled`. If it requires any additional actions, - * its fulfillment status may change to `requires_action`. - * - * @example - * import React from "react" - * import { useAdminFulfillSwap } from "medusa-react" - * - * type Props = { - * orderId: string, - * swapId: string - * } - * - * const Swap = ({ - * orderId, - * swapId - * }: Props) => { - * const fulfillSwap = useAdminFulfillSwap( - * orderId - * ) - * // ... - * - * const handleFulfill = () => { - * fulfillSwap.mutate({ - * swap_id: swapId, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.swaps) - * } - * }) - * } - * - * // ... - * } - * - * export default Swap - * - * @customNamespace Hooks.Admin.Swaps - * @category Mutations - */ -export const useAdminFulfillSwap = ( - /** - * The associated order's ID. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - AdminFulfillSwapReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - ({ - swap_id, - ...payload - }: AdminFulfillSwapReq) => - client.admin.orders.fulfillSwap(orderId, swap_id, payload), - buildOptions( - queryClient, - [ - adminOrderKeys.detail(orderId), - adminSwapKeys.lists(), - adminVariantKeys.all, - adminProductKeys.lists(), - ], - options - ) - ) -} - -export type AdminCreateSwapShipmentReq = AdminPostOrdersOrderSwapsSwapShipmentsReq & { - /** - * The swap's ID. - */ - swap_id: string -} - -/** - * This hook creates a shipment for a swap and mark its fulfillment as shipped. This changes the swap's fulfillment status - * to either `shipped` or `partially_shipped`, depending on whether all the items were shipped. - * - * @example - * import React from "react" - * import { useAdminCreateSwapShipment } from "medusa-react" - * - * type Props = { - * orderId: string, - * swapId: string - * } - * - * const Swap = ({ - * orderId, - * swapId - * }: Props) => { - * const createShipment = useAdminCreateSwapShipment( - * orderId - * ) - * // ... - * - * const handleCreateShipment = ( - * fulfillmentId: string - * ) => { - * createShipment.mutate({ - * swap_id: swapId, - * fulfillment_id: fulfillmentId, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.swaps) - * } - * }) - * } - * - * // ... - * } - * - * export default Swap - * - * @customNamespace Hooks.Admin.Swaps - * @category Mutations - */ -export const useAdminCreateSwapShipment = ( - /** - * The associated order's ID. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - AdminCreateSwapShipmentReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - ({ - swap_id, - ...payload - }: AdminCreateSwapShipmentReq) => - client.admin.orders.createSwapShipment(orderId, swap_id, payload), - buildOptions(queryClient, adminOrderKeys.detail(orderId), options) - ) -} - -/** - * This hook process a swap's payment either by refunding or issuing a payment. This depends on the `difference_due` - * of the swap. If `difference_due` is negative, the amount is refunded. If `difference_due` is positive, the amount is captured. - * - * @typeParamDefinition string - The swap's ID. - * - * @example - * import React from "react" - * import { useAdminProcessSwapPayment } from "medusa-react" - * - * type Props = { - * orderId: string, - * swapId: string - * } - * - * const Swap = ({ - * orderId, - * swapId - * }: Props) => { - * const processPayment = useAdminProcessSwapPayment( - * orderId - * ) - * // ... - * - * const handleProcessPayment = () => { - * processPayment.mutate(swapId, { - * onSuccess: ({ order }) => { - * console.log(order.swaps) - * } - * }) - * } - * - * // ... - * } - * - * export default Swap - * - * @customNamespace Hooks.Admin.Swaps - * @category Mutations - */ -export const useAdminProcessSwapPayment = ( - /** - * The associated order's ID. - */ - orderId: string, - options?: UseMutationOptions, Error, string> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (swapId: string) => client.admin.orders.processSwapPayment(orderId, swapId), - buildOptions( - queryClient, - [adminOrderKeys.detail(orderId), adminSwapKeys.lists()], - options - ) - ) -} - -/** - * The details of the swap's fulfillment to cancel. - */ -export type AdminCancelSwapFulfillmentReq = { - /** - * The swap's ID. - */ - swap_id: string - /** - * The fulfillment's ID. - */ - fulfillment_id: string -} - -/** - * This hook cancels a swap's fulfillment and change its fulfillment status to `canceled`. - * - * @example - * import React from "react" - * import { useAdminCancelSwapFulfillment } from "medusa-react" - * - * type Props = { - * orderId: string, - * swapId: string - * } - * - * const Swap = ({ - * orderId, - * swapId - * }: Props) => { - * const cancelFulfillment = useAdminCancelSwapFulfillment( - * orderId - * ) - * // ... - * - * const handleCancelFulfillment = ( - * fulfillmentId: string - * ) => { - * cancelFulfillment.mutate({ - * swap_id: swapId, - * fulfillment_id: fulfillmentId, - * }) - * } - * - * // ... - * } - * - * export default Swap - * - * @customNamespace Hooks.Admin.Swaps - * @category Mutations - */ -export const useAdminCancelSwapFulfillment = ( - /** - * The associated order's ID. - */ - orderId: string, - options?: UseMutationOptions< - Response, - Error, - { swap_id: string; fulfillment_id: string } - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - ({ - swap_id, - fulfillment_id, - }: { - swap_id: string - fulfillment_id: string - }) => - client.admin.orders.cancelSwapFulfillment( - orderId, - swap_id, - fulfillment_id - ), - buildOptions( - queryClient, - [adminOrderKeys.detail(orderId), adminSwapKeys.lists()], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/swaps/queries.ts b/packages/medusa-react/src/hooks/admin/swaps/queries.ts deleted file mode 100644 index 50c9374877..0000000000 --- a/packages/medusa-react/src/hooks/admin/swaps/queries.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { - AdminGetSwapsParams, - AdminSwapsListRes, - AdminSwapsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_SWAPS_QUERY_KEY = `admin_swaps` as const - -export const adminSwapKeys = queryKeysFactory(ADMIN_SWAPS_QUERY_KEY) - -type SwapsQueryKey = typeof adminSwapKeys - -/** - * This hook retrieves a list of swaps. The swaps can be paginated. - * - * @example - * To list swaps: - * - * ```tsx - * import React from "react" - * import { useAdminSwaps } from "medusa-react" - * - * const Swaps = () => { - * const { swaps, isLoading } = useAdminSwaps() - * - * return ( - *
- * {isLoading && Loading...} - * {swaps && !swaps.length && No Swaps} - * {swaps && swaps.length > 0 && ( - *
    - * {swaps.map((swap) => ( - *
  • {swap.payment_status}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Swaps - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminSwaps } from "medusa-react" - * - * const Swaps = () => { - * const { - * swaps, - * limit, - * offset, - * isLoading - * } = useAdminSwaps({ - * limit: 10, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {swaps && !swaps.length && No Swaps} - * {swaps && swaps.length > 0 && ( - *
    - * {swaps.map((swap) => ( - *
  • {swap.payment_status}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Swaps - * ``` - * - * @customNamespace Hooks.Admin.Swaps - * @category Queries - */ -export const useAdminSwaps = ( - /** - * Pagination configurations to apply on the retrieved swaps. - */ - query?: AdminGetSwapsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminSwapKeys.list(query), - () => client.admin.swaps.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a swap's details. - * - * @example - * import React from "react" - * import { useAdminSwap } from "medusa-react" - * - * type Props = { - * swapId: string - * } - * - * const Swap = ({ swapId }: Props) => { - * const { swap, isLoading } = useAdminSwap(swapId) - * - * return ( - *
- * {isLoading && Loading...} - * {swap && {swap.id}} - *
- * ) - * } - * - * export default Swap - * - * @customNamespace Hooks.Admin.Swaps - * @category Queries - */ -export const useAdminSwap = ( - /** - * The swap's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminSwapKeys.detail(id), - () => client.admin.swaps.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/tax-rates/index.ts b/packages/medusa-react/src/hooks/admin/tax-rates/index.ts deleted file mode 100644 index 193ac9e48c..0000000000 --- a/packages/medusa-react/src/hooks/admin/tax-rates/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin Tax Rate API Routes](https://docs.medusajs.com/api/admin#tax-rates). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Each region has at least a default tax rate. Admins can create and manage additional tax rates that can be applied for certain conditions, such as for specific product types. - * - * Related Guide: [How to manage tax rates](https://docs.medusajs.com/modules/taxes/admin/manage-tax-rates). - * - * @customNamespace Hooks.Admin.Tax Rates - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/tax-rates/mutations.ts b/packages/medusa-react/src/hooks/admin/tax-rates/mutations.ts deleted file mode 100644 index 5968aaa111..0000000000 --- a/packages/medusa-react/src/hooks/admin/tax-rates/mutations.ts +++ /dev/null @@ -1,555 +0,0 @@ -import { - AdminDeleteTaxRatesTaxRateProductsReq, - AdminDeleteTaxRatesTaxRateProductTypesReq, - AdminDeleteTaxRatesTaxRateShippingOptionsReq, - AdminPostTaxRatesReq, - AdminPostTaxRatesTaxRateProductsReq, - AdminPostTaxRatesTaxRateProductTypesReq, - AdminPostTaxRatesTaxRateReq, - AdminPostTaxRatesTaxRateShippingOptionsReq, - AdminTaxRatesDeleteRes, - AdminTaxRatesRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" -import { adminTaxRateKeys } from "./queries" - -/** - * This hook creates a tax rate. - * - * @example - * import React from "react" - * import { useAdminCreateTaxRate } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const CreateTaxRate = ({ regionId }: Props) => { - * const createTaxRate = useAdminCreateTaxRate() - * // ... - * - * const handleCreate = ( - * code: string, - * name: string, - * rate: number - * ) => { - * createTaxRate.mutate({ - * code, - * name, - * region_id: regionId, - * rate, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateTaxRate - * - * @customNamespace Hooks.Admin.Tax Rates - * @category Mutations - */ -export const useAdminCreateTaxRate = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostTaxRatesReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - return useMutation( - (payload: AdminPostTaxRatesReq) => client.admin.taxRates.create(payload), - buildOptions(queryClient, adminTaxRateKeys.lists(), options) - ) -} - -/** - * This hook updates a tax rate's details. - * - * @example - * import React from "react" - * import { useAdminUpdateTaxRate } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const updateTaxRate = useAdminUpdateTaxRate(taxRateId) - * // ... - * - * const handleUpdate = ( - * name: string - * ) => { - * updateTaxRate.mutate({ - * name - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.name) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - * @customNamespace Hooks.Admin.Tax Rates - * @category Mutations - */ -export const useAdminUpdateTaxRate = ( - /** - * The tax rate's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostTaxRatesTaxRateReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostTaxRatesTaxRateReq) => - client.admin.taxRates.update(id, payload), - buildOptions( - queryClient, - [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], - options - ) - ) -} - -/** - * This hook deletes a tax rate. Resources associated with the tax rate, such as products or product types, are not deleted. - * - * @example - * import React from "react" - * import { useAdminDeleteTaxRate } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const deleteTaxRate = useAdminDeleteTaxRate(taxRateId) - * // ... - * - * const handleDelete = () => { - * deleteTaxRate.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - * @customNamespace Hooks.Admin.Tax Rates - * @category Mutations - */ -export const useAdminDeleteTaxRate = ( - /** - * The tax rate's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.taxRates.delete(id), - buildOptions( - queryClient, - [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], - options - ) - ) -} - -/** - * This hook adds products to a tax rate. - * - * @example - * import React from "react" - * import { useAdminCreateProductTaxRates } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const addProduct = useAdminCreateProductTaxRates(taxRateId) - * // ... - * - * const handleAddProduct = (productIds: string[]) => { - * addProduct.mutate({ - * products: productIds, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.products) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - * @customNamespace Hooks.Admin.Tax Rates - * @category Mutations - */ -export const useAdminCreateProductTaxRates = ( - /** - * The tax rate's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostTaxRatesTaxRateProductsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostTaxRatesTaxRateProductsReq) => - client.admin.taxRates.addProducts(id, payload), - buildOptions( - queryClient, - [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], - options - ) - ) -} - -/** - * This hook removes products from a tax rate. This only removes the association between the products and the tax rate. It does not delete the products. - * - * @example - * import React from "react" - * import { useAdminDeleteProductTaxRates } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const removeProduct = useAdminDeleteProductTaxRates(taxRateId) - * // ... - * - * const handleRemoveProduct = (productIds: string[]) => { - * removeProduct.mutate({ - * products: productIds, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.products) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - * @customNamespace Hooks.Admin.Tax Rates - * @category Mutations - */ -export const useAdminDeleteProductTaxRates = ( - /** - * The tax rate's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminDeleteTaxRatesTaxRateProductsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminDeleteTaxRatesTaxRateProductsReq) => - client.admin.taxRates.removeProducts(id, payload), - buildOptions( - queryClient, - [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], - options - ) - ) -} - -/** - * This hook adds product types to a tax rate. - * - * @example - * import React from "react" - * import { - * useAdminCreateProductTypeTaxRates, - * } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const addProductTypes = useAdminCreateProductTypeTaxRates( - * taxRateId - * ) - * // ... - * - * const handleAddProductTypes = (productTypeIds: string[]) => { - * addProductTypes.mutate({ - * product_types: productTypeIds, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.product_types) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - * @customNamespace Hooks.Admin.Tax Rates - * @category Mutations - */ -export const useAdminCreateProductTypeTaxRates = ( - /** - * The tax rate's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostTaxRatesTaxRateProductTypesReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostTaxRatesTaxRateProductTypesReq) => - client.admin.taxRates.addProductTypes(id, payload), - buildOptions( - queryClient, - [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], - options - ) - ) -} - -/** - * This hook removes product types from a tax rate. This only removes the association between the - * product types and the tax rate. It does not delete the product types. - * - * @example - * import React from "react" - * import { - * useAdminDeleteProductTypeTaxRates, - * } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const removeProductTypes = useAdminDeleteProductTypeTaxRates( - * taxRateId - * ) - * // ... - * - * const handleRemoveProductTypes = ( - * productTypeIds: string[] - * ) => { - * removeProductTypes.mutate({ - * product_types: productTypeIds, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.product_types) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - * @customNamespace Hooks.Admin.Tax Rates - * @category Mutations - */ -export const useAdminDeleteProductTypeTaxRates = ( - /** - * The tax rate's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminDeleteTaxRatesTaxRateProductTypesReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminDeleteTaxRatesTaxRateProductTypesReq) => - client.admin.taxRates.removeProductTypes(id, payload), - buildOptions( - queryClient, - [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], - options - ) - ) -} - -/** - * This hook adds shipping options to a tax rate. - * - * @example - * import React from "react" - * import { useAdminCreateShippingTaxRates } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const addShippingOption = useAdminCreateShippingTaxRates( - * taxRateId - * ) - * // ... - * - * const handleAddShippingOptions = ( - * shippingOptionIds: string[] - * ) => { - * addShippingOption.mutate({ - * shipping_options: shippingOptionIds, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.shipping_options) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - * @customNamespace Hooks.Admin.Tax Rates - * @category Mutations - */ -export const useAdminCreateShippingTaxRates = ( - /** - * The tax rate's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminPostTaxRatesTaxRateShippingOptionsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostTaxRatesTaxRateShippingOptionsReq) => - client.admin.taxRates.addShippingOptions(id, payload), - buildOptions( - queryClient, - [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], - options - ) - ) -} - -/** - * This hook removes shipping options from a tax rate. This only removes the association between - * the shipping options and the tax rate. It does not delete the shipping options. - * - * @example - * import React from "react" - * import { useAdminDeleteShippingTaxRates } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const removeShippingOptions = useAdminDeleteShippingTaxRates( - * taxRateId - * ) - * // ... - * - * const handleRemoveShippingOptions = ( - * shippingOptionIds: string[] - * ) => { - * removeShippingOptions.mutate({ - * shipping_options: shippingOptionIds, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.shipping_options) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - * @customNamespace Hooks.Admin.Tax Rates - * @category Mutations - */ -export const useAdminDeleteShippingTaxRates = ( - /** - * The tax rate's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminDeleteTaxRatesTaxRateShippingOptionsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminDeleteTaxRatesTaxRateShippingOptionsReq) => - client.admin.taxRates.removeShippingOptions(id, payload), - buildOptions( - queryClient, - [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/tax-rates/queries.ts b/packages/medusa-react/src/hooks/admin/tax-rates/queries.ts deleted file mode 100644 index fdc390493e..0000000000 --- a/packages/medusa-react/src/hooks/admin/tax-rates/queries.ts +++ /dev/null @@ -1,225 +0,0 @@ -import { - AdminGetTaxRatesParams, - AdminTaxRatesListRes, - AdminTaxRatesRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_TAX_RATES_QUERY_KEY = `admin_tax_rates` as const - -export const adminTaxRateKeys = queryKeysFactory(ADMIN_TAX_RATES_QUERY_KEY) - -type TaxRateQueryKeys = typeof adminTaxRateKeys - -/** - * This hook retrieves a list of tax rates. The tax rates can be filtered by fields such as `name` or `rate` - * passed in the `query` parameter. The tax rates can also be paginated. - * - * @example - * To list tax rates: - * - * ```tsx - * import React from "react" - * import { useAdminTaxRates } from "medusa-react" - * - * const TaxRates = () => { - * const { - * tax_rates, - * isLoading - * } = useAdminTaxRates() - * - * return ( - *
- * {isLoading && Loading...} - * {tax_rates && !tax_rates.length && ( - * No Tax Rates - * )} - * {tax_rates && tax_rates.length > 0 && ( - *
    - * {tax_rates.map((tax_rate) => ( - *
  • {tax_rate.code}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default TaxRates - * ``` - * - * To specify relations that should be retrieved within the tax rates: - * - * ```tsx - * import React from "react" - * import { useAdminTaxRates } from "medusa-react" - * - * const TaxRates = () => { - * const { - * tax_rates, - * isLoading - * } = useAdminTaxRates({ - * expand: ["shipping_options"] - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {tax_rates && !tax_rates.length && ( - * No Tax Rates - * )} - * {tax_rates && tax_rates.length > 0 && ( - *
    - * {tax_rates.map((tax_rate) => ( - *
  • {tax_rate.code}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default TaxRates - * ``` - * - * By default, only the first `50` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminTaxRates } from "medusa-react" - * - * const TaxRates = () => { - * const { - * tax_rates, - * limit, - * offset, - * isLoading - * } = useAdminTaxRates({ - * expand: ["shipping_options"], - * limit: 10, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {tax_rates && !tax_rates.length && ( - * No Tax Rates - * )} - * {tax_rates && tax_rates.length > 0 && ( - *
    - * {tax_rates.map((tax_rate) => ( - *
  • {tax_rate.code}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default TaxRates - * ``` - * - * @customNamespace Hooks.Admin.Tax Rates - * @category Queries - */ -export const useAdminTaxRates = ( - /** - * Filters and pagination configurations applied to the retrieved tax rates. - */ - query?: AdminGetTaxRatesParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminTaxRateKeys.list(query), - () => client.admin.taxRates.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a tax rate's details. - * - * @example - * A simple example that retrieves a tax rate by its ID: - * - * ```tsx - * import React from "react" - * import { useAdminTaxRate } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const { tax_rate, isLoading } = useAdminTaxRate(taxRateId) - * - * return ( - *
- * {isLoading && Loading...} - * {tax_rate && {tax_rate.code}} - *
- * ) - * } - * - * export default TaxRate - * ``` - * - * To specify relations that should be retrieved: - * - * ```tsx - * import React from "react" - * import { useAdminTaxRate } from "medusa-react" - * - * const TaxRate = (taxRateId: string) => { - * const { tax_rate, isLoading } = useAdminTaxRate(taxRateId, { - * expand: ["shipping_options"] - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {tax_rate && {tax_rate.code}} - *
- * ) - * } - * - * export default TaxRate - * ``` - * - * @customNamespace Hooks.Admin.Tax Rates - * @category Queries - */ -export const useAdminTaxRate = ( - /** - * The tax rate's ID. - */ - id: string, - /** - * Configurations to apply on retrieved tax rates. - */ - query?: AdminGetTaxRatesParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminTaxRateKeys.detail(id), - () => client.admin.taxRates.retrieve(id, query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/uploads/index.ts b/packages/medusa-react/src/hooks/admin/uploads/index.ts deleted file mode 100644 index a80467b2fc..0000000000 --- a/packages/medusa-react/src/hooks/admin/uploads/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @packageDocumentation - * - * Mutations listed here are used to send requests to the [Admin Upload API Routes](https://docs.medusajs.com/api/admin#uploads). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * The methods in this class are used to upload any type of resources. For example, they can be used to upload CSV files that are used to import products into the store. - * - * Related Guide: [How to upload CSV file when importing a product](https://docs.medusajs.com/modules/products/admin/import-products#1-upload-csv-file). - * - * @customNamespace Hooks.Admin.Uploads - */ - -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/uploads/mutations.ts b/packages/medusa-react/src/hooks/admin/uploads/mutations.ts deleted file mode 100644 index 5d62c3c648..0000000000 --- a/packages/medusa-react/src/hooks/admin/uploads/mutations.ts +++ /dev/null @@ -1,190 +0,0 @@ -import { - AdminDeleteUploadsReq, - AdminDeleteUploadsRes, - AdminPostUploadsDownloadUrlReq, - AdminUploadsDownloadUrlRes, - AdminUploadsRes, -} from "@medusajs/medusa" -import { AdminCreateUploadPayload, Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" - -/** - * This hook uploads a file to a public bucket or storage. The file upload is handled by the file service installed on the Medusa backend. - * - * @example - * import React from "react" - * import { useAdminUploadFile } from "medusa-react" - * - * const UploadFile = () => { - * const uploadFile = useAdminUploadFile() - * // ... - * - * const handleFileUpload = (file: File) => { - * uploadFile.mutate(file, { - * onSuccess: ({ uploads }) => { - * console.log(uploads[0].key) - * } - * }) - * } - * - * // ... - * } - * - * export default UploadFile - * - * @customNamespace Hooks.Admin.Uploads - * @category Mutations - */ -export const useAdminUploadFile = ( - options?: UseMutationOptions< - Response, - Error, - AdminCreateUploadPayload - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation((payload: AdminCreateUploadPayload) => { - return client.admin.uploads.create(payload) - }, buildOptions(queryClient, undefined, options)) -} - -/** - * This hook uploads a file to an ACL or a non-public bucket. The file upload is handled by the file service installed on the Medusa backend. - * - * @example - * import React from "react" - * import { useAdminUploadProtectedFile } from "medusa-react" - * - * const UploadFile = () => { - * const uploadFile = useAdminUploadProtectedFile() - * // ... - * - * const handleFileUpload = (file: File) => { - * uploadFile.mutate(file, { - * onSuccess: ({ uploads }) => { - * console.log(uploads[0].key) - * } - * }) - * } - * - * // ... - * } - * - * export default UploadFile - * - * @customNamespace Hooks.Admin.Uploads - * @category Mutations - */ -export const useAdminUploadProtectedFile = ( - options?: UseMutationOptions< - Response, - Error, - AdminCreateUploadPayload - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation((payload: AdminCreateUploadPayload) => { - return client.admin.uploads.createProtected(payload) - }, buildOptions(queryClient, undefined, options)) -} - -/** - * This hook creates and retrieve a presigned or public download URL for a file. The URL creation is handled by the file service installed on the Medusa backend. - * - * @example - * import React from "react" - * import { useAdminCreatePresignedDownloadUrl } from "medusa-react" - * - * const Image = () => { - * const createPresignedUrl = useAdminCreatePresignedDownloadUrl() - * // ... - * - * const handlePresignedUrl = (fileKey: string) => { - * createPresignedUrl.mutate({ - * file_key: fileKey - * }, { - * onSuccess: ({ download_url }) => { - * console.log(download_url) - * } - * }) - * } - * - * // ... - * } - * - * export default Image - * - * @customNamespace Hooks.Admin.Uploads - * @category Mutations - */ -export const useAdminCreatePresignedDownloadUrl = ( - options?: UseMutationOptions< - Response, - Error, - AdminPostUploadsDownloadUrlReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminPostUploadsDownloadUrlReq) => - client.admin.uploads.getPresignedDownloadUrl(payload), - buildOptions(queryClient, undefined, options) - ) -} - -/** - * This hook deletes an uploaded file from storage. The file is deleted using the installed file service on the Medusa backend. - * - * @example - * import React from "react" - * import { useAdminDeleteFile } from "medusa-react" - * - * const Image = () => { - * const deleteFile = useAdminDeleteFile() - * // ... - * - * const handleDeleteFile = (fileKey: string) => { - * deleteFile.mutate({ - * file_key: fileKey - * }, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Image - * - * @customNamespace Hooks.Admin.Uploads - * @category Mutations - */ -export const useAdminDeleteFile = ( - options?: UseMutationOptions< - Response, - Error, - AdminDeleteUploadsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminDeleteUploadsReq) => client.admin.uploads.delete(payload), - buildOptions(queryClient, undefined, options) - ) -} diff --git a/packages/medusa-react/src/hooks/admin/users/index.ts b/packages/medusa-react/src/hooks/admin/users/index.ts deleted file mode 100644 index 21c4420b95..0000000000 --- a/packages/medusa-react/src/hooks/admin/users/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Admin User API Routes](https://docs.medusajs.com/api/admin#users). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * A store can have more than one user, each having the same privileges. Admins can manage users, their passwords, and more. - * - * Related Guide: [How to manage users](https://docs.medusajs.com/modules/users/admin/manage-users). - * - * @customNamespace Hooks.Admin.Users - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/users/mutations.ts b/packages/medusa-react/src/hooks/admin/users/mutations.ts deleted file mode 100644 index f309cf3048..0000000000 --- a/packages/medusa-react/src/hooks/admin/users/mutations.ts +++ /dev/null @@ -1,273 +0,0 @@ -import { - AdminDeleteUserRes, - AdminResetPasswordRequest, - AdminResetPasswordTokenRequest, - AdminUserRes, -} from "@medusajs/medusa" -import { - AdminCreateUserPayload, - AdminUpdateUserPayload, - Response, -} from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" -import { adminUserKeys } from "./queries" -import { useMedusa } from "../../../contexts/medusa" -import { buildOptions } from "../../utils/buildOptions" - -/** - * This hook creates an admin user. The user has the same privileges as all admin users, and will be able to - * authenticate and perform admin functionalities right after creation. - * - * @example - * import React from "react" - * import { useAdminCreateUser } from "medusa-react" - * - * const CreateUser = () => { - * const createUser = useAdminCreateUser() - * // ... - * - * const handleCreateUser = () => { - * createUser.mutate({ - * email: "user@example.com", - * password: "supersecret", - * }, { - * onSuccess: ({ user }) => { - * console.log(user.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateUser - * - * @customNamespace Hooks.Admin.Users - * @category Mutations - */ -export const useAdminCreateUser = ( - options?: UseMutationOptions< - Response, - Error, - AdminCreateUserPayload - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminCreateUserPayload) => client.admin.users.create(payload), - buildOptions(queryClient, adminUserKeys.lists(), options) - ) -} - -/** - * This hook updates an admin user's details. - * - * @example - * import React from "react" - * import { useAdminUpdateUser } from "medusa-react" - * - * type Props = { - * userId: string - * } - * - * const User = ({ userId }: Props) => { - * const updateUser = useAdminUpdateUser(userId) - * // ... - * - * const handleUpdateUser = ( - * firstName: string - * ) => { - * updateUser.mutate({ - * first_name: firstName, - * }, { - * onSuccess: ({ user }) => { - * console.log(user.first_name) - * } - * }) - * } - * - * // ... - * } - * - * export default User - * - * @customNamespace Hooks.Admin.Users - * @category Mutations - */ -export const useAdminUpdateUser = ( - /** - * The user's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - AdminUpdateUserPayload - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: AdminUpdateUserPayload) => client.admin.users.update(id, payload), - buildOptions( - queryClient, - [adminUserKeys.lists(), adminUserKeys.detail(id)], - options - ) - ) -} - -/** - * This hook deletes a user. Once deleted, the user will not be able to authenticate or perform admin functionalities. - * - * @example - * import React from "react" - * import { useAdminDeleteUser } from "medusa-react" - * - * type Props = { - * userId: string - * } - * - * const User = ({ userId }: Props) => { - * const deleteUser = useAdminDeleteUser(userId) - * // ... - * - * const handleDeleteUser = () => { - * deleteUser.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default User - * - * @customNamespace Hooks.Admin.Users - * @category Mutations - */ -export const useAdminDeleteUser = ( - /** - * The user's ID. - */ - id: string, - options?: UseMutationOptions, Error, void> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.admin.users.delete(id), - buildOptions( - queryClient, - [adminUserKeys.detail(id), adminUserKeys.lists()], - options - ) - ) -} - -/** - * This hook resets the password of an admin user using their reset password token. You must generate a reset password token first - * for the user using the {@link useAdminSendResetPasswordToken} hook, then use that token to reset the password in this hook. - * - * @example - * import React from "react" - * import { useAdminResetPassword } from "medusa-react" - * - * const ResetPassword = () => { - * const resetPassword = useAdminResetPassword() - * // ... - * - * const handleResetPassword = ( - * token: string, - * password: string - * ) => { - * resetPassword.mutate({ - * token, - * password, - * }, { - * onSuccess: ({ user }) => { - * console.log(user.id) - * } - * }) - * } - * - * // ... - * } - * - * export default ResetPassword - * - * @customNamespace Hooks.Admin.Users - * @category Mutations - */ -export const useAdminResetPassword = ( - options?: UseMutationOptions< - Response, - Error, - AdminResetPasswordRequest - > -) => { - const { client } = useMedusa() - return useMutation( - (payload: AdminResetPasswordRequest) => - client.admin.users.resetPassword(payload), - options - ) -} - -/** - * This hook generates a password token for an admin user with a given email. This also triggers the `user.password_reset` event. So, if you have a Notification Service installed - * that can handle this event, a notification, such as an email, will be sent to the user. The token is triggered as part of the `user.password_reset` event's payload. - * That token must be used later to reset the password using the {@link useAdminResetPassword} hook. - * - * @example - * import React from "react" - * import { useAdminSendResetPasswordToken } from "medusa-react" - * - * const Login = () => { - * const requestPasswordReset = useAdminSendResetPasswordToken() - * // ... - * - * const handleResetPassword = ( - * email: string - * ) => { - * requestPasswordReset.mutate({ - * email - * }, { - * onSuccess: () => { - * // successful - * } - * }) - * } - * - * // ... - * } - * - * export default Login - * - * @customNamespace Hooks.Admin.Users - * @category Mutations - */ -export const useAdminSendResetPasswordToken = ( - options?: UseMutationOptions< - Response, - Error, - AdminResetPasswordTokenRequest - > -) => { - const { client } = useMedusa() - return useMutation( - (payload: AdminResetPasswordTokenRequest) => - client.admin.users.sendResetPasswordToken(payload), - options - ) -} diff --git a/packages/medusa-react/src/hooks/admin/users/queries.ts b/packages/medusa-react/src/hooks/admin/users/queries.ts deleted file mode 100644 index 6f13a86a7b..0000000000 --- a/packages/medusa-react/src/hooks/admin/users/queries.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { - AdminGetUsersParams, - AdminUserRes, - AdminUsersListRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_USERS_QUERY_KEY = `admin_users` as const - -export const adminUserKeys = queryKeysFactory(ADMIN_USERS_QUERY_KEY) - -type UserQueryKeys = typeof adminUserKeys - -/** - * This hook retrieves all admin users. - * - * @example - * To list users: - * - * ```tsx - * import React from "react" - * import { useAdminUsers } from "medusa-react" - * - * const Users = () => { - * const { users, isLoading } = useAdminUsers() - * - * return ( - *
- * {isLoading && Loading...} - * {users && !users.length && No Users} - * {users && users.length > 0 && ( - *
    - * {users.map((user) => ( - *
  • {user.email}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Users - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminUsers } from "medusa-react" - * - * const Users = () => { - * const { - * users, - * limit, - * offset, - * isLoading - * } = useAdminUsers({ - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {users && !users.length && No Users} - * {users && users.length > 0 && ( - *
    - * {users.map((user) => ( - *
  • {user.email}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Users - * ``` - * - * @customNamespace Hooks.Admin.Users - * @category Queries - */ -export const useAdminUsers = ( - query?: AdminGetUsersParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminUserKeys.list(query), - () => client.admin.users.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves an admin user's details. - * - * @example - * import React from "react" - * import { useAdminUser } from "medusa-react" - * - * type Props = { - * userId: string - * } - * - * const User = ({ userId }: Props) => { - * const { user, isLoading } = useAdminUser( - * userId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {user && {user.first_name} {user.last_name}} - *
- * ) - * } - * - * export default User - * - * @customNamespace Hooks.Admin.Users - * @category Queries - */ -export const useAdminUser = ( - /** - * The user's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminUserKeys.detail(id), - () => client.admin.users.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/admin/variants/index.ts b/packages/medusa-react/src/hooks/admin/variants/index.ts deleted file mode 100644 index 0d96a59ec2..0000000000 --- a/packages/medusa-react/src/hooks/admin/variants/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @packageDocumentation - * - * Queries listed here are used to send requests to the [Admin Product Variant API Routes](https://docs.medusajs.com/api/admin#product-variants). - * - * All hooks listed require {@link Hooks.Admin.Auth.useAdminLogin | user authentication}. - * - * Product variants are the actual salable item in your store. Each variant is a combination of the different option values available on the product. - * - * Related Guide: [How to manage product variants](https://docs.medusajs.com/modules/products/admin/manage-products#manage-product-variants). - * - * @customNamespace Hooks.Admin.Product Variants - */ - -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/admin/variants/queries.ts b/packages/medusa-react/src/hooks/admin/variants/queries.ts deleted file mode 100644 index b9425b5f3d..0000000000 --- a/packages/medusa-react/src/hooks/admin/variants/queries.ts +++ /dev/null @@ -1,287 +0,0 @@ -import { - AdminGetVariantParams, - AdminGetVariantsParams, - AdminGetVariantsVariantInventoryRes, - AdminVariantsListRes, - AdminVariantsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ADMIN_VARIANT_QUERY_KEY = `admin_variants` as const - -export const adminVariantKeys = queryKeysFactory(ADMIN_VARIANT_QUERY_KEY) - -type VariantQueryKeys = typeof adminVariantKeys - -/** - * This hook retrieves a list of product variants. The product variant can be filtered by fields such as `id` or `title` - * passed in the `query` parameter. The product variant can also be paginated. - * - * @example - * To list product variants: - * - * ```tsx - * import React from "react" - * import { useAdminVariants } from "medusa-react" - * - * const Variants = () => { - * const { variants, isLoading } = useAdminVariants() - * - * return ( - *
- * {isLoading && Loading...} - * {variants && !variants.length && ( - * No Variants - * )} - * {variants && variants.length > 0 && ( - *
    - * {variants.map((variant) => ( - *
  • {variant.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Variants - * ``` - * - * To specify relations that should be retrieved within the product variants: - * - * ```tsx - * import React from "react" - * import { useAdminVariants } from "medusa-react" - * - * const Variants = () => { - * const { variants, isLoading } = useAdminVariants({ - * expand: "options" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {variants && !variants.length && ( - * No Variants - * )} - * {variants && variants.length > 0 && ( - *
    - * {variants.map((variant) => ( - *
  • {variant.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Variants - * ``` - * - * By default, only the first `100` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useAdminVariants } from "medusa-react" - * - * const Variants = () => { - * const { - * variants, - * limit, - * offset, - * isLoading - * } = useAdminVariants({ - * expand: "options", - * limit: 50, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {variants && !variants.length && ( - * No Variants - * )} - * {variants && variants.length > 0 && ( - *
    - * {variants.map((variant) => ( - *
  • {variant.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Variants - * ``` - * - * @customNamespace Hooks.Admin.Product Variants - * @category Queries - */ -export const useAdminVariants = ( - /** - * Filters and pagination configurations to apply on the retrieved product variants. - */ - query?: AdminGetVariantsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminVariantKeys.list(query), - () => client.admin.variants.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a product variant's details. - * - * @example - * A simple example that retrieves a product variant by its ID: - * - * ```tsx - * import React from "react" - * import { useAdminVariant } from "medusa-react" - * - * type Props = { - * variantId: string - * } - * - * const Variant = ({ variantId }: Props) => { - * const { variant, isLoading } = useAdminVariant( - * variantId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {variant && {variant.title}} - *
- * ) - * } - * - * export default Variant - * ``` - * - * To specify relations that should be retrieved: - * - * ```tsx - * import React from "react" - * import { useAdminVariant } from "medusa-react" - * - * type Props = { - * variantId: string - * } - * - * const Variant = ({ variantId }: Props) => { - * const { variant, isLoading } = useAdminVariant( - * variantId, { - * expand: "options" - * } - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {variant && {variant.title}} - *
- * ) - * } - * - * export default Variant - * ``` - * - * @customNamespace Hooks.Admin.Product Variants - * @category Queries - */ -export const useAdminVariant = ( - /** - * The product variant's ID. - */ - id: string, - /** - * Configurations to apply on the retrieved product variant. - */ - query?: AdminGetVariantParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminVariantKeys.detail(id), - () => client.admin.variants.retrieve(id, query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves the available inventory of a product variant. - * - * @example - * import React from "react" - * import { useAdminVariantsInventory } from "medusa-react" - * - * type Props = { - * variantId: string - * } - * - * const VariantInventory = ({ variantId }: Props) => { - * const { variant, isLoading } = useAdminVariantsInventory( - * variantId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {variant && variant.inventory.length === 0 && ( - * Variant doesn't have inventory details - * )} - * {variant && variant.inventory.length > 0 && ( - *
    - * {variant.inventory.map((inventory) => ( - *
  • {inventory.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default VariantInventory - * - * @customNamespace Hooks.Admin.Product Variants - * @category Queries - */ -export const useAdminVariantsInventory = ( - /** - * The product variant's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminVariantKeys.detail(id), - () => client.admin.variants.getInventory(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/index.ts b/packages/medusa-react/src/hooks/index.ts deleted file mode 100644 index d7688a759d..0000000000 --- a/packages/medusa-react/src/hooks/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./admin" -export * from "./store" -export * from "./utils" - diff --git a/packages/medusa-react/src/hooks/store/carts/index.ts b/packages/medusa-react/src/hooks/store/carts/index.ts deleted file mode 100644 index 47196d64ae..0000000000 --- a/packages/medusa-react/src/hooks/store/carts/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Store Cart API Routes](https://docs.medusajs.com/api/store#carts). - * - * A cart is a virtual shopping bag that customers can use to add items they want to purchase. - * A cart is then used to checkout and place an order. - * - * The hooks listed have general examples on how to use them, but it's highly recommended to use the {@link Providers.Cart.CartProvider | CartProvider} provider and - * the {@link Providers.Cart.useCart | useCart} hook to manage your cart and access the current cart across your application. - * - * Related Guide: [How to implement cart functionality in your storefront](https://docs.medusajs.com/modules/carts-and-checkout/storefront/implement-cart). - * - * @customNamespace Hooks.Store.Carts - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/store/carts/mutations.ts b/packages/medusa-react/src/hooks/store/carts/mutations.ts deleted file mode 100644 index 18eca0ccaf..0000000000 --- a/packages/medusa-react/src/hooks/store/carts/mutations.ts +++ /dev/null @@ -1,549 +0,0 @@ -import { - StoreCartsRes, - StoreCompleteCartRes, - StorePostCartReq, - StorePostCartsCartPaymentSessionReq, - StorePostCartsCartPaymentSessionUpdateReq, - StorePostCartsCartReq, - StorePostCartsCartShippingMethodReq, -} from "@medusajs/medusa" -import { useMutation, UseMutationOptions } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" - -/** - * The details of the cart to create. - */ -export type CreateCartReq = StorePostCartReq | undefined - -/** - * This hook creates a Cart. Although optional, specifying the cart's region and sales channel can affect the cart's pricing and - * the products that can be added to the cart respectively. - * - * So, make sure to set those early on and change them if necessary, such as when the customer changes their region. - * - * If a customer is logged in, make sure to pass its ID or email within the cart's details so that the cart is attached to the customer. - * - * @example - * import React from "react" - * import { useCreateCart } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Cart = ({ regionId }: Props) => { - * const createCart = useCreateCart() - * - * const handleCreate = () => { - * createCart.mutate({ - * region_id: regionId - * // creates an empty cart - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.items) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Carts - * @category Mutations - */ -export const useCreateCart = ( - options?: UseMutationOptions< - StoreCartsRes, - Error, - StorePostCartReq | undefined - > -) => { - const { client } = useMedusa() - return useMutation( - (data?: StorePostCartReq | undefined) => client.carts.create(data), - options - ) -} - -/** - * This hook updates a Cart's details. If the cart has payment sessions and the region was not changed, - * the payment sessions are updated. The cart's totals are also recalculated. - * - * @example - * import React from "react" - * import { useUpdateCart } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const updateCart = useUpdateCart(cartId) - * - * const handleUpdate = ( - * email: string - * ) => { - * updateCart.mutate({ - * email - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.email) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Carts - * @category Mutations - */ -export const useUpdateCart = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseMutationOptions -) => { - const { client } = useMedusa() - return useMutation( - (data: StorePostCartsCartReq) => client.carts.update(cartId, data), - options - ) -} - -/** - * This hook completes a cart and place an order or create a swap, based on the cart's type. This includes attempting to authorize the cart's payment. - * If authorizing the payment requires more action, the cart will not be completed and the order will not be placed or the swap will not be created. - * An idempotency key will be generated if none is provided in the header `Idempotency-Key` and added to - * the response. If an error occurs during cart completion or the request is interrupted for any reason, the cart completion can be retried by passing the idempotency - * key in the `Idempotency-Key` header. - * - * @example - * import React from "react" - * import { useCompleteCart } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const completeCart = useCompleteCart(cartId) - * - * const handleComplete = () => { - * completeCart.mutate(void 0, { - * onSuccess: ({ data, type }) => { - * console.log(data.id, type) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Carts - * @category Mutations - */ -export const useCompleteCart = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseMutationOptions -) => { - const { client } = useMedusa() - return useMutation(() => client.carts.complete(cartId), options) -} - -/** - * This hook creates Payment Sessions for each of the available Payment Providers in the Cart's Region. If there's only one payment session created, - * it will be selected by default. The creation of the payment session uses the payment provider and may require sending requests to third-party services. - * - * @example - * import React from "react" - * import { useCreatePaymentSession } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const createPaymentSession = useCreatePaymentSession(cartId) - * - * const handleComplete = () => { - * createPaymentSession.mutate(void 0, { - * onSuccess: ({ cart }) => { - * console.log(cart.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Carts - * @category Mutations - */ -export const useCreatePaymentSession = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseMutationOptions -) => { - const { client } = useMedusa() - return useMutation(() => client.carts.createPaymentSessions(cartId), options) -} - -/** - * The details of the payment session to update. - */ -export type UpdatePaymentSessionReq = StorePostCartsCartPaymentSessionUpdateReq & { - /** - * The payment provider's identifier. - */ - provider_id: string -} - -/** - * This hook updates a Payment Session with additional data. This can be useful depending on the payment provider used. - * All payment sessions are updated and cart totals are recalculated afterwards. - * - * @example - * import React from "react" - * import { useUpdatePaymentSession } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const updatePaymentSession = useUpdatePaymentSession(cartId) - * - * const handleUpdate = ( - * providerId: string, - * data: Record - * ) => { - * updatePaymentSession.mutate({ - * provider_id: providerId, - * data - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.payment_session) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Carts - * @category Mutations - */ -export const useUpdatePaymentSession = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseMutationOptions< - StoreCartsRes, - Error, - UpdatePaymentSessionReq - > -) => { - const { client } = useMedusa() - return useMutation( - ({ data, provider_id }: UpdatePaymentSessionReq) => - client.carts.updatePaymentSession(cartId, provider_id, { data }), - options - ) -} - -/** - * The details of the payment session to refresh. - */ -export type RefreshPaymentSessionMutationData = { - /** - * The payment provider's identifier. - */ - provider_id: string -} - -/** - * This hook refreshes a Payment Session to ensure that it is in sync with the Cart. This is usually not necessary, but is provided for edge cases. - * - * @example - * import React from "react" - * import { useRefreshPaymentSession } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const refreshPaymentSession = useRefreshPaymentSession(cartId) - * - * const handleRefresh = ( - * providerId: string - * ) => { - * refreshPaymentSession.mutate({ - * provider_id: providerId, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Carts - * @category Mutations - */ -export const useRefreshPaymentSession = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseMutationOptions< - StoreCartsRes, - Error, - RefreshPaymentSessionMutationData - > -) => { - const { client } = useMedusa() - return useMutation( - ({ provider_id }: RefreshPaymentSessionMutationData) => - client.carts.refreshPaymentSession(cartId, provider_id), - options - ) -} - -/** - * This hook selects the Payment Session that will be used to complete the cart. This is typically used when the customer chooses their preferred payment method during checkout. - * The totals of the cart will be recalculated. - * - * @example - * import React from "react" - * import { useSetPaymentSession } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const setPaymentSession = useSetPaymentSession(cartId) - * - * const handleSetPaymentSession = ( - * providerId: string - * ) => { - * setPaymentSession.mutate({ - * provider_id: providerId, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.payment_session) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Carts - * @category Mutations - */ -export const useSetPaymentSession = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseMutationOptions< - StoreCartsRes, - Error, - StorePostCartsCartPaymentSessionReq - > -) => { - const { client } = useMedusa() - return useMutation( - (data: StorePostCartsCartPaymentSessionReq) => - client.carts.setPaymentSession(cartId, data), - options - ) -} - -/** - * This hook adds a shipping method to the cart. The validation of the `data` field is handled by the fulfillment provider of the chosen shipping option. - * - * @example - * import React from "react" - * import { useAddShippingMethodToCart } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const addShippingMethod = useAddShippingMethodToCart(cartId) - * - * const handleAddShippingMethod = ( - * optionId: string - * ) => { - * addShippingMethod.mutate({ - * option_id: optionId, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.shipping_methods) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Carts - * @category Mutations - */ -export const useAddShippingMethodToCart = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseMutationOptions< - StoreCartsRes, - Error, - StorePostCartsCartShippingMethodReq - > -) => { - const { client } = useMedusa() - return useMutation( - (data: StorePostCartsCartShippingMethodReq) => - client.carts.addShippingMethod(cartId, data), - options - ) -} - -/** - * The details of the payment session to delete. - */ -export type DeletePaymentSessionMutationData = { - /** - * The payment provider's identifier. - */ - provider_id: string -} - -/** - * This hook deletes a Payment Session in a Cart. May be useful if a payment has failed. The totals will be recalculated. - * - * @example - * import React from "react" - * import { useDeletePaymentSession } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const deletePaymentSession = useDeletePaymentSession(cartId) - * - * const handleDeletePaymentSession = ( - * providerId: string - * ) => { - * deletePaymentSession.mutate({ - * provider_id: providerId, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Carts - * @category Mutations - */ -export const useDeletePaymentSession = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseMutationOptions< - StoreCartsRes, - Error, - DeletePaymentSessionMutationData - > -) => { - const { client } = useMedusa() - return useMutation( - ({ provider_id }: DeletePaymentSessionMutationData) => - client.carts.deletePaymentSession(cartId, provider_id), - options - ) -} - -/** - * This hook allows you to create a cart and set its payment session as a preparation for checkout. - * It performs the same actions as the {@link useCreateCart} and {@link useCreatePaymentSession} hooks. - * - * @example - * import React from "react" - * import { useStartCheckout } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Checkout = ({ regionId }: Props) => { - * const startCheckout = useStartCheckout() - * - * const handleCheckout = () => { - * startCheckout.mutate({ - * region_id: regionId, - * }, { - * onSuccess: (cart) => { - * console.log(cart.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default Checkout - * - * @customNamespace Hooks.Store.Carts - * @category Mutations - */ -export const useStartCheckout = ( - options?: UseMutationOptions -) => { - const { client } = useMedusa() - const mutation = useMutation(async (data?: StorePostCartReq) => { - const { cart } = await client.carts.create(data) - const res = await client.carts.createPaymentSessions(cart.id) - return res.cart - }, options) - - return mutation -} diff --git a/packages/medusa-react/src/hooks/store/carts/queries.ts b/packages/medusa-react/src/hooks/store/carts/queries.ts deleted file mode 100644 index 4987b0a42a..0000000000 --- a/packages/medusa-react/src/hooks/store/carts/queries.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { StoreCartsRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const CARTS_QUERY_KEY = `carts` as const - -export const cartKeys = queryKeysFactory(CARTS_QUERY_KEY) -type CartQueryKey = typeof cartKeys - -/** - * This hook retrieves a Cart's details. This includes recalculating its totals. - * - * @example - * import React from "react" - * import { useGetCart } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const { cart, isLoading } = useGetCart(cartId) - * - * return ( - *
- * {isLoading && Loading...} - * {cart && cart.items.length === 0 && ( - * Cart is empty - * )} - * {cart && cart.items.length > 0 && ( - *
    - * {cart.items.map((item) => ( - *
  • {item.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Carts - * @category Queries - */ -export const useGetCart = ( - /** - * The cart's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - cartKeys.detail(id), - () => client.carts.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/collections/index.ts b/packages/medusa-react/src/hooks/store/collections/index.ts deleted file mode 100644 index f552cbe037..0000000000 --- a/packages/medusa-react/src/hooks/store/collections/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @packageDocumentation - * - * Queries listed here are used to send requests to the [Store Product Collection API Routes](https://docs.medusajs.com/api/store#product-collections). - * - * A product collection is used to organize products for different purposes such as marketing or discount purposes. For example, you can create a Summer Collection. - * Using the methods in this class, you can list or retrieve a collection's details and products. - * - * @customNamespace Hooks.Store.Product Collections - */ - -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/store/collections/queries.ts b/packages/medusa-react/src/hooks/store/collections/queries.ts deleted file mode 100644 index 4598abb6f3..0000000000 --- a/packages/medusa-react/src/hooks/store/collections/queries.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { - StoreCollectionsListRes, - StoreCollectionsRes, - StoreGetCollectionsParams, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const COLLECTIONS_QUERY_KEY = `collections` as const - -export const collectionKeys = queryKeysFactory(COLLECTIONS_QUERY_KEY) - -type CollectionQueryKey = typeof collectionKeys - -/** - * This hook retrieves a product collection's details. - * - * @example - * import React from "react" - * import { useCollection } from "medusa-react" - * - * type Props = { - * collectionId: string - * } - * - * const ProductCollection = ({ collectionId }: Props) => { - * const { collection, isLoading } = useCollection(collectionId) - * - * return ( - *
- * {isLoading && Loading...} - * {collection && {collection.title}} - *
- * ) - * } - * - * export default ProductCollection - * - * @customNamespace Hooks.Store.Product Collections - * @category Queries - */ -export const useCollection = ( - /** - * The product collection's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - collectionKeys.detail(id), - () => client.collections.retrieve(id), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a list of product collections. The product collections can be filtered by fields such as `handle` or `created_at` passed in the `query` parameter. - * The product collections can also be paginated. - * - * @example - * To list product collections: - * - * ```tsx - * import React from "react" - * import { useCollections } from "medusa-react" - * - * const ProductCollections = () => { - * const { collections, isLoading } = useCollections() - * - * return ( - *
- * {isLoading && Loading...} - * {collections && collections.length === 0 && ( - * No Product Collections - * )} - * {collections && collections.length > 0 && ( - *
    - * {collections.map((collection) => ( - *
  • {collection.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ProductCollections - * ``` - * - * By default, only the first `10` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useCollections } from "medusa-react" - * - * const ProductCollections = () => { - * const { - * collections, - * limit, - * offset, - * isLoading - * } = useCollections({ - * limit: 20, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {collections && collections.length === 0 && ( - * No Product Collections - * )} - * {collections && collections.length > 0 && ( - *
    - * {collections.map((collection) => ( - *
  • {collection.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ProductCollections - * ``` - * - * @customNamespace Hooks.Store.Product Collections - * @category Queries - */ -export const useCollections = ( - /** - * Filters and pagination configurations to apply on the retrieved product collections. - */ - query?: StoreGetCollectionsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - collectionKeys.list(query), - () => client.collections.list(query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/customers/index.ts b/packages/medusa-react/src/hooks/store/customers/index.ts deleted file mode 100644 index 290d0ba1d3..0000000000 --- a/packages/medusa-react/src/hooks/store/customers/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Store Customer API Routes](https://docs.medusajs.com/api/store#customers_postcustomers). - * - * A customer can register and manage their information such as addresses, orders, payment methods, and more. - * - * Related Guide: [How to implement customer profiles in your storefront](https://docs.medusajs.com/modules/customers/storefront/implement-customer-profiles). - * - * @customNamespace Hooks.Store.Customers - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/store/customers/mutations.ts b/packages/medusa-react/src/hooks/store/customers/mutations.ts deleted file mode 100644 index 6db225975b..0000000000 --- a/packages/medusa-react/src/hooks/store/customers/mutations.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { - StoreCustomersRes, - StorePostCustomersCustomerReq, - StorePostCustomersReq, -} from "@medusajs/medusa" -import { UseMutationOptions, useMutation } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts/medusa" - -/** - * This hook registers a new customer. This will also automatically authenticate the customer and set their login session in the response Cookie header. - * Subsequent requests sent with other hooks are sent with the Cookie session automatically. - * - * @example - * import React from "react" - * import { useCreateCustomer } from "medusa-react" - * - * const RegisterCustomer = () => { - * const createCustomer = useCreateCustomer() - * // ... - * - * const handleCreate = ( - * customerData: { - * first_name: string - * last_name: string - * email: string - * password: string - * } - * ) => { - * // ... - * createCustomer.mutate(customerData, { - * onSuccess: ({ customer }) => { - * console.log(customer.id) - * } - * }) - * } - * - * // ... - * } - * - * export default RegisterCustomer - * - * @customNamespace Hooks.Store.Customers - * @category Mutations - */ -export const useCreateCustomer = ( - options?: UseMutationOptions -) => { - const { client } = useMedusa() - return useMutation( - (data: StorePostCustomersReq) => client.customers.create(data), - options - ) -} - -export type UpdateMeReq = StorePostCustomersCustomerReq & { - /** - * The customer's ID. - */ - id: string -} - -/** - * This hook updates the logged-in customer's details. This hook requires [customer authentication](https://docs.medusajs.com/medusa-react/overview#customer-authentication). - * - * @example - * import React from "react" - * import { useUpdateMe } from "medusa-react" - * - * type Props = { - * customerId: string - * } - * - * const Customer = ({ customerId }: Props) => { - * const updateCustomer = useUpdateMe() - * // ... - * - * const handleUpdate = ( - * firstName: string - * ) => { - * // ... - * updateCustomer.mutate({ - * id: customerId, - * first_name: firstName, - * }, { - * onSuccess: ({ customer }) => { - * console.log(customer.first_name) - * } - * }) - * } - * - * // ... - * } - * - * export default Customer - * - * @customNamespace Hooks.Store.Customers - * @category Mutations - */ -export const useUpdateMe = ( - options?: UseMutationOptions< - StoreCustomersRes, - Error, - UpdateMeReq - > -) => { - const { client } = useMedusa() - return useMutation( - ({ id, ...data }: UpdateMeReq) => - client.customers.update(data), - options - ) -} diff --git a/packages/medusa-react/src/hooks/store/customers/queries.ts b/packages/medusa-react/src/hooks/store/customers/queries.ts deleted file mode 100644 index 77855c3741..0000000000 --- a/packages/medusa-react/src/hooks/store/customers/queries.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { - StoreCustomersListOrdersRes, - StoreCustomersRes, - StoreGetCustomersCustomerOrdersParams, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const CUSTOMERS_QUERY_KEY = `customers` as const - -export const customerKeys = { - ...queryKeysFactory(CUSTOMERS_QUERY_KEY), - orders: (id: string) => [...customerKeys.detail(id), "orders"] as const, -} - -type CustomerQueryKey = typeof customerKeys - -/** - * This hook retrieves the logged-in customer's details. It requires [customer authentication](https://docs.medusajs.com/medusa-react/overview#customer-authentication). - * - * @example - * import React from "react" - * import { useMeCustomer } from "medusa-react" - * - * const Customer = () => { - * const { customer, isLoading } = useMeCustomer() - * - * return ( - *
- * {isLoading && Loading...} - * {customer && ( - * {customer.first_name} {customer.last_name} - * )} - *
- * ) - * } - * - * export default Customer - * - * @customNamespace Hooks.Store.Customers - * @category Queries - */ -export const useMeCustomer = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - customerKeys.detail("me"), - () => client.customers.retrieve(), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a list of the logged-in customer's orders. The orders can be filtered by fields such as `status` or `fulfillment_status`. The orders can also be paginated. - * This hook requires [customer authentication](https://docs.medusajs.com/medusa-react/overview#customer-authentication). - * - * @example - * import React from "react" - * import { useCustomerOrders } from "medusa-react" - * - * const Orders = () => { - * // refetch a function that can be used to - * // re-retrieve orders after the customer logs in - * const { orders, isLoading } = useCustomerOrders() - * - * return ( - *
- * {isLoading && Loading orders...} - * {orders?.length && ( - *
    - * {orders.map((order) => ( - *
  • {order.display_id}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Orders - * - * @customNamespace Hooks.Store.Customers - * @category Queries - */ -export const useCustomerOrders = ( - /** - * Filters and pagination configurations to apply on the retrieved orders. - */ - query: StoreGetCustomersCustomerOrdersParams = { limit: 10, offset: 0 }, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - customerKeys.orders("me"), - () => client.customers.listOrders(query), - options - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/gift-cards/index.ts b/packages/medusa-react/src/hooks/store/gift-cards/index.ts deleted file mode 100644 index d1f6de74ab..0000000000 --- a/packages/medusa-react/src/hooks/store/gift-cards/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @packageDocumentation - * - * Queries listed here are used to send requests to the [Store Gift Card API Routes](https://docs.medusajs.com/api/store#gift-cards). - * - * Customers can use gift cards during checkout to deduct the gift card's balance from the checkout total. - * - * Related Guide: [How to use gift cards in a storefront](https://docs.medusajs.com/modules/gift-cards/storefront/use-gift-cards). - * - * @customNamespace Hooks.Store.Gift Cards - */ - -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/store/gift-cards/queries.ts b/packages/medusa-react/src/hooks/store/gift-cards/queries.ts deleted file mode 100644 index d59d97c575..0000000000 --- a/packages/medusa-react/src/hooks/store/gift-cards/queries.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { StoreGiftCardsRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const GIFT_CARDS_QUERY_KEY = `gift_cards` as const - -export const giftCardKeys = queryKeysFactory(GIFT_CARDS_QUERY_KEY) - -type GiftCardQueryKey = typeof giftCardKeys - -/** - * This hook retrieves a Gift Card's details by its associated unique code. - * - * @example - * import React from "react" - * import { useGiftCard } from "medusa-react" - * - * type Props = { - * giftCardCode: string - * } - * - * const GiftCard = ({ giftCardCode }: Props) => { - * const { gift_card, isLoading, isError } = useGiftCard( - * giftCardCode - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {gift_card && {gift_card.value}} - * {isError && Gift Card does not exist} - *
- * ) - * } - * - * export default GiftCard - * - * @customNamespace Hooks.Store.Gift Cards - * @category Queries - */ -export const useGiftCard = ( - /** - * The gift card's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - giftCardKeys.detail(id), - () => client.giftCards.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/index.ts b/packages/medusa-react/src/hooks/store/index.ts deleted file mode 100644 index 7111248ac9..0000000000 --- a/packages/medusa-react/src/hooks/store/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -export * from "./carts/" -export * from "./collections" -export * from "./customers/" -export * from "./gift-cards/" -export * from "./line-items/" -export * from "./order-edits" -export * from "./orders/" -export * from "./payment-collections" -export * from "./product-categories" -export * from "./product-tags" -export * from "./product-types/" -export * from "./products/" -export * from "./regions/" -export * from "./return-reasons/" -export * from "./returns/" -export * from "./shipping-options/" -export * from "./swaps/" diff --git a/packages/medusa-react/src/hooks/store/line-items/index.ts b/packages/medusa-react/src/hooks/store/line-items/index.ts deleted file mode 100644 index 6de46b4444..0000000000 --- a/packages/medusa-react/src/hooks/store/line-items/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @packageDocumentation - * - * Mutations listed here are used to send requests to the Line Item API Routes part of the [Store Cart API Routes](https://docs.medusajs.com/api/store#carts). - * - * The hooks listed have general examples on how to use them, but it's highly recommended to use the {@link Providers.Cart.CartProvider | CartProvider} provider and - * the {@link Providers.Cart.useCart | useCart} hook to manage your cart and access the current cart across your application. - * - * @customNamespace Hooks.Store.Line Items - */ - -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/store/line-items/mutations.ts b/packages/medusa-react/src/hooks/store/line-items/mutations.ts deleted file mode 100644 index fd46985197..0000000000 --- a/packages/medusa-react/src/hooks/store/line-items/mutations.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { - StoreCartsRes, - StorePostCartsCartLineItemsItemReq, - StorePostCartsCartLineItemsReq, -} from "@medusajs/medusa" -import { useMutation, UseMutationOptions } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" - -/** - * This hook generates a Line Item with a given Product Variant and adds it to the Cart. - * - * @example - * import React from "react" - * import { useCreateLineItem } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const createLineItem = useCreateLineItem(cartId) - * - * const handleAddItem = ( - * variantId: string, - * quantity: number - * ) => { - * createLineItem.mutate({ - * variant_id: variantId, - * quantity, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.items) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Line Items - * @category Mutations - */ -export const useCreateLineItem = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseMutationOptions< - StoreCartsRes, - Error, - StorePostCartsCartLineItemsReq - > -) => { - const { client } = useMedusa() - return useMutation( - (data: StorePostCartsCartLineItemsReq) => - client.carts.lineItems.create(cartId, data), - options - ) -} - -export type UpdateLineItemReq = StorePostCartsCartLineItemsItemReq & { - /** - * The line item's ID. - */ - lineId: string -} - -/** - * This hook updates a line item's data. - * - * @example - * import React from "react" - * import { useUpdateLineItem } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const updateLineItem = useUpdateLineItem(cartId) - * - * const handleUpdateItem = ( - * lineItemId: string, - * quantity: number - * ) => { - * updateLineItem.mutate({ - * lineId: lineItemId, - * quantity, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.items) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Line Items - * @category Mutations - */ -export const useUpdateLineItem = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseMutationOptions< - StoreCartsRes, - Error, - UpdateLineItemReq - > -) => { - const { client } = useMedusa() - return useMutation( - ({ - lineId, - ...data - }: UpdateLineItemReq) => - client.carts.lineItems.update(cartId, lineId, data), - options - ) -} - -/** - * This hook deletes a line item from a cart. The payment sessions will be updated and the totals will be recalculated. - * - * @example - * import React from "react" - * import { useDeleteLineItem } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const deleteLineItem = useDeleteLineItem(cartId) - * - * const handleDeleteItem = ( - * lineItemId: string - * ) => { - * deleteLineItem.mutate({ - * lineId: lineItemId, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.items) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - * @customNamespace Hooks.Store.Line Items - * @category Mutations - */ -export const useDeleteLineItem = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseMutationOptions -) => { - const { client } = useMedusa() - return useMutation( - ({ lineId }: { lineId: string }) => - client.carts.lineItems.delete(cartId, lineId), - options - ) -} diff --git a/packages/medusa-react/src/hooks/store/order-edits/index.ts b/packages/medusa-react/src/hooks/store/order-edits/index.ts deleted file mode 100644 index be5d5b73aa..0000000000 --- a/packages/medusa-react/src/hooks/store/order-edits/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Store Order Edits API Routes](https://docs.medusajs.com/api/store#order-edits). - * - * Order edits are changes made to items in an order such as adding, updating their quantity, or deleting them. Order edits are created by the admin. - * A customer can review order edit requests created by an admin and confirm or decline them. - * - * Related Guide: [How to handle order edits in a storefront](https://docs.medusajs.com/modules/orders/storefront/handle-order-edits). - * - * @customNamespace Hooks.Store.Order Edits - */ - -export * from "./queries" -export * from './mutations' \ No newline at end of file diff --git a/packages/medusa-react/src/hooks/store/order-edits/mutations.ts b/packages/medusa-react/src/hooks/store/order-edits/mutations.ts deleted file mode 100644 index 90ca7d94f0..0000000000 --- a/packages/medusa-react/src/hooks/store/order-edits/mutations.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" - -import { - StoreOrderEditsRes, - StorePostOrderEditsOrderEditDecline, -} from "@medusajs/medusa" - -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { orderEditQueryKeys } from "./queries" - -/** - * This hook declines an Order Edit. The changes are not reflected on the original order. - * - * @example - * import React from "react" - * import { useDeclineOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const declineOrderEdit = useDeclineOrderEdit(orderEditId) - * // ... - * - * const handleDeclineOrderEdit = ( - * declinedReason: string - * ) => { - * declineOrderEdit.mutate({ - * declined_reason: declinedReason, - * }, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.declined_at) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - * @customNamespace Hooks.Store.Order Edits - * @category Mutations - */ -export const useDeclineOrderEdit = ( - /** - * The order edit's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - StorePostOrderEditsOrderEditDecline - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: StorePostOrderEditsOrderEditDecline) => - client.orderEdits.decline(id, payload), - buildOptions( - queryClient, - [orderEditQueryKeys.lists(), orderEditQueryKeys.detail(id)], - options - ) - ) -} - -/** - * This hook completes and confirms an Order Edit and reflect its changes on the original order. Any additional payment required must - * be authorized first using the {@link Hooks.Store."Payment Collections".useAuthorizePaymentSession | useAuthorizePaymentSession} hook. - * - * @example - * import React from "react" - * import { useCompleteOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const completeOrderEdit = useCompleteOrderEdit( - * orderEditId - * ) - * // ... - * - * const handleCompleteOrderEdit = () => { - * completeOrderEdit.mutate(void 0, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.confirmed_at) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - * @customNamespace Hooks.Store.Order Edits - * @category Mutations - */ -export const useCompleteOrderEdit = ( - /** - * The order edit's ID. - */ - id: string, - options?: UseMutationOptions, Error> -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - () => client.orderEdits.complete(id), - buildOptions( - queryClient, - [orderEditQueryKeys.lists(), orderEditQueryKeys.detail(id)], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/store/order-edits/queries.ts b/packages/medusa-react/src/hooks/store/order-edits/queries.ts deleted file mode 100644 index 733a8275f7..0000000000 --- a/packages/medusa-react/src/hooks/store/order-edits/queries.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { StoreOrderEditsRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const ORDER_EDITS_QUERY_KEY = `orderEdit` as const - -export const orderEditQueryKeys = queryKeysFactory< - typeof ORDER_EDITS_QUERY_KEY ->(ORDER_EDITS_QUERY_KEY) - -type OrderQueryKey = typeof orderEditQueryKeys - -/** - * This hook retrieves an Order Edit's details. - * - * @example - * import React from "react" - * import { useOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const { order_edit, isLoading } = useOrderEdit(orderEditId) - * - * return ( - *
- * {isLoading && Loading...} - * {order_edit && ( - *
    - * {order_edit.changes.map((change) => ( - *
  • {change.type}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default OrderEdit - * - * @customNamespace Hooks.Store.Order Edits - * @category Queries - */ -export const useOrderEdit = ( - /** - * The order edit's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - orderEditQueryKeys.detail(id), - () => client.orderEdits.retrieve(id), - options - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/orders/index.ts b/packages/medusa-react/src/hooks/store/orders/index.ts deleted file mode 100644 index 8a1b603752..0000000000 --- a/packages/medusa-react/src/hooks/store/orders/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Store Order API Routes](https://docs.medusajs.com/api/store#orders). - * - * Orders are purchases made by customers, typically through a storefront. - * Orders are placed and created using {@link Hooks.Store.Carts | cart} hooks. The listed hooks allow retrieving and claiming orders. - * - * Related Guide: [How to retrieve order details in a storefront](https://docs.medusajs.com/modules/orders/storefront/retrieve-order-details). - * - * @customNamespace Hooks.Store.Orders - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/store/orders/mutations.ts b/packages/medusa-react/src/hooks/store/orders/mutations.ts deleted file mode 100644 index d5d3e1f6b9..0000000000 --- a/packages/medusa-react/src/hooks/store/orders/mutations.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" - -import { - StorePostCustomersCustomerAcceptClaimReq, - StorePostCustomersCustomerOrderClaimReq, -} from "@medusajs/medusa" - -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { orderKeys } from "./queries" - -/** - * This hook allows the logged-in customer to claim ownership of one or more orders. This generates a token that can be used later on to verify the claim - * using the {@link useGrantOrderAccess} hook. This also emits the event `order-update-token.created`. So, if you have a notification provider installed - * that handles this event and sends the customer a notification, such as an email, the customer should receive instructions on how to - * finalize their claim ownership. - * - * @example - * import React from "react" - * import { useRequestOrderAccess } from "medusa-react" - * - * const ClaimOrder = () => { - * const claimOrder = useRequestOrderAccess() - * - * const handleClaimOrder = ( - * orderIds: string[] - * ) => { - * claimOrder.mutate({ - * order_ids: orderIds - * }, { - * onSuccess: () => { - * // successful - * }, - * onError: () => { - * // an error occurred. - * } - * }) - * } - * - * // ... - * } - * - * export default ClaimOrder - * - * @customNamespace Hooks.Store.Orders - * @category Mutations - */ -export const useRequestOrderAccess = ( - options?: UseMutationOptions< - Response<{}>, - Error, - StorePostCustomersCustomerOrderClaimReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: StorePostCustomersCustomerOrderClaimReq) => - client.orders.requestCustomerOrders(payload), - buildOptions(queryClient, [orderKeys.all], options) - ) -} - -/** - * This hook verifies the claim order token provided to the customer when they request ownership of an order. - * - * @example - * import React from "react" - * import { useGrantOrderAccess } from "medusa-react" - * - * const ClaimOrder = () => { - * const confirmOrderRequest = useGrantOrderAccess() - * - * const handleOrderRequestConfirmation = ( - * token: string - * ) => { - * confirmOrderRequest.mutate({ - * token - * }, { - * onSuccess: () => { - * // successful - * }, - * onError: () => { - * // an error occurred. - * } - * }) - * } - * - * // ... - * } - * - * export default ClaimOrder - * - * @customNamespace Hooks.Store.Orders - * @category Mutations - */ -export const useGrantOrderAccess = ( - options?: UseMutationOptions< - Response<{}>, - Error, - StorePostCustomersCustomerAcceptClaimReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: StorePostCustomersCustomerAcceptClaimReq) => - client.orders.confirmRequest(payload), - buildOptions(queryClient, [orderKeys.all], options) - ) -} diff --git a/packages/medusa-react/src/hooks/store/orders/queries.ts b/packages/medusa-react/src/hooks/store/orders/queries.ts deleted file mode 100644 index ce8057f509..0000000000 --- a/packages/medusa-react/src/hooks/store/orders/queries.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { StoreGetOrdersParams, StoreOrdersRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const ORDERS_QUERY_KEY = `orders` as const - -export const orderKeys = { - ...queryKeysFactory( - ORDERS_QUERY_KEY - ), - cart: (cartId: string) => [...orderKeys.details(), "cart", cartId] as const, -} - -type OrderQueryKey = typeof orderKeys - -/** - * This hook retrieves an Order's details. - * - * @example - * import React from "react" - * import { useOrder } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const { - * order, - * isLoading, - * } = useOrder(orderId) - * - * return ( - *
- * {isLoading && Loading...} - * {order && {order.display_id}} - * - *
- * ) - * } - * - * export default Order - * - * @customNamespace Hooks.Store.Orders - * @category Queries - */ -export const useOrder = ( - /** - * The order's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - orderKeys.detail(id), - () => client.orders.retrieve(id), - options - ) - - return { ...data, ...rest } as const -} - -/** - * This hook retrieves an order's details by the ID of the cart that was used to create the order. - * - * @example - * import React from "react" - * import { useCartOrder } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Order = ({ cartId }: Props) => { - * const { - * order, - * isLoading, - * } = useCartOrder(cartId) - * - * return ( - *
- * {isLoading && Loading...} - * {order && {order.display_id}} - * - *
- * ) - * } - * - * export default Order - * - * @customNamespace Hooks.Store.Orders - * @category Queries - */ -export const useCartOrder = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - orderKeys.cart(cartId), - () => client.orders.retrieveByCartId(cartId), - options - ) - - return { ...data, ...rest } as const -} - -/** - * This hook looks up an order using filters. If the filters don't narrow down the results to a single order, a `404` response is returned with no orders. - * - * @example - * import React from "react" - * import { useOrders } from "medusa-react" - * - * type Props = { - * displayId: number - * email: string - * } - * - * const Order = ({ - * displayId, - * email - * }: Props) => { - * const { - * order, - * isLoading, - * } = useOrders({ - * display_id: displayId, - * email, - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {order && {order.display_id}} - * - *
- * ) - * } - * - * export default Order - * - * @customNamespace Hooks.Store.Orders - * @category Queries - */ -export const useOrders = ( - /** - * Filters used to retrieve the order. - */ - query: StoreGetOrdersParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - orderKeys.list(query), - () => client.orders.lookupOrder(query), - options - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/payment-collections/index.ts b/packages/medusa-react/src/hooks/store/payment-collections/index.ts deleted file mode 100644 index b9fdf95d87..0000000000 --- a/packages/medusa-react/src/hooks/store/payment-collections/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Store Payment Collection API Routes](https://docs.medusajs.com/api/store#payment-collections). - * - * A payment collection is useful for managing additional payments, such as for Order Edits, or installment payments. - * - * @customNamespace Hooks.Store.Payment Collections - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/store/payment-collections/mutations.ts b/packages/medusa-react/src/hooks/store/payment-collections/mutations.ts deleted file mode 100644 index bfc059a2fa..0000000000 --- a/packages/medusa-react/src/hooks/store/payment-collections/mutations.ts +++ /dev/null @@ -1,403 +0,0 @@ -import { Response } from "@medusajs/medusa-js" -import { - useMutation, - UseMutationOptions, - useQueryClient, -} from "@tanstack/react-query" - -import { - StorePaymentCollectionSessionsReq, - StorePaymentCollectionsRes, - StorePaymentCollectionsSessionRes, - StorePostPaymentCollectionsBatchSessionsAuthorizeReq, - StorePostPaymentCollectionsBatchSessionsReq, -} from "@medusajs/medusa" - -import { useMedusa } from "../../../contexts" -import { buildOptions } from "../../utils/buildOptions" -import { paymentCollectionQueryKeys } from "./queries" - -/** - * This hook creates, updates, or deletes a list of payment sessions of a Payment Collections. If a payment session is not provided in the `sessions` array, it's deleted. - * - * @example - * To add two new payment sessions: - * - * ```tsx - * import React from "react" - * import { useManageMultiplePaymentSessions } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const managePaymentSessions = useManageMultiplePaymentSessions( - * paymentCollectionId - * ) - * - * const handleManagePaymentSessions = () => { - * managePaymentSessions.mutate({ - * // Total amount = 10000 - * sessions: [ - * { - * provider_id: "stripe", - * amount: 5000, - * }, - * { - * provider_id: "manual", - * amount: 5000, - * }, - * ] - * }, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * ``` - * - * To update a payment session and another one by not including it in the payload: - * - * ```tsx - * import React from "react" - * import { useManageMultiplePaymentSessions } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const managePaymentSessions = useManageMultiplePaymentSessions( - * paymentCollectionId - * ) - * - * const handleManagePaymentSessions = () => { - * managePaymentSessions.mutate({ - * // Total amount = 10000 - * sessions: [ - * { - * provider_id: "stripe", - * amount: 10000, - * session_id: "ps_123456" - * }, - * ] - * }, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * ``` - * - * @customNamespace Hooks.Store.Payment Collections - * @category Mutations - */ -export const useManageMultiplePaymentSessions = ( - /** - * The payment collection's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - StorePostPaymentCollectionsBatchSessionsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: StorePostPaymentCollectionsBatchSessionsReq) => - client.paymentCollections.managePaymentSessionsBatch(id, payload), - buildOptions( - queryClient, - [ - paymentCollectionQueryKeys.lists(), - paymentCollectionQueryKeys.detail(id), - ], - options - ) - ) -} - -/** - * This hook creates a Payment Session for a payment provider in a Payment Collection. - * - * @example - * import React from "react" - * import { useManagePaymentSession } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const managePaymentSession = useManagePaymentSession( - * paymentCollectionId - * ) - * - * const handleManagePaymentSession = ( - * providerId: string - * ) => { - * managePaymentSession.mutate({ - * provider_id: providerId - * }, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - * @customNamespace Hooks.Store.Payment Collections - * @category Mutations - */ -export const useManagePaymentSession = ( - /** - * The payment collection's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - StorePaymentCollectionSessionsReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload: StorePaymentCollectionSessionsReq) => - client.paymentCollections.managePaymentSession(id, payload), - buildOptions( - queryClient, - [ - paymentCollectionQueryKeys.lists(), - paymentCollectionQueryKeys.detail(id), - ], - options - ) - ) -} - -/** - * This hook authorizes a Payment Session of a Payment Collection. - * - * @typeParamDefinition string - The payment session's ID. - * - * @example - * import React from "react" - * import { useAuthorizePaymentSession } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const authorizePaymentSession = useAuthorizePaymentSession( - * paymentCollectionId - * ) - * // ... - * - * const handleAuthorizePayment = (paymentSessionId: string) => { - * authorizePaymentSession.mutate(paymentSessionId, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - * @customNamespace Hooks.Store.Payment Collections - * @category Mutations - */ -export const useAuthorizePaymentSession = ( - /** - * The payment collection's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - /** - * The payment session's ID. - */ - string - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (session_id: string) => - client.paymentCollections.authorizePaymentSession(id, session_id), - buildOptions( - queryClient, - [ - paymentCollectionQueryKeys.lists(), - paymentCollectionQueryKeys.detail(id), - ], - options - ) - ) -} - -/** - * This hook authorize the Payment Sessions of a Payment Collection. - * - * @example - * import React from "react" - * import { useAuthorizePaymentSessionsBatch } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const authorizePaymentSessions = useAuthorizePaymentSessionsBatch( - * paymentCollectionId - * ) - * // ... - * - * const handleAuthorizePayments = (paymentSessionIds: string[]) => { - * authorizePaymentSessions.mutate({ - * session_ids: paymentSessionIds - * }, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - * @customNamespace Hooks.Store.Payment Collections - * @category Mutations - */ -export const useAuthorizePaymentSessionsBatch = ( - /** - * The payment collection's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - StorePostPaymentCollectionsBatchSessionsAuthorizeReq - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (payload) => - client.paymentCollections.authorizePaymentSessionsBatch(id, payload), - buildOptions( - queryClient, - [ - paymentCollectionQueryKeys.lists(), - paymentCollectionQueryKeys.detail(id), - ], - options - ) - ) -} - -/** - * This hook refreshes a Payment Session's data to ensure that it is in sync with the Payment Collection. - * - * @typeParamDefinition string - The payment session's ID. - * - * @example - * import React from "react" - * import { usePaymentCollectionRefreshPaymentSession } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const refreshPaymentSession = usePaymentCollectionRefreshPaymentSession( - * paymentCollectionId - * ) - * // ... - * - * const handleRefreshPaymentSession = (paymentSessionId: string) => { - * refreshPaymentSession.mutate(paymentSessionId, { - * onSuccess: ({ payment_session }) => { - * console.log(payment_session.status) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - * @customNamespace Hooks.Store.Payment Collections - * @category Mutations - */ -export const usePaymentCollectionRefreshPaymentSession = ( - /** - * The payment collection's ID. - */ - id: string, - options?: UseMutationOptions< - Response, - Error, - /** - * The payment session's ID. - */ - string - > -) => { - const { client } = useMedusa() - const queryClient = useQueryClient() - - return useMutation( - (session_id: string) => - client.paymentCollections.refreshPaymentSession(id, session_id), - buildOptions( - queryClient, - [ - paymentCollectionQueryKeys.lists(), - paymentCollectionQueryKeys.detail(id), - ], - options - ) - ) -} diff --git a/packages/medusa-react/src/hooks/store/payment-collections/queries.ts b/packages/medusa-react/src/hooks/store/payment-collections/queries.ts deleted file mode 100644 index 64bd2e3e38..0000000000 --- a/packages/medusa-react/src/hooks/store/payment-collections/queries.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { StorePaymentCollectionsRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const PAYMENT_COLLECTION_QUERY_KEY = `paymentCollection` as const - -export const paymentCollectionQueryKeys = queryKeysFactory< - typeof PAYMENT_COLLECTION_QUERY_KEY ->(PAYMENT_COLLECTION_QUERY_KEY) - -type PaymentCollectionKey = typeof paymentCollectionQueryKeys - -/** - * This hook retrieves a Payment Collection's details. - * - * @example - * import React from "react" - * import { usePaymentCollection } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const { - * payment_collection, - * isLoading - * } = usePaymentCollection( - * paymentCollectionId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {payment_collection && ( - * {payment_collection.status} - * )} - *
- * ) - * } - * - * export default PaymentCollection - * - * @customNamespace Hooks.Store.Payment Collections - * @category Queries - */ -export const usePaymentCollection = ( - /** - * The payment collection's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - paymentCollectionQueryKeys.detail(id), - () => client.paymentCollections.retrieve(id), - options - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/product-categories/index.ts b/packages/medusa-react/src/hooks/store/product-categories/index.ts deleted file mode 100644 index 63e101bbd8..0000000000 --- a/packages/medusa-react/src/hooks/store/product-categories/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @packageDocumentation - * - * Queries listed here are used to send requests to the [Store Product Category API Routes](https://docs.medusajs.com/api/store#product-categories_getproductcategories). - * - * Products can be categoriezed into categories. A product can be associated more than one category. - * - * Related Guide: [How to use product categories in a storefront](https://docs.medusajs.com/modules/products/storefront/use-categories). - * - * @featureFlag product_categories - * - * @customNamespace Hooks.Store.Product Categories - */ - -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/store/product-categories/queries.ts b/packages/medusa-react/src/hooks/store/product-categories/queries.ts deleted file mode 100644 index 6e8a062467..0000000000 --- a/packages/medusa-react/src/hooks/store/product-categories/queries.ts +++ /dev/null @@ -1,286 +0,0 @@ -import { - StoreGetProductCategoriesParams, - StoreGetProductCategoriesRes, - StoreGetProductCategoriesCategoryParams, - StoreGetProductCategoriesCategoryRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" - -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const STORE_PRODUCT_CATEGORIES_QUERY_KEY = `product_categories` as const -export const storeProductCategoryKeys = queryKeysFactory( - STORE_PRODUCT_CATEGORIES_QUERY_KEY -) -type ProductCategoryQueryKeys = typeof storeProductCategoryKeys - -/** - * This hook retrieves a list of product categories. The product categories can be filtered by fields such as `handle` or `q` passed in the `query` parameter. - * The product categories can also be paginated. This hook can also be used to retrieve a product category by its handle. - * - * @example - * To list product categories: - * - * ```tsx - * import React from "react" - * import { useProductCategories } from "medusa-react" - * - * function Categories() { - * const { - * product_categories, - * isLoading, - * } = useProductCategories() - * - * return ( - *
- * {isLoading && Loading...} - * {product_categories && !product_categories.length && ( - * No Categories - * )} - * {product_categories && product_categories.length > 0 && ( - *
    - * {product_categories.map( - * (category) => ( - *
  • {category.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Categories - * ``` - * - * To retrieve a product category by its handle: - * - * ```tsx - * import React from "react" - * import { useProductCategories } from "medusa-react" - * - * function Categories( - * handle: string - * ) { - * const { - * product_categories, - * isLoading, - * } = useProductCategories({ - * handle - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {product_categories && !product_categories.length && ( - * No Categories - * )} - * {product_categories && product_categories.length > 0 && ( - *
    - * {product_categories.map( - * (category) => ( - *
  • {category.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Categories - * ``` - * - * To specify relations that should be retrieved within the product categories: - * - * ```tsx - * import React from "react" - * import { useProductCategories } from "medusa-react" - * - * function Categories( - * handle: string - * ) { - * const { - * product_categories, - * isLoading, - * } = useProductCategories({ - * handle, - * expand: "products" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {product_categories && !product_categories.length && ( - * No Categories - * )} - * {product_categories && product_categories.length > 0 && ( - *
    - * {product_categories.map( - * (category) => ( - *
  • {category.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Categories - * ``` - * - * By default, only the first `100` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import { useProductCategories } from "medusa-react" - * - * function Categories( - * handle: string - * ) { - * const { - * product_categories, - * limit, - * offset, - * isLoading, - * } = useProductCategories({ - * handle, - * expand: "products", - * limit: 50, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {product_categories && !product_categories.length && ( - * No Categories - * )} - * {product_categories && product_categories.length > 0 && ( - *
    - * {product_categories.map( - * (category) => ( - *
  • {category.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Categories - * ``` - * - * @customNamespace Hooks.Store.Product Categories - * @category Queries - */ -export const useProductCategories = ( - /** - * Filters and pagination configurations to apply on the retrieved product categories. - */ - query?: StoreGetProductCategoriesParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - storeProductCategoryKeys.list(query), - () => client.productCategories.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a Product Category's details. - * - * @example - * A simple example that retrieves a product category by its ID: - * - * ```tsx - * import React from "react" - * import { useProductCategory } from "medusa-react" - * - * type Props = { - * categoryId: string - * } - * - * const Category = ({ categoryId }: Props) => { - * const { product_category, isLoading } = useProductCategory( - * categoryId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {product_category && {product_category.name}} - *
- * ) - * } - * - * export default Category - * ``` - * - * To specify relations that should be retrieved: - * - * ```tsx - * import React from "react" - * import { useProductCategory } from "medusa-react" - * - * type Props = { - * categoryId: string - * } - * - * const Category = ({ categoryId }: Props) => { - * const { product_category, isLoading } = useProductCategory( - * categoryId, - * { - * expand: "products" - * } - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {product_category && {product_category.name}} - *
- * ) - * } - * - * export default Category - * ``` - * - * @customNamespace Hooks.Store.Product Categories - * @category Queries - */ -export const useProductCategory = ( - /** - * The product category's ID. - */ - id: string, - /** - * Configurations to apply on the retrieved product categories. - */ - query?: StoreGetProductCategoriesCategoryParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - storeProductCategoryKeys.detail(id), - () => client.productCategories.retrieve(id, query), - options - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/product-tags/index.ts b/packages/medusa-react/src/hooks/store/product-tags/index.ts deleted file mode 100644 index 54c03683a3..0000000000 --- a/packages/medusa-react/src/hooks/store/product-tags/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @packageDocumentation - * - * Queries listed here are used to send requests to the [Store Product Tag API Routes](https://docs.medusajs.com/api/store#product-tags). - * - * Product tags are string values that can be used to filter products by. - * Products can have more than one tag, and products can share tags. - * - * @customNamespace Hooks.Store.Product Tags - */ - -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/store/product-tags/queries.ts b/packages/medusa-react/src/hooks/store/product-tags/queries.ts deleted file mode 100644 index 894f459599..0000000000 --- a/packages/medusa-react/src/hooks/store/product-tags/queries.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { - StoreGetProductTagsParams, - StoreProductTagsListRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const PRODUCT_TAGS_QUERY_KEY = `product_tags` as const - -export const productTagKeys = queryKeysFactory(PRODUCT_TAGS_QUERY_KEY) - -type ProductTypesQueryKeys = typeof productTagKeys - -/** - * This hook retrieves a list of product tags. The product tags can be filtered by fields such as `id` or `q` - * passed in the `query` parameter. The product tags can also be sorted or paginated. - * - * @example - * To list product tags: - * - * ```tsx - * import React from "react" - * import { useProductTags } from "medusa-react" - * - * function Tags() { - * const { - * product_tags, - * isLoading, - * } = useProductTags() - * - * return ( - *
- * {isLoading && Loading...} - * {product_tags && !product_tags.length && ( - * No Product Tags - * )} - * {product_tags && product_tags.length > 0 && ( - *
    - * {product_tags.map( - * (tag) => ( - *
  • {tag.value}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Tags - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useProductTags } from "medusa-react" - * - * function Tags() { - * const { - * product_tags, - * limit, - * offset, - * isLoading, - * } = useProductTags({ - * limit: 10, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {product_tags && !product_tags.length && ( - * No Product Tags - * )} - * {product_tags && product_tags.length > 0 && ( - *
    - * {product_tags.map( - * (tag) => ( - *
  • {tag.value}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Tags - * ``` - * - * @customNamespace Hooks.Store.Product Tags - * @category Queries - */ -export const useProductTags = ( - /** - * Filters and pagination configurations to apply on the retrieved product tags. - */ - query?: StoreGetProductTagsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - productTagKeys.list(query), - () => client.productTags.list(query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/product-types/index.ts b/packages/medusa-react/src/hooks/store/product-types/index.ts deleted file mode 100644 index d2bd45d332..0000000000 --- a/packages/medusa-react/src/hooks/store/product-types/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @packageDocumentation - * - * Queries listed here are used to send requests to the [Store Product Type API Routes](https://docs.medusajs.com/api/store#product-types). - * - * Product types are string values that can be used to filter products by. - * Products can have more than one tag, and products can share types. - * - * @customNamespace Hooks.Store.Product Types - */ - -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/store/product-types/queries.ts b/packages/medusa-react/src/hooks/store/product-types/queries.ts deleted file mode 100644 index e0e47c26b8..0000000000 --- a/packages/medusa-react/src/hooks/store/product-types/queries.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { - StoreGetProductTypesParams, - StoreProductTypesListRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils" - -const PRODUCT_TYPES_QUERY_KEY = `product_types` as const - -export const productTypeKeys = queryKeysFactory(PRODUCT_TYPES_QUERY_KEY) - -type ProductTypesQueryKeys = typeof productTypeKeys - -/** - * This hook retrieves a list of product types. The product types can be filtered by fields such as `value` or `q` passed - * in the `query` parameter. The product types can also be sorted or paginated. - * - * @example - * To list product types: - * - * ```tsx - * import React from "react" - * import { useProductTypes } from "medusa-react" - * - * function Types() { - * const { - * product_types, - * isLoading, - * } = useProductTypes() - * - * return ( - *
- * {isLoading && Loading...} - * {product_types && !product_types.length && ( - * No Product Types - * )} - * {product_types && product_types.length > 0 && ( - *
    - * {product_types.map( - * (type) => ( - *
  • {type.value}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Types - * ``` - * - * By default, only the first `20` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useProductTypes } from "medusa-react" - * - * function Types() { - * const { - * product_types, - * limit, - * offset, - * isLoading, - * } = useProductTypes({ - * limit: 10, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {product_types && !product_types.length && ( - * No Product Types - * )} - * {product_types && product_types.length > 0 && ( - *
    - * {product_types.map( - * (type) => ( - *
  • {type.value}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Types - * ``` - * - * @customNamespace Hooks.Store.Product Types - * @category Queries - */ -export const useProductTypes = ( - /** - * Filters and pagination configurations to apply on retrieved product types. - */ - query?: StoreGetProductTypesParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - productTypeKeys.list(query), - () => client.productTypes.list(query), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/products/index.ts b/packages/medusa-react/src/hooks/store/products/index.ts deleted file mode 100644 index e65d230b98..0000000000 --- a/packages/medusa-react/src/hooks/store/products/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @packageDocumentation - * - * Queries listed here are used to send requests to the [Store Product API Routes](https://docs.medusajs.com/api/store#products). - * - * Products are saleable items in a store. This also includes [saleable gift cards](https://docs.medusajs.com/modules/gift-cards/storefront/use-gift-cards) in a store. - * Using the methods in this class, you can filter products by categories, collections, sales channels, and more. - * - * Related Guide: [How to show products in a storefront](https://docs.medusajs.com/modules/products/storefront/show-products). - * - * @customNamespace Hooks.Store.Products - */ - -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/store/products/queries.ts b/packages/medusa-react/src/hooks/store/products/queries.ts deleted file mode 100644 index 08b07b9ddd..0000000000 --- a/packages/medusa-react/src/hooks/store/products/queries.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { - StoreGetProductsParams, - StoreProductsListRes, - StoreProductsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const PRODUCTS_QUERY_KEY = `products` as const - -export const productKeys = queryKeysFactory< - typeof PRODUCTS_QUERY_KEY, - StoreGetProductsParams ->(PRODUCTS_QUERY_KEY) -type ProductQueryKey = typeof productKeys - -/** - * This hook retrieves a list of products. The products can be filtered by fields such as `id` or `q` passed in the `query` parameter. The products can also be sorted or paginated. - * This hook can also be used to retrieve a product by its handle. - * - * For accurate and correct pricing of the products based on the customer's context, it's highly recommended to pass fields such as - * `region_id`, `currency_code`, and `cart_id` when available. - * - * Passing `sales_channel_id` ensures retrieving only products available in the specified sales channel. - * You can alternatively use a publishable API key in the request header instead of passing a `sales_channel_id`. - * - * @example - * To list products: - * - * ```tsx - * import React from "react" - * import { useProducts } from "medusa-react" - * - * const Products = () => { - * const { products, isLoading } = useProducts() - * - * return ( - *
- * {isLoading && Loading...} - * {products && !products.length && No Products} - * {products && products.length > 0 && ( - *
    - * {products.map((product) => ( - *
  • {product.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Products - * ``` - * - * To specify relations that should be retrieved within the products: - * - * ```tsx - * import React from "react" - * import { useProducts } from "medusa-react" - * - * const Products = () => { - * const { products, isLoading } = useProducts({ - * expand: "variants" - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {products && !products.length && No Products} - * {products && products.length > 0 && ( - *
    - * {products.map((product) => ( - *
  • {product.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Products - * ``` - * - * By default, only the first `100` records are retrieved. You can control pagination by specifying the `limit` and `offset` properties: - * - * ```tsx - * import React from "react" - * import { useProducts } from "medusa-react" - * - * const Products = () => { - * const { - * products, - * limit, - * offset, - * isLoading - * } = useProducts({ - * expand: "variants", - * limit: 50, - * offset: 0 - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {products && !products.length && No Products} - * {products && products.length > 0 && ( - *
    - * {products.map((product) => ( - *
  • {product.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Products - * ``` - * - * @customNamespace Hooks.Store.Products - * @category Queries - */ -export const useProducts = ( - /** - * Filters and pagination configurations to apply on the retrieved products. - */ - query?: StoreGetProductsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - productKeys.list(query), - () => client.products.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a Product's details. For accurate and correct pricing of the product based on the customer's context, it's highly recommended to pass fields such as - * `region_id`, `currency_code`, and `cart_id` when available. - * - * Passing `sales_channel_id` ensures retrieving only products available in the current sales channel. - * You can alternatively use a publishable API key in the request header instead of passing a `sales_channel_id`. - * - * @example - * import React from "react" - * import { useProduct } from "medusa-react" - * - * type Props = { - * productId: string - * } - * - * const Product = ({ productId }: Props) => { - * const { product, isLoading } = useProduct(productId) - * - * return ( - *
- * {isLoading && Loading...} - * {product && {product.title}} - *
- * ) - * } - * - * export default Product - * - * @customNamespace Hooks.Store.Products - * @category Queries - */ -export const useProduct = ( - /** - * The product's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - productKeys.detail(id), - () => client.products.retrieve(id), - options - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/regions/index.ts b/packages/medusa-react/src/hooks/store/regions/index.ts deleted file mode 100644 index 339bc901a8..0000000000 --- a/packages/medusa-react/src/hooks/store/regions/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @packageDocumentation - * - * Queries listed here are used to send requests to the [Store Region API Routes](https://docs.medusajs.com/api/store#regions_getregions). - * - * Regions are different countries or geographical regions that the commerce store serves customers in. - * Customers can choose what region they're in, which can be used to change the prices shown based on the region and its currency. - * - * Related Guide: [How to use regions in a storefront](https://docs.medusajs.com/modules/regions-and-currencies/storefront/use-regions). - * - * @customNamespace Hooks.Store.Regions - */ - -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/store/regions/queries.ts b/packages/medusa-react/src/hooks/store/regions/queries.ts deleted file mode 100644 index 95c9a20083..0000000000 --- a/packages/medusa-react/src/hooks/store/regions/queries.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { StoreRegionsListRes, StoreRegionsRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const REGIONS_QUERY_KEY = `regions` as const - -const regionsKey = queryKeysFactory(REGIONS_QUERY_KEY) - -type RegionQueryType = typeof regionsKey - -/** - * This hook retrieves a list of regions. This hook is useful to show the customer all available regions to choose from. - * - * @example - * import React from "react" - * import { useRegions } from "medusa-react" - * - * const Regions = () => { - * const { regions, isLoading } = useRegions() - * - * return ( - *
- * {isLoading && Loading...} - * {regions?.length && ( - *
    - * {regions.map((region) => ( - *
  • - * {region.name} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Regions - * - * @customNamespace Hooks.Store.Regions - * @category Queries - */ -export const useRegions = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - regionsKey.lists(), - () => client.regions.list(), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a Region's details. - * - * @example - * import React from "react" - * import { useRegion } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ regionId }: Props) => { - * const { region, isLoading } = useRegion( - * regionId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {region && {region.name}} - *
- * ) - * } - * - * export default Region - * - * @customNamespace Hooks.Store.Regions - * @category Queries - */ -export const useRegion = ( - /** - * The region's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - regionsKey.detail(id), - () => client.regions.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/return-reasons/index.ts b/packages/medusa-react/src/hooks/store/return-reasons/index.ts deleted file mode 100644 index 27af68eaed..0000000000 --- a/packages/medusa-react/src/hooks/store/return-reasons/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @packageDocumentation - * - * Queries listed here are used to send requests to the [Store Return Reason API Routes](https://docs.medusajs.com/api/store#return-reasons). - * - * Return reasons are key-value pairs that are used to specify why an order return is being created. - * - * @customNamespace Hooks.Store.Return Reasons - */ - -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/store/return-reasons/queries.ts b/packages/medusa-react/src/hooks/store/return-reasons/queries.ts deleted file mode 100644 index 6717fb161f..0000000000 --- a/packages/medusa-react/src/hooks/store/return-reasons/queries.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { - StoreReturnReasonsListRes, - StoreReturnReasonsRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const RETURNS_REASONS_QUERY_KEY = `return_reasons` as const - -const returnReasonsKey = queryKeysFactory(RETURNS_REASONS_QUERY_KEY) - -type ReturnReasonsQueryKey = typeof returnReasonsKey - -/** - * This hook retrieves a list of Return Reasons. This is useful when implementing a Create Return flow in the storefront. - * - * @example - * import React from "react" - * import { useReturnReasons } from "medusa-react" - * - * const ReturnReasons = () => { - * const { - * return_reasons, - * isLoading - * } = useReturnReasons() - * - * return ( - *
- * {isLoading && Loading...} - * {return_reasons?.length && ( - *
    - * {return_reasons.map((returnReason) => ( - *
  • - * {returnReason.label} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ReturnReasons - * - * @customNamespace Hooks.Store.Return Reasons - * @category Queries - */ -export const useReturnReasons = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - returnReasonsKey.lists(), - () => client.returnReasons.list(), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a Return Reason's details. - * - * @example - * import React from "react" - * import { useReturnReason } from "medusa-react" - * - * type Props = { - * returnReasonId: string - * } - * - * const ReturnReason = ({ returnReasonId }: Props) => { - * const { - * return_reason, - * isLoading - * } = useReturnReason( - * returnReasonId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {return_reason && {return_reason.label}} - *
- * ) - * } - * - * export default ReturnReason - * - * @customNamespace Hooks.Store.Return Reasons - * @category Queries - */ -export const useReturnReason = ( - /** - * The return reason's ID. - */ - id: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - returnReasonsKey.detail(id), - () => client.returnReasons.retrieve(id), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/returns/index.ts b/packages/medusa-react/src/hooks/store/returns/index.ts deleted file mode 100644 index df86405a19..0000000000 --- a/packages/medusa-react/src/hooks/store/returns/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @packageDocumentation - * - * Mutations listed here are used to send requests to the [Store Return API Routes](https://docs.medusajs.com/api/store#returns). - * - * A return can be created by a customer to return items in an order. - * - * Related Guide: [How to create a return in a storefront](https://docs.medusajs.com/modules/orders/storefront/create-return). - * - * @customNamespace Hooks.Store.Returns - */ - -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/store/returns/mutations.ts b/packages/medusa-react/src/hooks/store/returns/mutations.ts deleted file mode 100644 index 84bf798d1b..0000000000 --- a/packages/medusa-react/src/hooks/store/returns/mutations.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { StorePostReturnsReq, StoreReturnsRes } from "@medusajs/medusa" -import { useMutation, UseMutationOptions } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" - -/** - * This hook creates a return for an order. If a return shipping method is specified, the return is automatically fulfilled. - * - * @example - * import React from "react" - * import { useCreateReturn } from "medusa-react" - * - * type CreateReturnData = { - * items: { - * item_id: string, - * quantity: number - * }[] - * return_shipping: { - * option_id: string - * } - * } - * - * type Props = { - * orderId: string - * } - * - * const CreateReturn = ({ orderId }: Props) => { - * const createReturn = useCreateReturn() - * // ... - * - * const handleCreate = (data: CreateReturnData) => { - * createReturn.mutate({ - * ...data, - * order_id: orderId - * }, { - * onSuccess: ({ return: returnData }) => { - * console.log(returnData.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateReturn - * - * @customNamespace Hooks.Store.Returns - * @category Mutations - */ -export const useCreateReturn = ( - options?: UseMutationOptions -) => { - const { client } = useMedusa() - return useMutation( - (data: StorePostReturnsReq) => client.returns.create(data), - options - ) -} diff --git a/packages/medusa-react/src/hooks/store/shipping-options/index.ts b/packages/medusa-react/src/hooks/store/shipping-options/index.ts deleted file mode 100644 index a4718f66c7..0000000000 --- a/packages/medusa-react/src/hooks/store/shipping-options/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @packageDocumentation - * - * Queries listed here are used to send requests to the [Store Shipping Option API Routes](https://docs.medusajs.com/api/store#shipping-options). - * - * A shipping option is used to define the available shipping methods during checkout or when creating a return. - * - * Related Guide: [Shipping Option architecture](https://docs.medusajs.com/modules/carts-and-checkout/shipping#shipping-option). - * - * @customNamespace Hooks.Store.Shipping Options - */ - -export * from "./queries" diff --git a/packages/medusa-react/src/hooks/store/shipping-options/queries.ts b/packages/medusa-react/src/hooks/store/shipping-options/queries.ts deleted file mode 100644 index d6ebc7e5d4..0000000000 --- a/packages/medusa-react/src/hooks/store/shipping-options/queries.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { - StoreGetShippingOptionsParams, - StoreShippingOptionsListRes, -} from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const SHIPPING_OPTION_QUERY_KEY = `shipping_options` as const - -const shippingOptionKey = { - ...queryKeysFactory(SHIPPING_OPTION_QUERY_KEY), - cart: (cartId: string) => [...shippingOptionKey.all, "cart", cartId] as const, -} - -type ShippingOptionQueryKey = typeof shippingOptionKey - -/** - * This hook retrieves a list of shipping options. The shipping options can be filtered using the `query` parameter. - * - * @example - * import React from "react" - * import { useShippingOptions } from "medusa-react" - * - * const ShippingOptions = () => { - * const { - * shipping_options, - * isLoading, - * } = useShippingOptions() - * - * return ( - *
- * {isLoading && Loading...} - * {shipping_options?.length && - * shipping_options?.length > 0 && ( - *
    - * {shipping_options?.map((shipping_option) => ( - *
  • - * {shipping_option.id} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ShippingOptions - * - * @customNamespace Hooks.Store.Shipping Options - * @category Queries - */ -export const useShippingOptions = ( - /** - * The filters to apply on the shipping options. - */ - query?: StoreGetShippingOptionsParams, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - shippingOptionKey.list(query), - async () => client.shippingOptions.list(query), - options - ) - return { ...data, ...rest } as const -} - -/** - * This hook retrieves a list of shipping options available for a cart. - * - * @example - * import React from "react" - * import { useCartShippingOptions } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const ShippingOptions = ({ cartId }: Props) => { - * const { shipping_options, isLoading } = - * useCartShippingOptions(cartId) - * - * return ( - *
- * {isLoading && Loading...} - * {shipping_options && !shipping_options.length && ( - * No shipping options - * )} - * {shipping_options && ( - *
    - * {shipping_options.map( - * (shipping_option) => ( - *
  • - * {shipping_option.name} - *
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default ShippingOptions - * - * @customNamespace Hooks.Store.Shipping Options - * @category Queries - */ -export const useCartShippingOptions = ( - /** - * The cart's ID. - */ - cartId: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - shippingOptionKey.cart(cartId), - async () => client.shippingOptions.listCartOptions(cartId), - options - ) - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/store/swaps/index.ts b/packages/medusa-react/src/hooks/store/swaps/index.ts deleted file mode 100644 index f6289d972c..0000000000 --- a/packages/medusa-react/src/hooks/store/swaps/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @packageDocumentation - * - * Queries and Mutations listed here are used to send requests to the [Store Swap API Routes](https://docs.medusajs.com/api/store#swaps). - * - * A swap is created by a customer or an admin to exchange an item with a new one. - * Creating a swap implicitely includes creating a return for the item being exchanged. - * - * Related Guide: [How to create a swap in a storefront](https://docs.medusajs.com/modules/orders/storefront/create-swap) - * - * @customNamespace Hooks.Store.Swaps - */ - -export * from "./queries" -export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/store/swaps/mutations.ts b/packages/medusa-react/src/hooks/store/swaps/mutations.ts deleted file mode 100644 index 6a11540aad..0000000000 --- a/packages/medusa-react/src/hooks/store/swaps/mutations.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { StorePostSwapsReq, StoreSwapsRes } from "@medusajs/medusa" -import { useMutation, UseMutationOptions } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" - -/** - * This hook creates a Swap for an Order. This will also create a return and associate it with the swap. If a return shipping option is specified, the return will automatically be fulfilled. - * To complete the swap, you must use the {@link Hooks.Store.Carts.useCompleteCart | useCompleteCart} hook passing it the ID of the swap's cart. - * - * An idempotency key will be generated if none is provided in the header `Idempotency-Key` and added to - * the response. If an error occurs during swap creation or the request is interrupted for any reason, the swap creation can be retried by passing the idempotency - * key in the `Idempotency-Key` header. - * - * @example - * import React from "react" - * import { useCreateSwap } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * type CreateData = { - * return_items: { - * item_id: string - * quantity: number - * }[] - * additional_items: { - * variant_id: string - * quantity: number - * }[] - * return_shipping_option: string - * } - * - * const CreateSwap = ({ - * orderId - * }: Props) => { - * const createSwap = useCreateSwap() - * // ... - * - * const handleCreate = ( - * data: CreateData - * ) => { - * createSwap.mutate({ - * ...data, - * order_id: orderId - * }, { - * onSuccess: ({ swap }) => { - * console.log(swap.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateSwap - * - * @customNamespace Hooks.Store.Swaps - * @category Mutations - */ -export const useCreateSwap = ( - options?: UseMutationOptions -) => { - const { client } = useMedusa() - return useMutation( - (data: StorePostSwapsReq) => client.swaps.create(data), - options - ) -} diff --git a/packages/medusa-react/src/hooks/store/swaps/queries.ts b/packages/medusa-react/src/hooks/store/swaps/queries.ts deleted file mode 100644 index 58a6cf882a..0000000000 --- a/packages/medusa-react/src/hooks/store/swaps/queries.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { StoreSwapsRes } from "@medusajs/medusa" -import { Response } from "@medusajs/medusa-js" -import { useQuery } from "@tanstack/react-query" -import { useMedusa } from "../../../contexts" -import { UseQueryOptionsWrapper } from "../../../types" -import { queryKeysFactory } from "../../utils/index" - -const SWAPS_QUERY_KEY = `swaps` as const - -const swapKey = { - ...queryKeysFactory(SWAPS_QUERY_KEY), - cart: (cartId: string) => [...swapKey.all, "cart", cartId] as const, -} - -type SwapQueryKey = typeof swapKey - -/** - * This hook retrieves a Swap's details by the ID of its cart. - * - * @example - * import React from "react" - * import { useCartSwap } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Swap = ({ cartId }: Props) => { - * const { - * swap, - * isLoading, - * } = useCartSwap(cartId) - * - * return ( - *
- * {isLoading && Loading...} - * {swap && {swap.id}} - * - *
- * ) - * } - * - * export default Swap - * - * @customNamespace Hooks.Store.Swaps - * @category Queries - */ -export const useCartSwap = ( - /** - * The ID of the swap's cart. - */ - cartId: string, - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - swapKey.cart(cartId), - () => client.swaps.retrieveByCartId(cartId), - options - ) - - return { ...data, ...rest } as const -} diff --git a/packages/medusa-react/src/hooks/utils/buildOptions.ts b/packages/medusa-react/src/hooks/utils/buildOptions.ts deleted file mode 100644 index dd39bb21fc..0000000000 --- a/packages/medusa-react/src/hooks/utils/buildOptions.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - QueryClient, - QueryKey, - UseMutationOptions, -} from "@tanstack/react-query" - -export const buildOptions = < - TData, - TError, - TVariables, - TContext, - TKey extends QueryKey ->( - queryClient: QueryClient, - queryKey?: TKey, - options?: UseMutationOptions -): UseMutationOptions => { - return { - ...options, - onSuccess: (...args) => { - if (options?.onSuccess) { - return options.onSuccess(...args) - } - - if (queryKey !== undefined) { - queryKey.forEach((key) => { - queryClient.invalidateQueries({ queryKey: key as QueryKey }) - }) - } - }, - } -} diff --git a/packages/medusa-react/src/hooks/utils/index.ts b/packages/medusa-react/src/hooks/utils/index.ts deleted file mode 100644 index 21a86250f7..0000000000 --- a/packages/medusa-react/src/hooks/utils/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./queryKeysFactory" -export * from "./useLocalStorage" diff --git a/packages/medusa-react/src/hooks/utils/queryKeysFactory.ts b/packages/medusa-react/src/hooks/utils/queryKeysFactory.ts deleted file mode 100644 index b840dab3ac..0000000000 --- a/packages/medusa-react/src/hooks/utils/queryKeysFactory.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { TQueryKey } from "../../types" - -export const queryKeysFactory = < - T, - TListQueryType = any, - TDetailQueryType = string ->( - globalKey: T -) => { - const queryKeyFactory: TQueryKey = { - all: [globalKey], - lists: () => [...queryKeyFactory.all, "list"], - list: (query?: TListQueryType) => [...queryKeyFactory.lists(), { query }], - details: () => [...queryKeyFactory.all, "detail"], - detail: (id: TDetailQueryType) => [...queryKeyFactory.details(), id], - } - return queryKeyFactory -} diff --git a/packages/medusa-react/src/hooks/utils/useLocalStorage.ts b/packages/medusa-react/src/hooks/utils/useLocalStorage.ts deleted file mode 100644 index 93f99d4f97..0000000000 --- a/packages/medusa-react/src/hooks/utils/useLocalStorage.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from "react" - -export const useLocalStorage = (key: string, initialState: string) => { - const [item, setItem] = React.useState(() => { - try { - const item = - typeof window !== "undefined" && window.localStorage.getItem(key) - - return item || initialState - } catch (err) { - return initialState - } - }) - - const save = (data: string) => { - setItem(data) - - if (typeof window !== "undefined") { - window.localStorage.setItem(key, data) - } - } - - const remove = () => { - if (typeof window !== "undefined") { - window.localStorage.removeItem(key) - } - } - - return [item, save, remove] as const -} diff --git a/packages/medusa-react/src/index.ts b/packages/medusa-react/src/index.ts deleted file mode 100644 index 3745e361d9..0000000000 --- a/packages/medusa-react/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./contexts" -export * from "./helpers" -export * from "./hooks" -export * from "./types" diff --git a/packages/medusa-react/src/types.ts b/packages/medusa-react/src/types.ts deleted file mode 100644 index b1ebdefc97..0000000000 --- a/packages/medusa-react/src/types.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - ProductVariant as ProductVariantEntity, - Region, - StoreCartsRes, -} from "@medusajs/medusa" -import { QueryKey, UseQueryOptions } from "@tanstack/react-query" - -export type UseQueryOptionsWrapper< - // Return type of queryFn - TQueryFn = unknown, - // Type thrown in case the queryFn rejects - E = Error, - // Query key type - TQueryKey extends QueryKey = QueryKey -> = Omit< - UseQueryOptions, - "queryKey" | "queryFn" | "select" | "refetchInterval" -> - -// Choose only a subset of the type Region to allow for some flexibility -export type RegionInfo = Pick -export type ProductVariant = ConvertDateToString< - Omit -> - -export type ProductVariantInfo = Pick - -type ConvertDateToString = { - [P in keyof T]: T[P] extends Date ? Date | string : T[P] -} - -export type Cart = StoreCartsRes["cart"] - -export type TQueryKey = { - all: [TKey] - lists: () => [...TQueryKey["all"], "list"] - list: ( - query?: TListQuery - ) => [ - ...ReturnType["lists"]>, - { query: TListQuery | undefined } - ] - details: () => [...TQueryKey["all"], "detail"] - detail: ( - id: TDetailQuery - ) => [...ReturnType["details"]>, TDetailQuery] -} diff --git a/packages/medusa-react/src/utils/index.ts b/packages/medusa-react/src/utils/index.ts deleted file mode 100644 index afcbe0b741..0000000000 --- a/packages/medusa-react/src/utils/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const isObject = (input: any) => input instanceof Object -export const isArray = (input: any) => Array.isArray(input) -export const isEmpty = (input: any) => { - return ( - input === null || - input === undefined || - (isObject(input) && Object.keys(input).length === 0) || - (isArray(input) && (input as any[]).length === 0) || - (typeof input === "string" && input.trim().length === 0) - ) -} diff --git a/packages/medusa-react/stories/Carts.stories.tsx b/packages/medusa-react/stories/Carts.stories.tsx deleted file mode 100644 index 8dcc53858b..0000000000 --- a/packages/medusa-react/stories/Carts.stories.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Meta } from "@storybook/react" -import React from "react" -import { useGetCart } from "../src" -import Layout from "./components/Layout" - -const Cart = ({ showHookData, id }) => { - const data = useGetCart(id) - return ( - -

Cart: {id}

-
- {data?.cart?.email} - {data?.cart?.total} -
-
- ) -} - -const meta: Meta = { - title: "Carts", - argTypes: { - showHookData: { - name: "Show hook data", - description: - "Whether or not story should display JSON of data returned from hook", - control: { - type: "boolean", - }, - defaultValue: true, - }, - }, - parameters: { - controls: { expanded: true }, - }, -} - -export default meta - -export const GetOne = (args: { showHookData: boolean; id: string }) => ( - -) - -GetOne.argTypes = { - id: { - control: { - type: "text", - }, - name: "cart id", - defaultValue: "cart_...", - }, -} diff --git a/packages/medusa-react/stories/Collections.stories.tsx b/packages/medusa-react/stories/Collections.stories.tsx deleted file mode 100644 index 52edf210fa..0000000000 --- a/packages/medusa-react/stories/Collections.stories.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { Meta } from "@storybook/react" -import React from "react" -import { useCollection, useCollections } from "../src" -import Layout from "./components/Layout" - -const Collections = ({ showHookData, limit, offset }) => { - const data = useCollections({ limit, offset }) - return ( - -

Collections

-
    - {data?.collections?.map((Collection) => ( -
  • {Collection.title}
  • - ))} -
-
- ) -} - -const Collection = ({ showHookData, id }) => { - const data = useCollection(id) - return ( - -

Collection: {id}

-
- {data?.collection?.title} - {data?.collection?.handle} -
-
- ) -} - -const meta: Meta = { - title: "Collections", - argTypes: { - showHookData: { - name: "Show hook data", - description: - "Whether or not story should display JSON of data returned from hook", - control: { - type: "boolean", - }, - defaultValue: true, - }, - }, - parameters: { - controls: { expanded: true }, - }, -} - -export default meta - -export const List = (args: { - limit: number - offset: number - showHookData: boolean -}) => - -List.argTypes = { - limit: { - control: { - type: "number", - }, - name: "limit", - defaultValue: 5, - }, - offset: { - control: { - type: "number", - }, - defaultValue: 0, - }, -} - -export const GetOne = (args: { showHookData: boolean; id: string }) => ( - -) - -GetOne.argTypes = { - id: { - control: { - type: "text", - }, - name: "Collection id", - defaultValue: "pcol_", - }, -} diff --git a/packages/medusa-react/stories/Customers.stories.tsx b/packages/medusa-react/stories/Customers.stories.tsx deleted file mode 100644 index 701286fa42..0000000000 --- a/packages/medusa-react/stories/Customers.stories.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { Meta } from "@storybook/react" -import React from "react" -import { useMeCustomer, useCustomerOrders } from "../src" -import Layout from "./components/Layout" - -const CustomerOrders = ({ showHookData, id }) => { - const data = useCustomerOrders(id) - return ( - -

Customer Orders

-
    - {data?.orders?.map((order) => ( -
  • price: {order.total}
  • - ))} -
-
- ) -} - -const Customer = ({ showHookData }) => { - const data = useMeCustomer() - return ( - -

Customer:

-
- {data?.customer?.first_name} {data?.customer?.last_name} -{" "} - {data?.customer?.email} -
-
- ) -} - -const meta: Meta = { - title: "Customers", - argTypes: { - showHookData: { - name: "Show hook data", - description: - "Whether or not story should display JSON of data returned from hook", - control: { - type: "boolean", - }, - defaultValue: true, - }, - }, - parameters: { - controls: { expanded: true }, - }, -} - -export default meta - -export const ListOrders = (args: { showHookData: boolean; id: string }) => ( - -) - -ListOrders.argTypes = { - id: { - control: { - type: "text", - }, - name: "customer id", - defaultValue: "reg_", - }, -} - -export const GetOne = (args: { showHookData: boolean }) => ( - -) diff --git a/packages/medusa-react/stories/Orders.stories.tsx b/packages/medusa-react/stories/Orders.stories.tsx deleted file mode 100644 index d70fd5efe2..0000000000 --- a/packages/medusa-react/stories/Orders.stories.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { Meta } from "@storybook/react" -import React from "react" -import { useCartOrder, useOrder, useProduct, useProducts } from "../src" -import Layout from "./components/Layout" - -const CartOrderComponent = ({ showHookData, cartId }) => { - const data = useCartOrder(cartId) - return ( - -

Order from cart with id: {cartId}

-
- {data?.order?.email} - {data?.order?.currency_code} -
-
- ) -} - -const Order = ({ showHookData, id }) => { - const data = useOrder(id) - return ( - -

Order: {id}

-
- {data?.order?.email} - {data?.order?.currency_code} -
-
- ) -} - -const meta: Meta = { - title: "Orders", - argTypes: { - showHookData: { - name: "Show hook data", - description: - "Whether or not story should display JSON of data returned from hook", - control: { - type: "boolean", - }, - defaultValue: true, - }, - }, - parameters: { - controls: { expanded: true }, - }, -} - -export default meta - -export const CartOrder = (args: { cartId: string; showHookData: boolean }) => ( - -) - -CartOrder.argTypes = { - cartId: { - control: { - type: "text", - }, - name: "cart id", - defaultValue: "cart_...", - }, -} - -export const GetOne = (args: { showHookData: boolean; id: string }) => ( - -) - -GetOne.argTypes = { - id: { - control: { - type: "text", - }, - name: "order id", - defaultValue: "order_...", - }, -} diff --git a/packages/medusa-react/stories/Products.stories.tsx b/packages/medusa-react/stories/Products.stories.tsx deleted file mode 100644 index 759bdf9bb9..0000000000 --- a/packages/medusa-react/stories/Products.stories.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { Meta } from "@storybook/react" -import React from "react" -import { useProduct, useProducts } from "../src" -import Layout from "./components/Layout" - -const Products = ({ showHookData, limit, offset }) => { - const data = useProducts({ limit, offset }) - return ( - -

Products

-
    - {data?.products?.map((product) => ( -
  • {product.title}
  • - ))} -
-
- ) -} - -const Product = ({ showHookData, id }) => { - const data = useProduct(id) - return ( - -

Product: {id}

-
- {data?.product?.title} - {data?.product?.handle} -
-
- ) -} - -const meta: Meta = { - title: "Products", - argTypes: { - showHookData: { - name: "Show hook data", - description: - "Whether or not story should display JSON of data returned from hook", - control: { - type: "boolean", - }, - defaultValue: true, - }, - }, - parameters: { - controls: { expanded: true }, - }, -} - -export default meta - -export const List = (args: { - limit: number - offset: number - showHookData: boolean -}) => - -List.argTypes = { - limit: { - control: { - type: "number", - }, - name: "limit", - defaultValue: 5, - }, - offset: { - control: { - type: "number", - }, - defaultValue: 0, - }, -} - -export const GetOne = (args: { showHookData: boolean; id: string }) => ( - -) - -GetOne.argTypes = { - id: { - control: { - type: "text", - }, - name: "product id", - defaultValue: "prod_", - }, -} diff --git a/packages/medusa-react/stories/Regions.stories.tsx b/packages/medusa-react/stories/Regions.stories.tsx deleted file mode 100644 index c7030b99bf..0000000000 --- a/packages/medusa-react/stories/Regions.stories.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { Meta } from "@storybook/react" -import React from "react" -import { useRegion, useRegions } from "../src" -import Layout from "./components/Layout" - -const Regions = ({ showHookData }) => { - const data = useRegions() - return ( - -

Regions

-
    - {data?.regions?.map((region) => ( -
  • {region.name}
  • - ))} -
-
- ) -} - -const Region = ({ showHookData, id }) => { - const data = useRegion(id) - return ( - -

Region: {id}

-
- {data?.region?.name} - {data?.region?.currency_code} -
-
- ) -} - -const meta: Meta = { - title: "Regions", - argTypes: { - showHookData: { - name: "Show hook data", - description: - "Whether or not story should display JSON of data returned from hook", - control: { - type: "boolean", - }, - defaultValue: true, - }, - }, - parameters: { - controls: { expanded: true }, - }, -} - -export default meta - -export const List = (args: { showHookData: boolean }) => - -export const GetOne = (args: { showHookData: boolean; id: string }) => ( - -) - -GetOne.argTypes = { - id: { - control: { - type: "text", - }, - name: "region id", - defaultValue: "reg_", - }, -} diff --git a/packages/medusa-react/stories/ReturnReasons.stories.tsx b/packages/medusa-react/stories/ReturnReasons.stories.tsx deleted file mode 100644 index 6cb90e32ba..0000000000 --- a/packages/medusa-react/stories/ReturnReasons.stories.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { Meta } from "@storybook/react" -import React from "react" -import { useReturnReason, useReturnReasons } from "../src" -import Layout from "./components/Layout" - -const ReturnReasons = ({ showHookData }) => { - const data = useReturnReasons() - return ( - -

Return Reasons

-
    - {data?.return_reasons?.map((rr) => ( -
  • - {rr.label} - {rr.value} -
  • - ))} -
-
- ) -} - -const ReturnReason = ({ showHookData, id }) => { - const data = useReturnReason(id) - return ( - -

Return Reason: {id}

-
- {data?.return_reason?.label} - {data?.return_reason?.value} -
-
- ) -} - -const meta: Meta = { - title: "Return Reasons", - argTypes: { - showHookData: { - name: "Show hook data", - description: - "Whether or not story should display JSON of data returned from hook", - control: { - type: "boolean", - }, - defaultValue: true, - }, - }, - parameters: { - controls: { expanded: true }, - }, -} - -export default meta - -export const List = (args: { showHookData: boolean }) => ( - -) - -export const GetOne = (args: { showHookData: boolean; id: string }) => ( - -) - -GetOne.argTypes = { - id: { - control: { - type: "text", - }, - name: "return reason id", - defaultValue: "rr_...", - }, -} diff --git a/packages/medusa-react/stories/ShippingOptions.stories.tsx b/packages/medusa-react/stories/ShippingOptions.stories.tsx deleted file mode 100644 index cbf80d5c6b..0000000000 --- a/packages/medusa-react/stories/ShippingOptions.stories.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { Meta } from "@storybook/react" -import React from "react" -import { useCartShippingOptions, useShippingOptions } from "../src" -import Layout from "./components/Layout" - -const ShippingOptions = ({ showHookData, cartId }) => { - const data = useShippingOptions(cartId) - return ( - -

Shipping Options

-
    - {data?.shipping_options?.map((so) => ( -
  • - {so.name} - {so.amount} -
  • - ))} -
-
- ) -} - -const CartShippingOptions = ({ showHookData, cartId }) => { - const data = useCartShippingOptions(cartId) - return ( - -

Cart shipping options: {cartId}

-
    - {data?.shipping_options?.map((so) => ( -
  • - {so.name} - {so.amount} -
  • - ))} -
-
- ) -} - -const meta: Meta = { - title: "Shipping Options", - argTypes: { - showHookData: { - name: "Show hook data", - description: - "Whether or not story should display JSON of data returned from hook", - control: { - type: "boolean", - }, - defaultValue: true, - }, - }, - parameters: { - controls: { expanded: true }, - }, -} - -export default meta - -export const List = (args: { showHookData: boolean; cartId: string }) => ( - -) - -List.argTypes = { - cartId: { - control: { - type: "text", - }, - name: "cart id", - defaultValue: "cart_...", - }, -} - -export const GetOne = (args: { showHookData: boolean; cartId: string }) => ( - -) - -GetOne.argTypes = { - cartId: { - control: { - type: "text", - }, - name: "cart id", - defaultValue: "cart_...", - }, -} diff --git a/packages/medusa-react/stories/Swaps.stories.tsx b/packages/medusa-react/stories/Swaps.stories.tsx deleted file mode 100644 index 9353b7b3df..0000000000 --- a/packages/medusa-react/stories/Swaps.stories.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Meta } from "@storybook/react" -import React from "react" -import { useCartSwap } from "../src" -import Layout from "./components/Layout" - -const Swap = ({ showHookData, cartId }) => { - const data = useCartSwap(cartId) - return ( - -

Cart swap: {cartId}

-
- {data?.swap?.order_id} - {data?.swap?.cart_id} -
-
- ) -} - -const meta: Meta = { - title: "Swaps", - argTypes: { - showHookData: { - name: "Show hook data", - description: - "Whether or not story should display JSON of data returned from hook", - control: { - type: "boolean", - }, - defaultValue: true, - }, - }, - parameters: { - controls: { expanded: true }, - }, -} - -export default meta - -export const GetOne = (args: { showHookData: boolean; cartId: string }) => ( - -) - -GetOne.argTypes = { - cartId: { - control: { - type: "text", - }, - name: "cart id", - defaultValue: "cart_...", - }, -} diff --git a/packages/medusa-react/stories/components/Layout.tsx b/packages/medusa-react/stories/components/Layout.tsx deleted file mode 100644 index 3f9fd13fd1..0000000000 --- a/packages/medusa-react/stories/components/Layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react" -import ReactJson from "react-json-view" - -const Layout = ({ children, showHookData, data }) => { - return ( -
-
{children}
-
-

Raw

- {showHookData && } -
-
- ) -} - -export default Layout diff --git a/packages/medusa-react/test/cart-context/cart.test.ts b/packages/medusa-react/test/cart-context/cart.test.ts deleted file mode 100644 index 4c3c8eff2e..0000000000 --- a/packages/medusa-react/test/cart-context/cart.test.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { useCart } from "../../src" -import { act, renderHook } from "@testing-library/react-hooks" -import { fixtures } from "../../mocks/data" -import { createCartWrapper } from "../utils" -import { Cart } from "../../src/types" - -describe("useBag hook", () => { - describe("sets a cart", () => { - test("success", async () => { - const { result } = renderHook(() => useCart(), { - wrapper: createCartWrapper(), - }) - const { setCart } = result.current - - act(() => { - setCart((fixtures.get("cart") as unknown) as Cart) - }) - - const { cart, totalItems } = result.current - - expect(cart).toEqual(fixtures.get("cart")) - expect(totalItems).toEqual(0) - }) - }) - - describe("createCart", () => { - test("creates a cart", async () => { - const { result, waitFor } = renderHook(() => useCart(), { - wrapper: createCartWrapper(), - }) - const { createCart } = result.current - - act(() => { - createCart.mutate({}) - }) - - await waitFor(() => result.current.createCart.isSuccess) - - const { cart, totalItems } = result.current - - expect(cart).toEqual(fixtures.get("cart")) - expect(totalItems).toEqual(0) - }) - }) - - describe("startCheckout", () => { - test("creates a payment session and updates the cart", async () => { - const { result, waitFor } = renderHook(() => useCart(), { - wrapper: createCartWrapper(), - initialProps: { - initialCartState: ({ - ...fixtures.get("cart"), - id: "test-cart", - } as unknown) as Cart, - }, - }) - const { startCheckout } = result.current - - act(() => { - startCheckout.mutate() - }) - - await waitFor(() => result.current.startCheckout.isSuccess) - - const { cart, totalItems } = result.current - - expect(cart).toEqual({ - ...fixtures.get("cart"), - id: "test-cart", - }) - expect(totalItems).toEqual(0) - }) - }) - - describe("updateCart", () => { - test("updates the cart", async () => { - const { result, waitFor } = renderHook(() => useCart(), { - wrapper: createCartWrapper(), - initialProps: { - initialCartState: ({ - ...fixtures.get("cart"), - id: "test-cart", - } as unknown) as Cart, - }, - }) - const { updateCart } = result.current - - act(() => { - updateCart.mutate({ - email: "zak@test.com", - }) - }) - - await waitFor(() => result.current.updateCart.isSuccess) - - const { cart, totalItems } = result.current - - expect(cart).toEqual({ - ...fixtures.get("cart"), - id: "test-cart", - email: "zak@test.com", - }) - expect(totalItems).toEqual(0) - }) - }) - - describe("addShippingMethod", () => { - test("adds a shipping method and updates the cart", async () => { - const { result, waitFor } = renderHook(() => useCart(), { - wrapper: createCartWrapper(), - initialProps: { - initialCartState: ({ - ...fixtures.get("cart"), - id: "test-cart", - } as unknown) as Cart, - }, - }) - const { addShippingMethod } = result.current - - act(() => { - addShippingMethod.mutate({ - option_id: "test-option", - }) - }) - - await waitFor(() => result.current.addShippingMethod.isSuccess) - - const { cart, totalItems } = result.current - - expect(cart).toEqual({ - ...fixtures.get("cart"), - id: "test-cart", - }) - expect(totalItems).toEqual(0) - }) - }) - - describe("pay", () => { - test("sets a payment session and updates the cart", async () => { - const { result, waitFor } = renderHook(() => useCart(), { - wrapper: createCartWrapper(), - initialProps: { - initialCartState: ({ - ...fixtures.get("cart"), - id: "test-cart", - } as unknown) as Cart, - }, - }) - const { pay } = result.current - - act(() => { - pay.mutate({ - provider_id: "test-provider", - }) - }) - - await waitFor(() => result.current.pay.isSuccess) - - const { cart, totalItems } = result.current - - expect(cart).toEqual({ - ...fixtures.get("cart"), - id: "test-cart", - }) - expect(totalItems).toEqual(0) - }) - }) - - describe("completeCheckout", () => { - test("calls complete cart, does not update the cart, and returns an order", async () => { - const { result, waitFor } = renderHook(() => useCart(), { - wrapper: createCartWrapper(), - initialProps: { - initialCartState: (fixtures.get("cart") as unknown) as Cart, - }, - }) - const { completeCheckout } = result.current - - act(() => { - completeCheckout.mutate() - }) - - await waitFor(() => result.current.completeCheckout.isSuccess) - - const { cart, totalItems } = result.current - - expect(cart).toEqual(fixtures.get("cart")) - expect(totalItems).toEqual(0) - - expect(result.current.completeCheckout.data.type).toEqual("order") - expect(result.current.completeCheckout.data.data).toEqual( - fixtures.get("order") - ) - }) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/auth/mutations.test.ts b/packages/medusa-react/test/hooks/admin/auth/mutations.test.ts deleted file mode 100644 index 9854472dfb..0000000000 --- a/packages/medusa-react/test/hooks/admin/auth/mutations.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminDeleteSession, useAdminLogin } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminLogin hook", () => { - test("logs in a user", async () => { - const payload = { - email: "lebron@james.com", - password: "supersecure", - } - - const { result, waitFor } = renderHook(() => useAdminLogin(), { - wrapper: createWrapper(), - }) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.user).toEqual(fixtures.get("user")) - }) -}) - -describe("useAdminDeleteSession hook", () => { - test("deletes a collection", async () => { - const { result, waitFor } = renderHook(() => useAdminDeleteSession(), { - wrapper: createWrapper(), - }) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/auth/queries.test.ts b/packages/medusa-react/test/hooks/admin/auth/queries.test.ts deleted file mode 100644 index cac72e9bfb..0000000000 --- a/packages/medusa-react/test/hooks/admin/auth/queries.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminGetSession } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminGetSession hook", () => { - test("returns the authenticated user", async () => { - const user = fixtures.get("user") - const { result, waitFor } = renderHook(() => useAdminGetSession(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.user).toEqual(user) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/batch-jobs/mutations.test.ts b/packages/medusa-react/test/hooks/admin/batch-jobs/mutations.test.ts deleted file mode 100644 index 1452f926ce..0000000000 --- a/packages/medusa-react/test/hooks/admin/batch-jobs/mutations.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCancelBatchJob, - useAdminConfirmBatchJob, - useAdminCreateBatchJob, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateBatchJob hook", () => { - test("creates a batch job and returns it", async () => { - const batch = { - type: "product_export", - dry_run: false, - context: {}, - } - - const { result, waitFor } = renderHook(() => useAdminCreateBatchJob(), { - wrapper: createWrapper(), - }) - - result.current.mutate(batch) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data?.response.status).toEqual(200) - expect(result.current.data?.batch_job).toEqual( - expect.objectContaining({ - ...fixtures.get("batch_job"), - ...batch, - }) - ) - }) -}) - -describe("useAdminCancelBatchJob hook", () => { - test("cancels a batch job and returns it", async () => { - const { result, waitFor } = renderHook( - () => useAdminCancelBatchJob(fixtures.get("batch_job").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data?.response.status).toEqual(200) - expect(result.current.data?.batch_job).toEqual( - expect.objectContaining({ - ...fixtures.get("batch_job"), - }) - ) - }) -}) - -describe("useAdminConfirmBatchJob hook", () => { - test("confirms a batch job and returns it", async () => { - const { result, waitFor } = renderHook( - () => useAdminConfirmBatchJob(fixtures.get("batch_job").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data?.response.status).toEqual(200) - expect(result.current.data?.batch_job).toEqual( - expect.objectContaining({ - ...fixtures.get("batch_job"), - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/batch-jobs/queries.test.ts b/packages/medusa-react/test/hooks/admin/batch-jobs/queries.test.ts deleted file mode 100644 index 93b5a21cad..0000000000 --- a/packages/medusa-react/test/hooks/admin/batch-jobs/queries.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminBatchJob, useAdminBatchJobs } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminBatchJobs hook", () => { - test("returns a list of batch job", async () => { - const batchJobs = fixtures.list("batch_job") - const { result, waitFor } = renderHook(() => useAdminBatchJobs(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response?.status).toEqual(200) - expect(result.current.batch_jobs).toEqual(batchJobs) - }) -}) - -describe("useAdminBatchJob hook", () => { - test("returns a batch job", async () => { - const batchJob = fixtures.get("batch_job") - const { result, waitFor } = renderHook( - () => useAdminBatchJob(batchJob.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response?.status).toEqual(200) - expect(result.current.batch_job).toEqual(batchJob) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/claims/mutations.test.ts b/packages/medusa-react/test/hooks/admin/claims/mutations.test.ts deleted file mode 100644 index 78872f6957..0000000000 --- a/packages/medusa-react/test/hooks/admin/claims/mutations.test.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCancelClaim, - useAdminCancelClaimFulfillment, - useAdminCreateClaim, - useAdminCreateClaimShipment, - useAdminFulfillClaim, - useAdminUpdateClaim, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateClaim hook", () => { - test("creates a claim for an order", async () => { - const orderId = fixtures.get("order").id - - const claim = { - type: "refund" as const, - claim_items: [ - { - item_id: "test-variant", - quantity: 1, - }, - ], - } - - const { result, waitFor } = renderHook(() => useAdminCreateClaim(orderId), { - wrapper: createWrapper(), - }) - - result.current.mutate(claim) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminUpdateClaim hook", () => { - test("updates a claim for an order", async () => { - const orderId = fixtures.get("order").id - const claimId = "test-claim" - const claim = { - shipping_method: [ - { - option_id: "test-so", - price: 1000, - }, - ], - } - - const { result, waitFor } = renderHook(() => useAdminUpdateClaim(orderId), { - wrapper: createWrapper(), - }) - - result.current.mutate({ - claim_id: claimId, - ...claim, - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminFulfillClaim hook", () => { - test("fulfills a claim", async () => { - const orderId = fixtures.get("order").id - const claimId = "test-claim" - const payload = { - no_notification: true, - } - - const { result, waitFor } = renderHook( - () => useAdminFulfillClaim(orderId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - claim_id: claimId, - ...payload, - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminCreateClaimShipment hook", () => { - test("creates a claim shipment", async () => { - const orderId = fixtures.get("order").id - const claimId = "test-claim" - const payload = { - fulfillment_id: "test-id", - tracking_numbers: [], - } - - const { result, waitFor } = renderHook( - () => useAdminCreateClaimShipment(orderId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - claim_id: claimId, - ...payload, - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminCancelClaim hook", () => { - test("cancels a claim for an order", async () => { - const orderId = fixtures.get("order").id - const claimId = "test-claim" - - const { result, waitFor } = renderHook(() => useAdminCancelClaim(orderId), { - wrapper: createWrapper(), - }) - - result.current.mutate(claimId) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminCancelClaimFulfillment hook", () => { - test("cancels a claim's fulfillment", async () => { - const orderId = fixtures.get("order").id - const claimId = "test-claim" - const fulfillmentId = "test-ful" - - const { result, waitFor } = renderHook( - () => useAdminCancelClaimFulfillment(orderId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ claim_id: claimId, fulfillment_id: fulfillmentId }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/collections/mutations.test.ts b/packages/medusa-react/test/hooks/admin/collections/mutations.test.ts deleted file mode 100644 index f9f3fd1f09..0000000000 --- a/packages/medusa-react/test/hooks/admin/collections/mutations.test.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminAddProductsToCollection, - useAdminCreateCollection, - useAdminDeleteCollection, - useAdminRemoveProductsFromCollection, - useAdminUpdateCollection, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateCollection hook", () => { - test("creates a collection and returns it", async () => { - const collection = { - title: "test_collection", - } - - const { result, waitFor } = renderHook(() => useAdminCreateCollection(), { - wrapper: createWrapper(), - }) - - result.current.mutate(collection) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.collection).toEqual( - expect.objectContaining({ - ...fixtures.get("product_collection"), - ...collection, - }) - ) - }) -}) - -describe("useAdminUpdateCollection hook", () => { - test("updates a collection and returns it", async () => { - const collection = { - title: "update_collection", - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateCollection(fixtures.get("product_collection").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(collection) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.collection).toEqual( - expect.objectContaining({ - ...fixtures.get("product_collection"), - ...collection, - }) - ) - }) -}) - -describe("useAdminDeleteCollection hook", () => { - test("deletes a collection", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteCollection(fixtures.get("product_collection").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: fixtures.get("product_collection").id, - deleted: true, - }) - ) - }) -}) - -describe("useAdminAddProductsToCollection hook", () => { - test("add products to a collection", async () => { - const update = { - product_ids: [fixtures.get("product").id], - } - - const { result, waitFor } = renderHook( - () => - useAdminAddProductsToCollection(fixtures.get("product_collection").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(update) - - await waitFor(() => result.current.isSuccess) - expect(result.current.data?.response.status).toEqual(200) - expect(result.current.data?.collection).toEqual( - expect.objectContaining({ - ...fixtures.get("product_collection"), - products: [fixtures.get("product")], - }) - ) - }) -}) - -describe("useAdminRemoveProductsFromCollection hook", () => { - test("remove products from a collection", async () => { - const remove = { - product_ids: [fixtures.get("product").id], - } - - const { result, waitFor } = renderHook( - () => - useAdminRemoveProductsFromCollection( - fixtures.get("product_collection").id - ), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(remove) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data?.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: fixtures.get("product_collection").id, - object: "product-collection", - removed_products: remove.product_ids, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/collections/queries.test.ts b/packages/medusa-react/test/hooks/admin/collections/queries.test.ts deleted file mode 100644 index 8d3043fccb..0000000000 --- a/packages/medusa-react/test/hooks/admin/collections/queries.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminCollection, useAdminCollections } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminCollections hook", () => { - test("returns a list of collections", async () => { - const collections = fixtures.list("product_collection") - const { result, waitFor } = renderHook(() => useAdminCollections(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.collections).toEqual(collections) - }) -}) - -describe("useAdminCollection hook", () => { - test("returns a collection", async () => { - const collection = fixtures.get("product_collection") - const { result, waitFor } = renderHook( - () => useAdminCollection(collection.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.collection).toEqual(collection) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/currencies/mutation.test.ts b/packages/medusa-react/test/hooks/admin/currencies/mutation.test.ts deleted file mode 100644 index 3ab58a7953..0000000000 --- a/packages/medusa-react/test/hooks/admin/currencies/mutation.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminUpdateCurrency } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminUpdateCurrency hook", () => { - test("updates a currency and returns it", async () => { - const update = { - includes_tax: true, - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateCurrency(fixtures.get("currency").code), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(update) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data?.response.status).toEqual(200) - expect(result.current.data?.currency).toEqual( - expect.objectContaining({ - ...fixtures.get("currency"), - ...update, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/currencies/queries.test.ts b/packages/medusa-react/test/hooks/admin/currencies/queries.test.ts deleted file mode 100644 index 05b0518fef..0000000000 --- a/packages/medusa-react/test/hooks/admin/currencies/queries.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminCurrencies } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminCurrencies hook", () => { - test("returns a list of currencies", async () => { - const currencies = fixtures.list("currency", 1) - const { result, waitFor } = renderHook(() => useAdminCurrencies(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response?.status).toEqual(200) - expect(result.current.currencies).toEqual(currencies) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/customer-groups/mutations.test.ts b/packages/medusa-react/test/hooks/admin/customer-groups/mutations.test.ts deleted file mode 100644 index a014c00223..0000000000 --- a/packages/medusa-react/test/hooks/admin/customer-groups/mutations.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" - -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateCustomerGroup, - useAdminUpdateCustomerGroup, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateCustomerGroup hook", () => { - test("creates a customer group and returns it", async () => { - const group = { - name: "Group 1", - } - - const { result, waitFor } = renderHook( - () => useAdminCreateCustomerGroup(), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(group) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.customer_group).toEqual( - expect.objectContaining(group) - ) - }) - - describe("useAdminUpdateCustomerGroup hook", () => { - test("updates a customer group and returns it", async () => { - const group = { - name: "Changeed name", - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateCustomerGroup(fixtures.get("customer_group").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(group) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.customer_group).toEqual( - expect.objectContaining({ - ...fixtures.get("customer_group"), - ...group, - }) - ) - }) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/customer-groups/queries.test.ts b/packages/medusa-react/test/hooks/admin/customer-groups/queries.test.ts deleted file mode 100644 index 97b284ecc1..0000000000 --- a/packages/medusa-react/test/hooks/admin/customer-groups/queries.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" - -import { fixtures } from "../../../../mocks/data" -import { - useAdminCustomerGroup, - useAdminCustomerGroupCustomers, - useAdminCustomerGroups, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminCustomerGroup hook", () => { - test("returns a customer group", async () => { - const group = fixtures.get("customer_group") - const { result, waitFor } = renderHook( - () => useAdminCustomerGroup(group.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.customer_group).toEqual(group) - }) - - test("returns a list of customer groups", async () => { - const groups = fixtures.list("customer_group") - const { result, waitFor } = renderHook(() => useAdminCustomerGroups(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.customer_groups).toEqual(groups) - }) - - test("returns a list of customers that belong to a group", async () => { - const groups = fixtures.list("customer_group") - const customers = fixtures.list("customer") - - const { result, waitFor } = renderHook( - () => useAdminCustomerGroupCustomers(groups[0].id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.customers).toEqual(customers) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/customers/mutations.test.ts b/packages/medusa-react/test/hooks/admin/customers/mutations.test.ts deleted file mode 100644 index 89fae279f3..0000000000 --- a/packages/medusa-react/test/hooks/admin/customers/mutations.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateCustomer, - useAdminUpdateCustomer, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateCustomer hook", () => { - test("creates a customer and returns it", async () => { - const customer = { - email: "lebron@james.com", - first_name: "Lebron", - last_name: "James", - password: "password", - } - - const { result, waitFor } = renderHook(() => useAdminCreateCustomer(), { - wrapper: createWrapper(), - }) - - result.current.mutate(customer) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.customer).toEqual( - expect.objectContaining({ - ...fixtures.get("customer"), - ...customer, - }) - ) - }) -}) - -describe("useAdminUpdateCustomer hook", () => { - test("updates a customer and returns it", async () => { - const customer = { - email: "lebron@james.com", - first_name: "Lebron", - last_name: "James", - password: "password", - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateCustomer(fixtures.get("customer").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(customer) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.customer).toEqual( - expect.objectContaining({ - ...fixtures.get("customer"), - ...customer, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/customers/queries.test.ts b/packages/medusa-react/test/hooks/admin/customers/queries.test.ts deleted file mode 100644 index 38a1624c23..0000000000 --- a/packages/medusa-react/test/hooks/admin/customers/queries.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminCustomer, useAdminCustomers } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminCustomers hook", () => { - test("returns a list of customers", async () => { - const customers = fixtures.list("customer") - const { result, waitFor } = renderHook(() => useAdminCustomers(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.customers).toEqual(customers) - }) -}) - -describe("useAdminCustomer hook", () => { - test("returns a customer", async () => { - const customer = fixtures.get("customer") - const { result, waitFor } = renderHook( - () => useAdminCustomer(customer.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.customer).toEqual(customer) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/discounts/mutations.test.ts b/packages/medusa-react/test/hooks/admin/discounts/mutations.test.ts deleted file mode 100644 index b9acb47e0f..0000000000 --- a/packages/medusa-react/test/hooks/admin/discounts/mutations.test.ts +++ /dev/null @@ -1,342 +0,0 @@ -import { DiscountConditionOperator } from "@medusajs/medusa" -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminAddDiscountConditionResourceBatch, - useAdminCreateDiscount, - useAdminCreateDynamicDiscountCode, - useAdminDeleteDiscount, - useAdminDeleteDiscountConditionResourceBatch, - useAdminDeleteDynamicDiscountCode, - useAdminDiscountAddRegion, - useAdminDiscountCreateCondition, - useAdminDiscountRemoveCondition, - useAdminDiscountRemoveRegion, - useAdminDiscountUpdateCondition, - useAdminUpdateDiscount, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminDeleteDiscountConditionResourceBatch hook", () => { - test("delete items from a discount condition and return the discount", async () => { - const resources = [ - { - id: fixtures.get("product").id, - }, - ] - const discountId = fixtures.get("discount").id - const conditionId = fixtures.get("discount").rule.conditions[0].id - - const { result, waitFor } = renderHook( - () => - useAdminDeleteDiscountConditionResourceBatch(discountId, conditionId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - resources, - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.discount).toEqual( - expect.objectContaining({ - ...fixtures.get("discount"), - rule: { - ...fixtures.get("discount").rule, - conditions: [ - { - ...fixtures.get("discount").rule.conditions[0], - products: [], - }, - ], - }, - }) - ) - }) -}) - -describe("useAdminAddDiscountConditionResourceBatch hook", () => { - test("add items to a discount condition and return the discount", async () => { - const resources = [ - { - id: fixtures.get("product").id, - }, - ] - const discountId = fixtures.get("discount").id - const conditionId = fixtures.get("discount").rule.conditions[0].id - - const { result, waitFor } = renderHook( - () => useAdminAddDiscountConditionResourceBatch(discountId, conditionId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ resources }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.discount).toEqual( - expect.objectContaining({ - ...fixtures.get("discount"), - rule: { - ...fixtures.get("discount").rule, - conditions: [ - { - ...fixtures.get("discount").rule.conditions[0], - products: [ - ...(fixtures.get("discount").rule.conditions[0]?.products ?? - []), - { id: fixtures.get("product").id }, - ], - }, - ], - }, - }) - ) - }) -}) - -describe("useAdminCreateDiscount hook", () => { - test("creates a discount and returns it", async () => { - const discount = { - code: "DISC", - rule: { - type: "percentage", - value: 10, - allocation: "total", - }, - is_dynamic: false, - is_disabled: false, - } - - const { result, waitFor } = renderHook(() => useAdminCreateDiscount(), { - wrapper: createWrapper(), - }) - - result.current.mutate(discount) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.discount).toEqual( - expect.objectContaining({ - ...fixtures.get("discount"), - ...discount, - }) - ) - }) -}) - -describe("useAdminUpdateDiscount hook", () => { - test("updates a discount and returns it", async () => { - const discount = { - code: "SUMMER10", - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateDiscount(fixtures.get("discount").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(discount) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.discount).toEqual( - expect.objectContaining({ - ...fixtures.get("discount"), - ...discount, - }) - ) - }) -}) - -describe("useAdminDeleteDiscount hook", () => { - test("updates a discount and returns it", async () => { - const id = fixtures.get("discount").id - - const { result, waitFor } = renderHook(() => useAdminDeleteDiscount(id), { - wrapper: createWrapper(), - }) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id, - deleted: true, - }) - ) - }) -}) - -describe("useAdminDiscountAddRegion hook", () => { - test("adds a region to the discount", async () => { - const id = fixtures.get("discount").id - - const { result, waitFor } = renderHook( - () => useAdminDiscountAddRegion(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate("test-region") - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.discount).toEqual( - expect.objectContaining(fixtures.get("discount")) - ) - }) -}) - -describe("useAdminCreateDynamicDiscountCode hook", () => { - test("creates a dynamic discount code", async () => { - const discount = { - code: "LUCKY10", - usage_limit: 10, - } - - const { result, waitFor } = renderHook( - () => useAdminCreateDynamicDiscountCode(fixtures.get("discount").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(discount) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.discount).toEqual( - expect.objectContaining({ - ...fixtures.get("discount"), - ...discount, - }) - ) - }) -}) - -describe("useAdminDiscountRemoveRegion hook", () => { - test("adds a region to the discount", async () => { - const id = fixtures.get("discount").id - - const { result, waitFor } = renderHook( - () => useAdminDiscountRemoveRegion(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate("test-region") - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.discount).toEqual( - expect.objectContaining(fixtures.get("discount")) - ) - }) -}) - -describe("useAdminDeleteDynamicDiscountCode hook", () => { - test("creates a dynamic discount code", async () => { - const id = fixtures.get("discount").id - - const { result, waitFor } = renderHook( - () => useAdminDeleteDynamicDiscountCode(fixtures.get("discount").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate("LUCKY10") - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.discount).toEqual( - expect.objectContaining(fixtures.get("discount")) - ) - }) -}) - -describe("useAdminDiscountCreateCondition hook", () => { - test("Creates a condition from a discount", async () => { - const id = fixtures.get("discount").id - const conditionId = fixtures.get("discount").rule.conditions[0].id - - const { result, waitFor } = renderHook( - () => useAdminDiscountCreateCondition(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - operator: DiscountConditionOperator.IN, - products: ["test-product"], - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.discount).toEqual(fixtures.get("discount")) - }) -}) -describe("useAdminDiscountUpdateCondition hook", () => { - test("Updates condition for discount", async () => { - const id = fixtures.get("discount").id - const conditionId = fixtures.get("discount").rule.conditions[0].id - - const { result, waitFor } = renderHook( - () => useAdminDiscountUpdateCondition(id, conditionId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ products: ["test-product"] }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.discount).toEqual(fixtures.get("discount")) - }) -}) - -describe("useAdminDiscountRemoveCondition hook", () => { - test("removes a condition from a discount", async () => { - const id = fixtures.get("discount").id - const conditionId = fixtures.get("discount").rule.conditions[0].id - - const { result, waitFor } = renderHook( - () => useAdminDiscountRemoveCondition(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(conditionId) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.id).toEqual(conditionId) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/discounts/queries.test.ts b/packages/medusa-react/test/hooks/admin/discounts/queries.test.ts deleted file mode 100644 index 7f439c462f..0000000000 --- a/packages/medusa-react/test/hooks/admin/discounts/queries.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminDiscount, - useAdminDiscounts, - useAdminGetDiscountByCode, - useAdminGetDiscountCondition, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminDiscounts hook", () => { - test("returns a list of discounts", async () => { - const discounts = fixtures.list("discount") - const { result, waitFor } = renderHook(() => useAdminDiscounts(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.discounts).toEqual(discounts) - }) -}) - -describe("useAdminGetDiscountByCode hook", () => { - test("retrieves a discount by discount code", async () => { - const discount = fixtures.get("discount") - const { result, waitFor } = renderHook( - () => useAdminGetDiscountByCode("10DISC"), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.discount).toEqual(discount) - }) -}) - -describe("useAdminDiscount hook", () => { - test("returns a discount", async () => { - const discount = fixtures.get("discount") - const { result, waitFor } = renderHook( - () => useAdminDiscount(discount.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.discount).toEqual(discount) - }) -}) - -describe("useAdminGetDiscountCondition hook", () => { - test("returns a discount condition", async () => { - const discount = fixtures.get("discount") - const { result, waitFor } = renderHook( - () => - useAdminGetDiscountCondition( - discount.id, - discount.rule.conditions[0].id - ), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.discount_condition).toEqual( - discount.rule.conditions[0] - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/draft-orders/mutations.test.ts b/packages/medusa-react/test/hooks/admin/draft-orders/mutations.test.ts deleted file mode 100644 index 368b1c9ff5..0000000000 --- a/packages/medusa-react/test/hooks/admin/draft-orders/mutations.test.ts +++ /dev/null @@ -1,189 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateDraftOrder, - useAdminDeleteDraftOrder, - useAdminDraftOrderAddLineItem, - useAdminDraftOrderRegisterPayment, - useAdminDraftOrderRemoveLineItem, - useAdminDraftOrderUpdateLineItem, - useAdminUpdateDraftOrder, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateDraftOrder hook", () => { - test("creates a draft order and returns it", async () => { - const draftOrder = { - email: "lebron@james.com", - items: [ - { - variant_id: "variant_01FGKMYKJVY3DYDZWCRB2GZS0G", - quantity: 1, - }, - ], - shipping_methods: [ - { - option_id: "opt_01FGKMYKJWQZCZANRNHR3XVRN3", - price: 0, - }, - ], - region_id: "reg_01FGKMYKKG6ACZANRNHR3XVRN3", - } - - const { result, waitFor } = renderHook(() => useAdminCreateDraftOrder(), { - wrapper: createWrapper(), - }) - - result.current.mutate(draftOrder) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.draft_order).toEqual( - expect.objectContaining({ - ...fixtures.get("draft_order"), - ...draftOrder, - }) - ) - }) -}) - -describe("useAdminUpdateDraftOrder hook", () => { - test("updates a draft order and returns it", async () => { - const id = fixtures.get("draft_order").id - const draftOrder = { - country_code: "dk", - } - - const { result, waitFor } = renderHook(() => useAdminUpdateDraftOrder(id), { - wrapper: createWrapper(), - }) - - result.current.mutate(draftOrder) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.draft_order).toEqual( - expect.objectContaining({ - ...fixtures.get("draft_order"), - ...draftOrder, - }) - ) - }) -}) - -describe("useAdminDeleteDraftOrder hook", () => { - test("deletes a draft order", async () => { - const id = fixtures.get("draft_order").id - - const { result, waitFor } = renderHook(() => useAdminDeleteDraftOrder(id), { - wrapper: createWrapper(), - }) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id, - deleted: true, - }) - ) - }) -}) - -describe("useAdminDraftOrderAddLineItem hook", () => { - test("adds a line item to a draft order", async () => { - const id = fixtures.get("draft_order").id - const lineItem = { - quantity: 2, - variant_id: "test-variant", - } - - const { result, waitFor } = renderHook( - () => useAdminDraftOrderAddLineItem(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(lineItem) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.draft_order).toEqual(fixtures.get("draft_order")) - }) -}) - -describe("useAdminDraftOrderUpdateLineItem hook", () => { - test("updates a draft order's line item", async () => { - const id = fixtures.get("draft_order").id - const lineItemId = "test-li" - const newLineItem = { - quantity: 1, - variant_id: "test-variant", - } - - const { result, waitFor } = renderHook( - () => useAdminDraftOrderUpdateLineItem(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - item_id: lineItemId, - ...newLineItem, - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.draft_order).toEqual(fixtures.get("draft_order")) - }) -}) - -describe("useAdminDraftOrderRemoveLineItem hook", () => { - test("delete a draft order's line item", async () => { - const id = fixtures.get("draft_order").id - const lineItemId = "test-li" - - const { result, waitFor } = renderHook( - () => useAdminDraftOrderRemoveLineItem(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(lineItemId) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.draft_order).toEqual(fixtures.get("draft_order")) - }) -}) - -describe("useAdminDraftOrderRegisterPayment hook", () => { - test("marks a draft order as paid", async () => { - const id = fixtures.get("draft_order").id - - const { result, waitFor } = renderHook( - () => useAdminDraftOrderRegisterPayment(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/draft-orders/queries.test.ts b/packages/medusa-react/test/hooks/admin/draft-orders/queries.test.ts deleted file mode 100644 index 9dd3012b06..0000000000 --- a/packages/medusa-react/test/hooks/admin/draft-orders/queries.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminDraftOrder, useAdminDraftOrders } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminDraftOrders hook", () => { - test("returns a list of draft orders", async () => { - const draftOrders = fixtures.list("draft_order") - const { result, waitFor } = renderHook(() => useAdminDraftOrders(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.draft_orders).toEqual(draftOrders) - }) -}) - -describe("useAdminDraftOrder hook", () => { - test("returns a draft order", async () => { - const draftOrder = fixtures.get("draft_order") - const { result, waitFor } = renderHook( - () => useAdminDraftOrder(draftOrder.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.draft_order).toEqual(draftOrder) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/gift-cards/mutations.test.ts b/packages/medusa-react/test/hooks/admin/gift-cards/mutations.test.ts deleted file mode 100644 index 8562fb769f..0000000000 --- a/packages/medusa-react/test/hooks/admin/gift-cards/mutations.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateGiftCard, - useAdminDeleteGiftCard, - useAdminUpdateGiftCard, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateGiftCard hook", () => { - test("creates a gift card and returns it", async () => { - const gc = { - value: 1000, - region_id: "test-id", - } - - const { result, waitFor } = renderHook(() => useAdminCreateGiftCard(), { - wrapper: createWrapper(), - }) - - result.current.mutate(gc) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.gift_card).toEqual( - expect.objectContaining({ - ...fixtures.get("gift_card"), - ...gc, - }) - ) - }) -}) - -describe("useAdminUpdateGiftCard hook", () => { - test("updates a gift card and returns it", async () => { - const gc = { - value: 2000, - region_id: "test-region", - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateGiftCard(fixtures.get("gift_card").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(gc) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.gift_card).toEqual( - expect.objectContaining({ - ...fixtures.get("gift_card"), - ...gc, - }) - ) - }) -}) - -describe("useAdminDeleteGiftCard hook", () => { - test("deletes a gift card", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteGiftCard(fixtures.get("gift_card").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: fixtures.get("gift_card").id, - deleted: true, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/gift-cards/queries.test.ts b/packages/medusa-react/test/hooks/admin/gift-cards/queries.test.ts deleted file mode 100644 index 2dbef80d03..0000000000 --- a/packages/medusa-react/test/hooks/admin/gift-cards/queries.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminGiftCard, useAdminGiftCards } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminGiftCards hook", () => { - test("returns a list of giftCards", async () => { - const giftCards = fixtures.list("gift_card") - const { result, waitFor } = renderHook(() => useAdminGiftCards(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.gift_cards).toEqual(giftCards) - }) -}) - -describe("useAdminGiftCard hook", () => { - test("returns a giftCard", async () => { - const giftCard = fixtures.get("gift_card") - const { result, waitFor } = renderHook( - () => useAdminGiftCard(giftCard.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.gift_card).toEqual(giftCard) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/inventory-items/mutations.test.ts b/packages/medusa-react/test/hooks/admin/inventory-items/mutations.test.ts deleted file mode 100644 index db804c94b2..0000000000 --- a/packages/medusa-react/test/hooks/admin/inventory-items/mutations.test.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { - useAdminCreateLocationLevel, - useAdminDeleteInventoryItem, - useAdminDeleteLocationLevel, - useAdminUpdateInventoryItem, - useAdminUpdateLocationLevel, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminUpdateInventoryItem hook", () => { - test("updates an inventory item", async () => { - const payload = { - sku: "test-sku", - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateInventoryItem("inventory-item-id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.inventory_item).toEqual( - expect.objectContaining({ - id: "inventory-item-id", - sku: "test-sku", - }) - ) - }) -}) - -describe("useAdminDeleteInventoryItem hook", () => { - test("Deletes an inventory item", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteInventoryItem("inventory-item-id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: "inventory-item-id", - deleted: true, - }) - ) - }) -}) - -describe("useAdminUpdateLocationLevel hook", () => { - test("Updates a location level", async () => { - const payload = { - incoming_quantity: 10, - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateLocationLevel("inventory-item-id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ ...payload, stockLocationId: "location_id" }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.inventory_item).toEqual( - expect.objectContaining({ - id: "inventory-item-id", - location_levels: [ - expect.objectContaining({ - incoming_quantity: 10, - }), - ], - }) - ) - }) -}) - -describe("useAdminDeleteLocationLevel hook", () => { - test("removes a location level", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteLocationLevel("inventory-item-id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate("location_id") - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.inventory_item).toEqual( - expect.objectContaining({ - id: "inventory-item-id", - location_levels: [], - }) - ) - }) -}) - -describe("useAdminCreateLocationLevel hook", () => { - test("creates a location level", async () => { - const payload = { - location_id: "loc_1", - incoming_quantity: 10, - stocked_quantity: 10, - } - - const { result, waitFor } = renderHook( - () => useAdminCreateLocationLevel("inventory-item-id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.inventory_item).toEqual( - expect.objectContaining({ - id: "inventory-item-id", - location_levels: expect.arrayContaining([ - expect.objectContaining({ ...payload }), - ]), - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/inventory-items/queries.test.ts b/packages/medusa-react/test/hooks/admin/inventory-items/queries.test.ts deleted file mode 100644 index 0fcc4f92bd..0000000000 --- a/packages/medusa-react/test/hooks/admin/inventory-items/queries.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminInventoryItem, - useAdminInventoryItemLocationLevels, - useAdminInventoryItems, - useAdminPriceList, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminInventoryItems hook", () => { - test("returns a list of inventory items", async () => { - const inventoryItems = fixtures.list("inventory_item") - const { result, waitFor } = renderHook(() => useAdminInventoryItems(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.inventory_items).toEqual(inventoryItems) - }) -}) - -describe("useAdminInventoryItem hook", () => { - test("returns a single inventory item", async () => { - const inventoryItem = fixtures.get("inventory_item") - const { result, waitFor } = renderHook( - () => useAdminInventoryItem(inventoryItem.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.inventory_item).toEqual(inventoryItem) - }) -}) - -describe("useAdminInventoryItem hook", () => { - test("returns a location levels for an inventory item", async () => { - const inventoryItem = fixtures.get("inventory_item") - const { result, waitFor } = renderHook( - () => useAdminInventoryItemLocationLevels(inventoryItem.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.inventory_item).toEqual(inventoryItem) - }) -}) - -describe("useAdminPriceList hook", () => { - test("returns a price list", async () => { - const priceList = fixtures.get("price_list") - const { result, waitFor } = renderHook( - () => useAdminPriceList(priceList.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.price_list).toEqual(priceList) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/invites/mutations.test.ts b/packages/medusa-react/test/hooks/admin/invites/mutations.test.ts deleted file mode 100644 index 67903360a8..0000000000 --- a/packages/medusa-react/test/hooks/admin/invites/mutations.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { - useAdminAcceptInvite, - useAdminCreateInvite, - useAdminDeleteInvite, - useAdminResendInvite, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminAcceptInvite hook", () => { - test("accepts an invite", async () => { - const payload = { - token: "test-token", - user: { - first_name: "zak", - last_name: "medusa", - password: "test-password", - }, - } - - const { result, waitFor } = renderHook(() => useAdminAcceptInvite(), { - wrapper: createWrapper(), - }) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - }) -}) - -describe("useAdminCreateInvite hook", () => { - test("creates an invite", async () => { - const payload = { - user: "test-id", - role: "admin" as const, - } - - const { result, waitFor } = renderHook(() => useAdminCreateInvite(), { - wrapper: createWrapper(), - }) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - }) -}) - -describe("useAdminDeleteInvite hook", () => { - test("deletes an invite", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteInvite("test-invite"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: "test-invite", - deleted: true, - }) - ) - }) -}) - -describe("useAdminResend hook", () => { - test("resends an invite", async () => { - const { result, waitFor } = renderHook( - () => useAdminResendInvite("test-invite"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/invites/queries.test.ts b/packages/medusa-react/test/hooks/admin/invites/queries.test.ts deleted file mode 100644 index 69fe51a4af..0000000000 --- a/packages/medusa-react/test/hooks/admin/invites/queries.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminInvites } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminInvites hook", () => { - test("returns a list of invites", async () => { - const invites = fixtures.list("invite") - const { result, waitFor } = renderHook(() => useAdminInvites(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.invites).toEqual(invites) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/notes/mutations.test.ts b/packages/medusa-react/test/hooks/admin/notes/mutations.test.ts deleted file mode 100644 index 061a3e304f..0000000000 --- a/packages/medusa-react/test/hooks/admin/notes/mutations.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateNote, - useAdminDeleteNote, - useAdminUpdateNote, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateNote hook", () => { - test("creates a note and returns it", async () => { - const note = { - value: "talked to customer", - resource_id: "test-swap", - resource_type: "swap", - } - - const { result, waitFor } = renderHook(() => useAdminCreateNote(), { - wrapper: createWrapper(), - }) - - result.current.mutate(note) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.note).toEqual( - expect.objectContaining({ - ...fixtures.get("note"), - ...note, - }) - ) - }) -}) - -describe("useAdminUpdateNote hook", () => { - test("updates a note and returns it", async () => { - const note = { - value: "problem with the supplier", - resource_id: "test-return", - resource_type: "return", - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateNote(fixtures.get("note").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(note) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.note).toEqual( - expect.objectContaining({ - ...fixtures.get("note"), - ...note, - }) - ) - }) -}) - -describe("useAdminDeleteNote hook", () => { - test("deletes a note", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteNote(fixtures.get("note").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: fixtures.get("note").id, - deleted: true, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/notes/queries.test.ts b/packages/medusa-react/test/hooks/admin/notes/queries.test.ts deleted file mode 100644 index 8c3bd63d0c..0000000000 --- a/packages/medusa-react/test/hooks/admin/notes/queries.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminNote, useAdminNotes } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminNotes hook", () => { - test("returns a list of notes", async () => { - const notes = fixtures.list("note") - const { result, waitFor } = renderHook(() => useAdminNotes(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.notes).toEqual(notes) - }) -}) - -describe("useAdminNote hook", () => { - test("returns a note", async () => { - const note = fixtures.get("note") - const { result, waitFor } = renderHook(() => useAdminNote(note.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.note).toEqual(note) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/notifications/mutations.test.ts b/packages/medusa-react/test/hooks/admin/notifications/mutations.test.ts deleted file mode 100644 index d7f5275d23..0000000000 --- a/packages/medusa-react/test/hooks/admin/notifications/mutations.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminResendNotification } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminResendNotification hook", () => { - test("resends a notification", async () => { - const notif = { - to: "me@me.me", - } - - const { result, waitFor } = renderHook( - () => useAdminResendNotification("test-notification"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(notif) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.notification).toEqual( - expect.objectContaining({ - ...fixtures.get("notification"), - ...notif, - id: "test-notification", - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/notifications/queries.test.ts b/packages/medusa-react/test/hooks/admin/notifications/queries.test.ts deleted file mode 100644 index 4c31c97811..0000000000 --- a/packages/medusa-react/test/hooks/admin/notifications/queries.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminNotifications } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminNotifications hook", () => { - test("returns a list of notifications", async () => { - const notifications = fixtures.list("notification") - const { result, waitFor } = renderHook(() => useAdminNotifications(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.notifications).toEqual(notifications) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/order-edits/mutations.test.ts b/packages/medusa-react/test/hooks/admin/order-edits/mutations.test.ts deleted file mode 100644 index 5dd9f28dab..0000000000 --- a/packages/medusa-react/test/hooks/admin/order-edits/mutations.test.ts +++ /dev/null @@ -1,277 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCancelOrderEdit, - useAdminConfirmOrderEdit, - useAdminCreateOrderEdit, - useAdminDeleteOrderEdit, - useAdminDeleteOrderEditItemChange, - useAdminOrderEditAddLineItem, - useAdminOrderEditDeleteLineItem, - useAdminOrderEditUpdateLineItem, - useAdminRequestOrderEditConfirmation, - useAdminUpdateOrderEdit, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminOrderEditUpdateLineItem hook", () => { - test("Update line item of an order edit and create or update an item change", async () => { - const id = "oe_1" - const itemId = "item_1" - const { result, waitFor } = renderHook( - () => useAdminOrderEditUpdateLineItem(id, itemId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ quantity: 3 }) - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order_edit).toEqual( - expect.objectContaining({ - ...fixtures.get("order_edit"), - changes: expect.arrayContaining([ - expect.objectContaining({ - quantity: 3, - }), - ]), - }) - ) - }) -}) - -describe("useAdminDeleteOrderEditItemChange hook", () => { - test("Deletes an order edit item change", async () => { - const id = "oe_1" - const itemChangeId = "oeic_1" - const { result, waitFor } = renderHook( - () => useAdminDeleteOrderEditItemChange(id, itemChangeId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: itemChangeId, - object: "item_change", - deleted: true, - }) - ) - }) -}) - -describe("useAdminDeleteOrderEdit hook", () => { - test("Deletes an order edit", async () => { - const id = "oe_1" - const { result, waitFor } = renderHook(() => useAdminDeleteOrderEdit(id), { - wrapper: createWrapper(), - }) - - result.current.mutate() - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id, - object: "order_edit", - deleted: true, - }) - ) - }) -}) - -describe("useAdminUpdateOrderEdit hook", () => { - test("updates an order edit and returns it", async () => { - const orderEdit = { - internal_note: "changed note", - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateOrderEdit(fixtures.get("order_edit").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(orderEdit) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order_edit).toEqual( - expect.objectContaining({ - ...fixtures.get("order_edit"), - ...orderEdit, - }) - ) - }) -}) - -describe("useAdminCreateOrderEdit hook", () => { - test("Created an order edit", async () => { - const { result, waitFor } = renderHook(() => useAdminCreateOrderEdit(), { - wrapper: createWrapper(), - }) - - const payload = { - order_id: "ord_1", - internal_note: "This is an internal note", - } - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - order_edit: { - ...fixtures.get("order_edit"), - ...payload, - }, - }) - ) - }) -}) - -describe("useAdminRequestOrderEditConfirmation hook", () => { - test("Requests an order edit", async () => { - const { result, waitFor } = renderHook( - () => useAdminRequestOrderEditConfirmation(fixtures.get("order_edit").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data?.order_edit).toEqual( - expect.objectContaining({ - ...fixtures.get("order_edit"), - requested_at: expect.any(String), - status: "requested", - }) - ) - }) -}) - -describe("useAdminOrderEditAddLineItem hook", () => { - test("Created an order edit line item", async () => { - const { result, waitFor } = renderHook( - () => useAdminOrderEditAddLineItem(fixtures.get("order_edit").id), - { - wrapper: createWrapper(), - } - ) - - const payload = { - variant_id: "var_1", - quantity: 2, - } - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - order_edit: { - ...fixtures.get("order_edit"), - ...payload, - }, - }) - ) - }) -}) - -describe("useAdminCancelOrderEdit hook", () => { - test("cancel an order edit", async () => { - const { result, waitFor } = renderHook( - () => useAdminCancelOrderEdit(fixtures.get("order_edit").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - order_edit: { - ...fixtures.get("order_edit"), - canceled_at: expect.any(String), - status: "canceled", - }, - }) - ) - }) -}) - -describe("useAdminConfirmOrderEdit hook", () => { - test("confirm an order edit", async () => { - const { result, waitFor } = renderHook( - () => useAdminConfirmOrderEdit(fixtures.get("order_edit").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - order_edit: { - ...fixtures.get("order_edit"), - confirmed_at: expect.any(String), - status: "confirmed", - }, - }) - ) - }) -}) - -describe("useAdminOrderEditDeleteLineItem hook", () => { - test("Remove line item of an order edit and create an item change", async () => { - const id = "oe_1" - const itemId = "item_1" - const { result, waitFor } = renderHook( - () => useAdminOrderEditDeleteLineItem(id, itemId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order_edit).toEqual( - expect.objectContaining({ - ...fixtures.get("order_edit"), - changes: expect.arrayContaining([ - expect.objectContaining({ - type: "item_remove", - }), - ]), - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/order-edits/queries.test.ts b/packages/medusa-react/test/hooks/admin/order-edits/queries.test.ts deleted file mode 100644 index a54de9b769..0000000000 --- a/packages/medusa-react/test/hooks/admin/order-edits/queries.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminOrderEdit, useAdminOrderEdits } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminOrderEdit hook", () => { - test("returns an order edit", async () => { - const order_edit = fixtures.get("order_edit") - const { result, waitFor } = renderHook( - () => useAdminOrderEdit(order_edit.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.order_edit).toEqual(order_edit) - }) -}) - -describe("useAdminOrderEdits hook", () => { - test("returns an order edit", async () => { - const order_edit = fixtures.get("order_edit") - const { result, waitFor } = renderHook(() => useAdminOrderEdits(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.order_edits).toEqual( - expect.arrayContaining([order_edit]) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/orders/mutations.test.ts b/packages/medusa-react/test/hooks/admin/orders/mutations.test.ts deleted file mode 100644 index 99ef0bc621..0000000000 --- a/packages/medusa-react/test/hooks/admin/orders/mutations.test.ts +++ /dev/null @@ -1,229 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminAddShippingMethod, - useAdminArchiveOrder, - useAdminCancelFulfillment, - useAdminCancelOrder, - useAdminCapturePayment, - useAdminCompleteOrder, - useAdminCreateFulfillment, - useAdminCreateShipment, - useAdminRefundPayment, - useAdminUpdateOrder, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminUpdateOrder hook", () => { - test("updates a order and returns it", async () => { - const order = { - email: "medusa@medusa.com", - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateOrder(fixtures.get("order").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(order) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual( - expect.objectContaining({ - ...fixtures.get("order"), - ...order, - }) - ) - }) -}) - -describe("useAdminCancelOrder hook", () => { - test("cancels an order", async () => { - const id = fixtures.get("order").id - - const { result, waitFor } = renderHook(() => useAdminCancelOrder(id), { - wrapper: createWrapper(), - }) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminArchiveOrder hook", () => { - test("archives an order", async () => { - const id = fixtures.get("order").id - - const { result, waitFor } = renderHook(() => useAdminArchiveOrder(id), { - wrapper: createWrapper(), - }) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminCompleteOrder hook", () => { - test("completes an order", async () => { - const id = fixtures.get("order").id - - const { result, waitFor } = renderHook(() => useAdminCompleteOrder(id), { - wrapper: createWrapper(), - }) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminCapturePayment hook", () => { - test("captures an order's payment", async () => { - const id = fixtures.get("order").id - - const { result, waitFor } = renderHook(() => useAdminCapturePayment(id), { - wrapper: createWrapper(), - }) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminRefundPayment hook", () => { - test("captures an order's payment", async () => { - const id = fixtures.get("order").id - - const payload = { - amount: 100, - reason: "wrong item", - } - - const { result, waitFor } = renderHook(() => useAdminRefundPayment(id), { - wrapper: createWrapper(), - }) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminCreateShipment hook", () => { - test("creates a shipment for an order", async () => { - const id = fixtures.get("order").id - - const payload = { - fulfillment_id: "test-ful", - tracking_numbers: [], - } - - const { result, waitFor } = renderHook(() => useAdminCreateShipment(id), { - wrapper: createWrapper(), - }) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminAddShippingMethod hook", () => { - test("adds a shipping method to an order", async () => { - const id = fixtures.get("order").id - - const payload = { - price: 1000, - option_id: "test-so", - } - - const { result, waitFor } = renderHook( - () => useAdminAddShippingMethod(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminCreateFulfillment hook", () => { - test("creates a fulfillment for an order", async () => { - const id = fixtures.get("order").id - - const fulfillment = { - items: [ - { - item_id: "test-item", - quantity: 2, - }, - ], - } - - const { result, waitFor } = renderHook( - () => useAdminCreateFulfillment(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(fulfillment) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminCancelFulfillment hook", () => { - test("cancels a fulfillment for an order", async () => { - const id = fixtures.get("order").id - const fulfillmentId = "test-ful" - - const { result, waitFor } = renderHook( - () => useAdminCancelFulfillment(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(fulfillmentId) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/orders/queries.test.ts b/packages/medusa-react/test/hooks/admin/orders/queries.test.ts deleted file mode 100644 index 6f25ba1132..0000000000 --- a/packages/medusa-react/test/hooks/admin/orders/queries.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminOrder, useAdminOrders } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminOrders hook", () => { - test("returns a list of orders", async () => { - const orders = fixtures.list("order") - const { result, waitFor } = renderHook(() => useAdminOrders(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.orders).toEqual(orders) - }) -}) - -describe("useAdminOrder hook", () => { - test("returns a order", async () => { - const order = fixtures.get("order") - const { result, waitFor } = renderHook(() => useAdminOrder(order.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.order).toEqual(order) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/payment-collections/mutations.test.ts b/packages/medusa-react/test/hooks/admin/payment-collections/mutations.test.ts deleted file mode 100644 index c42fbc7e08..0000000000 --- a/packages/medusa-react/test/hooks/admin/payment-collections/mutations.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { - useAdminDeletePaymentCollection, - useAdminMarkPaymentCollectionAsAuthorized, - useAdminUpdatePaymentCollection, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminDeletePaymentCollection hook", () => { - test("Delete a payment collection", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeletePaymentCollection("payment_collection_id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: "payment_collection_id", - deleted: true, - }) - ) - }) -}) - -describe("useAdminUpdatePaymentCollection hook", () => { - test("Update a Payment Collection", async () => { - const { result, waitFor } = renderHook( - () => useAdminUpdatePaymentCollection("payment_collection_id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - description: "new description", - metadata: { demo: "obj" }, - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.payment_collection).toEqual( - expect.objectContaining({ - id: "payment_collection_id", - description: "new description", - metadata: { demo: "obj" }, - }) - ) - }) -}) - -describe("useAdminMarkPaymentCollectionAsAuthorized hook", () => { - test("Mark a Payment Collection as Authorized", async () => { - const { result, waitFor } = renderHook( - () => useAdminMarkPaymentCollectionAsAuthorized("payment_collection_id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.payment_collection).toEqual( - expect.objectContaining({ - id: "payment_collection_id", - status: "authorized", - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/payment-collections/queries.test.ts b/packages/medusa-react/test/hooks/admin/payment-collections/queries.test.ts deleted file mode 100644 index bf91b07aed..0000000000 --- a/packages/medusa-react/test/hooks/admin/payment-collections/queries.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminPaymentCollection } from "../../../../src/hooks/admin/payment-collections" -import { createWrapper } from "../../../utils" - -describe("useAdminPaymentCollection hook", () => { - test("returns a payment collection", async () => { - const payment_collection = fixtures.get("payment_collection") - const { result, waitFor } = renderHook( - () => useAdminPaymentCollection(payment_collection.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.payment_collection).toEqual(payment_collection) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/payments/mutations.test.ts b/packages/medusa-react/test/hooks/admin/payments/mutations.test.ts deleted file mode 100644 index b6e789ce50..0000000000 --- a/packages/medusa-react/test/hooks/admin/payments/mutations.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { RefundReason } from "@medusajs/medusa" -import { renderHook } from "@testing-library/react-hooks/dom" -import { - useAdminPaymentsCapturePayment, - useAdminPaymentsRefundPayment, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminPaymentsCapturePayment hook", () => { - test("Capture a payment", async () => { - const { result, waitFor } = renderHook( - () => useAdminPaymentsCapturePayment("payment_id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.payment).toEqual( - expect.objectContaining({ - amount_captured: 900, - }) - ) - }) -}) - -describe("useAdminPaymentsRefundPayment hook", () => { - test("Update a Payment Collection", async () => { - const { result, waitFor } = renderHook( - () => useAdminPaymentsRefundPayment("payment_id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - amount: 500, - reason: RefundReason.DISCOUNT, - note: "note to refund", - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.refund).toEqual( - expect.objectContaining({ - payment_id: "payment_id", - amount: 500, - reason: RefundReason.DISCOUNT, - note: "note to refund", - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/payments/queries.test.ts b/packages/medusa-react/test/hooks/admin/payments/queries.test.ts deleted file mode 100644 index d987b57395..0000000000 --- a/packages/medusa-react/test/hooks/admin/payments/queries.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminPayment } from "../../../../src/hooks/admin/payments" -import { createWrapper } from "../../../utils" - -describe("useAdminPayment hook", () => { - test("returns a payment collection", async () => { - const payment = fixtures.get("payment") - const { result, waitFor } = renderHook(() => useAdminPayment(payment.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.payment).toEqual(payment) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/price-lists/mutations.test.ts b/packages/medusa-react/test/hooks/admin/price-lists/mutations.test.ts deleted file mode 100644 index c88e9c61f8..0000000000 --- a/packages/medusa-react/test/hooks/admin/price-lists/mutations.test.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreatePriceList, - useAdminCreatePriceListPrices, - useAdminDeletePriceList, - useAdminDeletePriceListPrices, - useAdminDeletePriceListProductPrices, - useAdminDeletePriceListVariantPrices, - useAdminUpdatePriceList, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -import { PriceListType } from "@medusajs/medusa/dist/types/price-list" - -describe("useAdminCreatePriceList hook", () => { - test("creates a price list and returns it", async () => { - const priceList = { - name: "talked to customer", - type: PriceListType.SALE, - description: "test", - prices: [], - } - - const { result, waitFor } = renderHook(() => useAdminCreatePriceList(), { - wrapper: createWrapper(), - }) - - result.current.mutate(priceList) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.price_list).toEqual( - expect.objectContaining({ - ...fixtures.get("price_list"), - ...priceList, - }) - ) - }) -}) - -describe("useAdminUpdatePriceList hook", () => { - test("updates a price list and returns it", async () => { - const priceList = { - name: "talked to customer", - type: PriceListType.SALE, - prices: [], - customer_groups: [], - } - - const { result, waitFor } = renderHook( - () => useAdminUpdatePriceList(fixtures.get("price_list").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(priceList) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.price_list).toEqual( - expect.objectContaining({ - ...fixtures.get("price_list"), - ...priceList, - }) - ) - }) -}) - -describe("useAdminDeletePriceList hook", () => { - test("deletes a price list", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeletePriceList(fixtures.get("price_list").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: fixtures.get("price_list").id, - deleted: true, - }) - ) - }) -}) - -describe("useAdminDeletePriceListBatch hook", () => { - test("deletes a money amounts from price list", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeletePriceListPrices(fixtures.get("price_list").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ price_ids: [fixtures.get("money_amount").id] }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - ids: [fixtures.get("money_amount").id], - deleted: true, - }) - ) - }) -}) - -describe("useAdminDeletePriceList hook", () => { - test("Adds prices to price list", async () => { - const { result, waitFor } = renderHook( - () => useAdminCreatePriceListPrices(fixtures.get("price_list").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ prices: [] }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - price_list: { - ...fixtures.get("price_list"), - }, - }) - ) - }) -}) - -describe("useAdminDeletePriceListProductPrices hook", () => { - test("should delete prices from a price list for all the variants related to the specified product", async () => { - const { result, waitFor } = renderHook( - () => - useAdminDeletePriceListProductPrices( - fixtures.get("price_list").id, - fixtures.get("product").id - ), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - ids: [], - object: "money-amount", - deleted: true, - }) - ) - }) -}) - -describe("useAdminDeletePriceListVariantPrices hook", () => { - test("should delete prices from a price list for the specified variant", async () => { - const { result, waitFor } = renderHook( - () => - useAdminDeletePriceListVariantPrices( - fixtures.get("price_list").id, - fixtures.get("product_variant").id - ), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - ids: [], - object: "money-amount", - deleted: true, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/price-lists/queries.test.ts b/packages/medusa-react/test/hooks/admin/price-lists/queries.test.ts deleted file mode 100644 index ce161c6231..0000000000 --- a/packages/medusa-react/test/hooks/admin/price-lists/queries.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminPriceList, useAdminPriceLists } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminPriceLists hook", () => { - test("returns a list of price lists", async () => { - const priceLists = fixtures.list("price_list") - const { result, waitFor } = renderHook(() => useAdminPriceLists(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.price_lists).toEqual(priceLists) - }) -}) - -describe("useAdminPriceList hook", () => { - test("returns a price list", async () => { - const priceList = fixtures.get("price_list") - const { result, waitFor } = renderHook( - () => useAdminPriceList(priceList.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.price_list).toEqual(priceList) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/product-categories/mutations.test.ts b/packages/medusa-react/test/hooks/admin/product-categories/mutations.test.ts deleted file mode 100644 index d4062e5e07..0000000000 --- a/packages/medusa-react/test/hooks/admin/product-categories/mutations.test.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" - -import { fixtures } from "../../../../mocks/data" -import { - useAdminAddProductsToCategory, - useAdminCreateProductCategory, - useAdminDeleteProductCategory, - useAdminDeleteProductsFromCategory, - useAdminUpdateProductCategory, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateProductCategory hook", () => { - test("creates a product category", async () => { - const category = { - name: "Jeans category", - } - - const { result, waitFor } = renderHook( - () => useAdminCreateProductCategory(), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(category) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.product_category).toEqual( - expect.objectContaining({ - ...fixtures.get("product_category"), - ...category, - }) - ) - }) -}) - -describe("useAdminUpdateProductCategory hook", () => { - test("updates a product category", async () => { - const category = { - name: "Updated name", - } - - const categoryId = fixtures.get("product_category").id - - const { result, waitFor } = renderHook( - () => useAdminUpdateProductCategory(categoryId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(category) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.product_category).toEqual({ - ...fixtures.get("product_category"), - ...category, - }) - }) -}) - -describe("useAdminDeleteProductCategory hook", () => { - test("deletes a product category", async () => { - const id = fixtures.get("product_category").id - - const { result, waitFor } = renderHook( - () => useAdminDeleteProductCategory(id), - { wrapper: createWrapper() } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data).toEqual( - expect.objectContaining({ - id, - object: "product-category", - deleted: true, - }) - ) - }) -}) - -describe("useAdminAddProductsToCategory hook", () => { - test("add products to a product category", async () => { - const id = fixtures.get("product_category").id - const productId = fixtures.get("product").id - - const { result, waitFor } = renderHook( - () => useAdminAddProductsToCategory(id), - { wrapper: createWrapper() } - ) - - result.current.mutate({ product_ids: [{ id: productId }] }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data).toEqual( - expect.objectContaining({ - product_category: fixtures.get("product_category"), - }) - ) - }) -}) - -describe("useAdminDeleteProductsFromCategory hook", () => { - test("remove products from a product category", async () => { - const id = fixtures.get("product_category").id - const productId = fixtures.get("product").id - - const { result, waitFor } = renderHook( - () => useAdminDeleteProductsFromCategory(id), - { wrapper: createWrapper() } - ) - - result.current.mutate({ product_ids: [{ id: productId }] }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data).toEqual( - expect.objectContaining({ - product_category: fixtures.get("product_category"), - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/product-categories/queries.test.ts b/packages/medusa-react/test/hooks/admin/product-categories/queries.test.ts deleted file mode 100644 index cbac614f67..0000000000 --- a/packages/medusa-react/test/hooks/admin/product-categories/queries.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminProductCategories, - useAdminProductCategory, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminProductCategories hook", () => { - test("returns a list of categories", async () => { - const categories = fixtures.list("product_category") - - const { result, waitFor } = renderHook(() => useAdminProductCategories(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.product_categories).toEqual(categories) - }) -}) - -describe("useAdminProductCategory hook", () => { - test("returns a category", async () => { - const category = fixtures.get("product_category") - - const { result, waitFor } = renderHook( - () => useAdminProductCategory(category.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.product_category).toEqual(category) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/products/mutations.test.ts b/packages/medusa-react/test/hooks/admin/products/mutations.test.ts deleted file mode 100644 index 8729998715..0000000000 --- a/packages/medusa-react/test/hooks/admin/products/mutations.test.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateProduct, - useAdminCreateProductOption, - useAdminDeleteProduct, - useAdminDeleteProductOption, - useAdminUpdateProduct, - useAdminUpdateProductOption, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateProduct hook", () => { - test("creates a product and returns it", async () => { - const product = { - title: "test-product", - is_giftcard: false, - discountable: false, - } - - const { result, waitFor } = renderHook(() => useAdminCreateProduct(), { - wrapper: createWrapper(), - }) - - result.current.mutate(product) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.product).toEqual( - expect.objectContaining({ - ...fixtures.get("product"), - ...product, - }) - ) - }) -}) - -describe("useAdminUpdateProduct hook", () => { - test("updates a product and returns it", async () => { - const id = fixtures.get("product").id - const product = { - title: "test-product-1", - images: [], - } - - const { result, waitFor } = renderHook(() => useAdminUpdateProduct(id), { - wrapper: createWrapper(), - }) - - result.current.mutate(product) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.product).toEqual( - expect.objectContaining({ - ...fixtures.get("product"), - ...product, - }) - ) - }) -}) - -describe("useAdminDeleteProduct hook", () => { - test("deletes a product", async () => { - const id = fixtures.get("product").id - - const { result, waitFor } = renderHook(() => useAdminDeleteProduct(id), { - wrapper: createWrapper(), - }) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id, - deleted: true, - }) - ) - }) -}) - -describe("useAdminCreateProductOption hook", () => { - test("creates a product option", async () => { - const productId = fixtures.get("product").id - - const { result, waitFor } = renderHook( - () => useAdminCreateProductOption(productId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - title: "color", - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.product).toEqual(fixtures.get("product")) - }) -}) - -describe("useAdminUpdateProductOption hook", () => { - test("updates a product option", async () => { - const productId = fixtures.get("product").id - - const { result, waitFor } = renderHook( - () => useAdminUpdateProductOption(productId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - title: "size", - option_id: "test-option", - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.product).toEqual(fixtures.get("product")) - }) -}) - -describe("useAdminDeleteProductOption hook", () => { - test("deletes a product option", async () => { - const productId = fixtures.get("product").id - - const { result, waitFor } = renderHook( - () => useAdminDeleteProductOption(productId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate("test-option") - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - option_id: "test-option", - deleted: true, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/products/queries.test.ts b/packages/medusa-react/test/hooks/admin/products/queries.test.ts deleted file mode 100644 index 3688874e06..0000000000 --- a/packages/medusa-react/test/hooks/admin/products/queries.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminProduct, - useAdminProducts, - useAdminProductTagUsage, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminProducts hook", () => { - test("returns a list of products", async () => { - const products = fixtures.list("product") - const { result, waitFor } = renderHook(() => useAdminProducts(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.products).toEqual(products) - }) -}) - -describe("useAdminProductTagUsage hook", () => { - test("returns a list of product tags", async () => { - const tags = fixtures.list("product_tag") - const { result, waitFor } = renderHook(() => useAdminProductTagUsage(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.tags).toEqual(tags) - }) -}) - -describe("useAdminProduct hook", () => { - test("returns a product", async () => { - const product = fixtures.get("product") - const { result, waitFor } = renderHook(() => useAdminProduct(product.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.product).toEqual(product) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/publishable-api-keys/mutations.test.ts b/packages/medusa-react/test/hooks/admin/publishable-api-keys/mutations.test.ts deleted file mode 100644 index aee26d7986..0000000000 --- a/packages/medusa-react/test/hooks/admin/publishable-api-keys/mutations.test.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" - -import { fixtures } from "../../../../mocks/data" -import { - useAdminAddPublishableKeySalesChannelsBatch, - useAdminCreatePublishableApiKey, - useAdminDeletePublishableApiKey, - useAdminRemovePublishableKeySalesChannelsBatch, - useAdminRevokePublishableApiKey, - useAdminUpdatePublishableApiKey, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminCreatePublishableApiKey hook", () => { - test("Created a publishable api key", async () => { - const { result, waitFor } = renderHook( - () => useAdminCreatePublishableApiKey(), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ title: "Mandatory title" }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - publishable_api_key: { - title: "Mandatory title", - ...fixtures.get("publishable_api_key"), - }, - }) - ) - }) -}) - -describe("useAdminUpdatePublishableApiKey hook", () => { - test("updates an publishable key and returns it", async () => { - const pubKey = { - title: "changed title", - } - - const { result, waitFor } = renderHook( - () => - useAdminUpdatePublishableApiKey(fixtures.get("publishable_api_key").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(pubKey) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.publishable_api_key).toEqual( - expect.objectContaining({ - ...fixtures.get("publishable_api_key"), - ...pubKey, - }) - ) - }) -}) - -describe("useAdminRevokePublishableApiKey hook", () => { - test("Revoke a publishable api key", async () => { - const id = "pubkey_1234" - const { result, waitFor } = renderHook( - () => useAdminRevokePublishableApiKey(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - publishable_api_key: { - ...fixtures.get("publishable_api_key"), - revoked_at: "2022-11-10 11:17:46.666Z", - revoked_by: "admin_user", - id, - }, - }) - ) - }) -}) - -describe("useAdminDeletePublishableApiKey hook", () => { - test("Deletes a publishable api key", async () => { - const id = "pubkey_1234" - const { result, waitFor } = renderHook( - () => useAdminDeletePublishableApiKey(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id, - object: "publishable_api_key", - deleted: true, - }) - ) - }) -}) - -describe("useAdminAddPublishableKeySalesChannelsBatch hook", () => { - test("Adds a SC to the publishable api key scope", async () => { - const id = "pubkey_1234" - - const { result, waitFor } = renderHook( - () => useAdminAddPublishableKeySalesChannelsBatch(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - sales_channel_ids: [{ id: "rand_id" }], - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.publishable_api_key).toEqual( - expect.objectContaining({ - ...fixtures.get("publishable_api_key"), - }) - ) - }) -}) - -describe("useAdminRemovePublishableKeySalesChannelsBatch hook", () => { - test("Deletes a SC from the publishable api key scope", async () => { - const id = "pubkey_1234" - const { result, waitFor } = renderHook( - () => useAdminRemovePublishableKeySalesChannelsBatch(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - sales_channel_ids: [{ id: "rand_id" }], - }) - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.publishable_api_key).toEqual( - expect.objectContaining({ - ...fixtures.get("publishable_api_key"), - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/publishable-api-keys/queries.test.ts b/packages/medusa-react/test/hooks/admin/publishable-api-keys/queries.test.ts deleted file mode 100644 index 22747a2a2a..0000000000 --- a/packages/medusa-react/test/hooks/admin/publishable-api-keys/queries.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" - -import { fixtures } from "../../../../mocks/data" -import { - useAdminPublishableApiKey, - useAdminPublishableApiKeys, - useAdminPublishableApiKeySalesChannels, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminPublishableApiKey hook", () => { - test("returns an publishable api key", async () => { - const publishable_api_key = fixtures.get("publishable_api_key") - const { result, waitFor } = renderHook( - () => useAdminPublishableApiKey(publishable_api_key.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.publishable_api_key).toEqual(publishable_api_key) - }) -}) - -describe("useAdminPublishableApiKeys hook", () => { - test("returns a list of publishable api keys", async () => { - const publishable_api_key = fixtures.get("publishable_api_key") - const { result, waitFor } = renderHook(() => useAdminPublishableApiKeys(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.publishable_api_keys).toEqual( - expect.arrayContaining([publishable_api_key]) - ) - }) -}) - -describe("useAdminPublishableApiKeySalesChannels hook", () => { - test("returns a list of sales channels of a publishable api key", async () => { - const publishable_api_key = fixtures.get("publishable_api_key") - - const { result, waitFor } = renderHook( - () => useAdminPublishableApiKeySalesChannels(publishable_api_key.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.sales_channels).toEqual( - fixtures.get("sales_channels") - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/regions/mutations.test.ts b/packages/medusa-react/test/hooks/admin/regions/mutations.test.ts deleted file mode 100644 index 8c5845a92b..0000000000 --- a/packages/medusa-react/test/hooks/admin/regions/mutations.test.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateRegion, - useAdminDeleteRegion, - useAdminRegionAddFulfillmentProvider, - useAdminRegionAddPaymentProvider, - useAdminRegionDeleteFulfillmentProvider, - useAdminRegionDeletePaymentProvider, - useAdminUpdateRegion, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateRegion hook", () => { - test("creates a region and returns it", async () => { - const region = { - name: "test region", - currency_code: "eur", - tax_rate: 10, - payment_providers: [], - fulfillment_providers: [], - countries: [], - } - - const { result, waitFor } = renderHook(() => useAdminCreateRegion(), { - wrapper: createWrapper(), - }) - - result.current.mutate(region) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.region).toEqual( - expect.objectContaining({ - ...fixtures.get("region"), - ...region, - }) - ) - }) -}) - -describe("useAdminUpdateRegion hook", () => { - test("updates a region and returns it", async () => { - const region = { - name: "Africa", - } - const id = fixtures.get("region").id - - const { result, waitFor } = renderHook(() => useAdminUpdateRegion(id), { - wrapper: createWrapper(), - }) - - result.current.mutate(region) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.region).toEqual( - expect.objectContaining({ - ...fixtures.get("region"), - ...region, - }) - ) - }) -}) - -describe("useAdminDeleteRegion hook", () => { - test("deletes a region", async () => { - const id = fixtures.get("region").id - - const { result, waitFor } = renderHook(() => useAdminDeleteRegion(id), { - wrapper: createWrapper(), - }) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id, - deleted: true, - }) - ) - }) -}) - -describe("useAdminRegionAddFulfillmentProvider hook", () => { - test("adds a fulfillment provider to a region", async () => { - const payload = { - provider_id: "test-ful", - } - const id = fixtures.get("region").id - - const { result, waitFor } = renderHook( - () => useAdminRegionAddFulfillmentProvider(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.region).toEqual(fixtures.get("region")) - }) -}) - -describe("useAdminRegionDeleteFulfillmentProvider hook", () => { - test("deletes a region's fulfillment provider", async () => { - const id = fixtures.get("region").id - - const { result, waitFor } = renderHook( - () => useAdminRegionDeleteFulfillmentProvider(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate("test-ful") - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.region).toEqual(fixtures.get("region")) - }) -}) - -describe("useAdminRegionAddPaymentProvider hook", () => { - test("adds a payment provider to a region", async () => { - const payload = { - provider_id: "test-pay", - } - const id = fixtures.get("region").id - - const { result, waitFor } = renderHook( - () => useAdminRegionAddPaymentProvider(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.region).toEqual(fixtures.get("region")) - }) -}) - -describe("useAdminRegionDeletePaymentProvider hook", () => { - test("deletes a region's payment provider", async () => { - const id = fixtures.get("region").id - - const { result, waitFor } = renderHook( - () => useAdminRegionDeletePaymentProvider(id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate("test-pay") - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.region).toEqual(fixtures.get("region")) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/regions/queries.test.ts b/packages/medusa-react/test/hooks/admin/regions/queries.test.ts deleted file mode 100644 index cc912d8ad2..0000000000 --- a/packages/medusa-react/test/hooks/admin/regions/queries.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminRegion, - useAdminRegionFulfillmentOptions, - useAdminRegions, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminRegions hook", () => { - test("returns a list of regions", async () => { - const regions = fixtures.list("region") - const { result, waitFor } = renderHook(() => useAdminRegions(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.regions).toEqual(regions) - }) -}) - -describe("useAdminRegion hook", () => { - test("returns a region", async () => { - const region = fixtures.get("region") - const { result, waitFor } = renderHook(() => useAdminRegion(region.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.region).toEqual(region) - }) -}) - -describe("useAdminRegionFulfillmentOptions hook", () => { - test("returns a region's fulfillment options", async () => { - const region = fixtures.get("region") - const options = fixtures.get("fulfillment_option") - const { result, waitFor } = renderHook( - () => useAdminRegionFulfillmentOptions(region.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.fulfillment_options).toEqual(options) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/reservations/mutations.test.ts b/packages/medusa-react/test/hooks/admin/reservations/mutations.test.ts deleted file mode 100644 index 741872fc63..0000000000 --- a/packages/medusa-react/test/hooks/admin/reservations/mutations.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateReservation, - useAdminDeleteReservation, - useAdminUpdateReservation, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateShippingProfile hook", () => { - test("creates a shipping profile and returns it", async () => { - const reservationPayload = { - location_id: "loc_1", - inventory_item_id: "inv_1", - quantity: 2, - } - - const { result, waitFor } = renderHook(() => useAdminCreateReservation(), { - wrapper: createWrapper(), - }) - - result.current.mutate(reservationPayload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.reservation).toEqual( - expect.objectContaining({ - ...fixtures.get("reservation"), - ...reservationPayload, - }) - ) - }) -}) - -describe("useAdminUpdateShippingProfile hook", () => { - test("updates a shipping profile and returns it", async () => { - const reservationPayload = { - quantity: 3, - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateReservation(fixtures.get("reservation").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(reservationPayload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.reservation).toEqual( - expect.objectContaining({ - ...fixtures.get("reservation"), - quantity: 3, - }) - ) - }) -}) - -describe("useAdminDeleteShippingProfile hook", () => { - test("deletes a shipping profile", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteReservation(fixtures.get("reservation").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: fixtures.get("reservation").id, - object: "reservation", - deleted: true, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/reservations/queries.test.ts b/packages/medusa-react/test/hooks/admin/reservations/queries.test.ts deleted file mode 100644 index f351d0db56..0000000000 --- a/packages/medusa-react/test/hooks/admin/reservations/queries.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminReservation, useAdminReservations } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminShippingProfiles hook", () => { - test("returns a list of shipping profiles", async () => { - const reservations = fixtures.list("reservation") - const { result, waitFor } = renderHook(() => useAdminReservations(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.reservations).toEqual(reservations) - }) -}) - -describe("useAdminShippingProfile hook", () => { - test("returns a shipping profile", async () => { - const reservation = fixtures.get("reservation") - const { result, waitFor } = renderHook( - () => useAdminReservation(reservation.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.reservation).toEqual(reservation) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/return-reasons/mutations.test.ts b/packages/medusa-react/test/hooks/admin/return-reasons/mutations.test.ts deleted file mode 100644 index 50f5ed2a01..0000000000 --- a/packages/medusa-react/test/hooks/admin/return-reasons/mutations.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateReturnReason, - useAdminDeleteReturnReason, - useAdminUpdateReturnReason, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateReturnReason hook", () => { - test("creates a return reason and returns it", async () => { - const rr = { - value: "too_big", - label: "Too big", - description: "Shirt is too big in length", - } - - const { result, waitFor } = renderHook(() => useAdminCreateReturnReason(), { - wrapper: createWrapper(), - }) - - result.current.mutate(rr) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.return_reason).toEqual( - expect.objectContaining({ - ...fixtures.get("return_reason"), - ...rr, - }) - ) - }) -}) - -describe("useAdminUpdateReturnReason hook", () => { - test("updates a return reason and returns it", async () => { - const rr = { - value: "too_small", - label: "Too small", - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateReturnReason(fixtures.get("return_reason").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(rr) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.return_reason).toEqual( - expect.objectContaining({ - ...fixtures.get("return_reason"), - ...rr, - }) - ) - }) -}) - -describe("useAdminDeleteReturnReason hook", () => { - test("deletes a return reason", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteReturnReason(fixtures.get("return_reason").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: fixtures.get("return_reason").id, - deleted: true, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/return-reasons/queries.test.ts b/packages/medusa-react/test/hooks/admin/return-reasons/queries.test.ts deleted file mode 100644 index 7432a5a5fd..0000000000 --- a/packages/medusa-react/test/hooks/admin/return-reasons/queries.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminReturnReason, useAdminReturnReasons } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminReturnReasons hook", () => { - test("returns a list of return reasons", async () => { - const returnReasons = fixtures.list("return_reason") - const { result, waitFor } = renderHook(() => useAdminReturnReasons(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.return_reasons).toEqual(returnReasons) - }) -}) - -describe("useAdminReturnReason hook", () => { - test("returns a return reason", async () => { - const returnReason = fixtures.get("return_reason") - const { result, waitFor } = renderHook( - () => useAdminReturnReason(returnReason.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.return_reason).toEqual(returnReason) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/returns/mutations.test.ts b/packages/medusa-react/test/hooks/admin/returns/mutations.test.ts deleted file mode 100644 index 0e706922ea..0000000000 --- a/packages/medusa-react/test/hooks/admin/returns/mutations.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminCancelReturn, useAdminReceiveReturn } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCancel hook", () => { - test("cancels a return", async () => { - const { result, waitFor } = renderHook( - () => useAdminCancelReturn("test-return"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminReceiveReturn hook", () => { - test("marks a return as received", async () => { - const payload = { - items: [ - { - item_id: "test_id", - quantity: 1, - }, - ], - } - - const { result, waitFor } = renderHook( - () => useAdminReceiveReturn("test-return"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ ...payload }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.return).toEqual(fixtures.get("return")) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/returns/queries.test.ts b/packages/medusa-react/test/hooks/admin/returns/queries.test.ts deleted file mode 100644 index 18c2d9c3c2..0000000000 --- a/packages/medusa-react/test/hooks/admin/returns/queries.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminReturns } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminReturns hook", () => { - test("returns a list of returns", async () => { - const returns = fixtures.list("return") - const { result, waitFor } = renderHook(() => useAdminReturns(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.returns).toEqual(returns) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/sales-channels/mutations.test.ts b/packages/medusa-react/test/hooks/admin/sales-channels/mutations.test.ts deleted file mode 100644 index 467343c4af..0000000000 --- a/packages/medusa-react/test/hooks/admin/sales-channels/mutations.test.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" - -import { fixtures } from "../../../../mocks/data" -import { - useAdminAddProductsToSalesChannel, - useAdminCreateSalesChannel, - useAdminDeleteProductsFromSalesChannel, - useAdminDeleteSalesChannel, - useAdminUpdateSalesChannel, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateSalesChannel hook", () => { - test("returns a sales channel", async () => { - const salesChannel = { - name: "sales channel 1 name", - description: "sales channel 1 description", - } - - const { result, waitFor } = renderHook(() => useAdminCreateSalesChannel(), { - wrapper: createWrapper(), - }) - - result.current.mutate(salesChannel) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.sales_channel).toEqual( - expect.objectContaining({ - ...fixtures.get("sales_channel"), - ...salesChannel, - }) - ) - }) -}) - -describe("useAdminUpdateSalesChannel hook", () => { - test("updates a sales channel", async () => { - const salesChannel = { - name: "medusa sales channel", - description: "main sales channel for medusa", - is_disabled: true, - } - - const salesChannelId = fixtures.get("sales_channel").id - - const { result, waitFor } = renderHook( - () => useAdminUpdateSalesChannel(salesChannelId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(salesChannel) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.sales_channel).toEqual({ - ...fixtures.get("sales_channel"), - ...salesChannel, - }) - }) -}) - -describe("useAdminDeleteSalesChannel hook", () => { - test("deletes a sales channel", async () => { - const id = fixtures.get("sales_channel").id - - const { result, waitFor } = renderHook( - () => useAdminDeleteSalesChannel(id), - { wrapper: createWrapper() } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data).toEqual( - expect.objectContaining({ - id, - object: "sales-channel", - deleted: true, - }) - ) - }) -}) - -describe("useAdminDeleteProductsFromSalesChannel hook", () => { - test("remove products from a sales channel", async () => { - const id = fixtures.get("sales_channel").id - const productId = fixtures.get("product").id - - const { result, waitFor } = renderHook( - () => useAdminDeleteProductsFromSalesChannel(id), - { wrapper: createWrapper() } - ) - - result.current.mutate({ product_ids: [{ id: productId }] }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data).toEqual( - expect.objectContaining({ - sales_channel: fixtures.get("sales_channel"), - }) - ) - }) -}) - -describe("useAdminAddProductsToSalesChannel hook", () => { - test("add products to a sales channel", async () => { - const id = fixtures.get("sales_channel").id - const productId = fixtures.get("product").id - - const { result, waitFor } = renderHook( - () => useAdminAddProductsToSalesChannel(id), - { wrapper: createWrapper() } - ) - - result.current.mutate({ product_ids: [{ id: productId }] }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data).toEqual( - expect.objectContaining({ - sales_channel: fixtures.get("sales_channel"), - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/sales-channels/queries.test.ts b/packages/medusa-react/test/hooks/admin/sales-channels/queries.test.ts deleted file mode 100644 index 428f296e80..0000000000 --- a/packages/medusa-react/test/hooks/admin/sales-channels/queries.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminSalesChannel, useAdminSalesChannels } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminSalesChannel hook", () => { - test("returns a sales channel", async () => { - const salesChannel = fixtures.get("sales_channel") - const { result, waitFor } = renderHook( - () => useAdminSalesChannel(salesChannel.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.sales_channel).toEqual(salesChannel) - }) -}) - -describe("useAdminSalesChannels hook", () => { - test("returns a list of sales channels", async () => { - const salesChannels = fixtures.get("sales_channels") - const { result, waitFor } = renderHook(() => useAdminSalesChannels(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.sales_channels).toEqual(salesChannels) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/shipping-options/mutations.test.ts b/packages/medusa-react/test/hooks/admin/shipping-options/mutations.test.ts deleted file mode 100644 index d2dfd2016e..0000000000 --- a/packages/medusa-react/test/hooks/admin/shipping-options/mutations.test.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateShippingOption, - useAdminDeleteShippingOption, - useAdminUpdateShippingOption, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateShippingOption hook", () => { - test("creates a shipping option and returns it", async () => { - const so = { - name: "test-so", - region_id: "test-region", - provider_id: "test-provider", - data: {}, - price_type: "flat", - } - - const { result, waitFor } = renderHook( - () => useAdminCreateShippingOption(), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(so) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.shipping_option).toEqual( - expect.objectContaining({ - ...fixtures.get("shipping_option"), - ...so, - }) - ) - }) -}) - -describe("useAdminUpdateShippingOption hook", () => { - test("updates a shipping option and returns it", async () => { - const so = { - name: "test-so", - requirements: [ - { - id: "test-so-req", - type: "thing", - amount: 500, - }, - ], - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateShippingOption(fixtures.get("shipping_option").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(so) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.shipping_option).toEqual( - expect.objectContaining({ - ...fixtures.get("shipping_option"), - ...so, - }) - ) - }) -}) - -describe("useAdminDeleteShippingOption hook", () => { - test("deletes a shipping option", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteShippingOption(fixtures.get("shipping_option").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: fixtures.get("shipping_option").id, - deleted: true, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/shipping-options/queries.test.ts b/packages/medusa-react/test/hooks/admin/shipping-options/queries.test.ts deleted file mode 100644 index 52bfb0a221..0000000000 --- a/packages/medusa-react/test/hooks/admin/shipping-options/queries.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminShippingOption, - useAdminShippingOptions, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminShippingOptions hook", () => { - test("returns a list of shipping options", async () => { - const shippingOptions = fixtures.list("shipping_option") - const { result, waitFor } = renderHook(() => useAdminShippingOptions(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.shipping_options).toEqual(shippingOptions) - }) -}) - -describe("useAdminShippingOption hook", () => { - test("returns a shipping option", async () => { - const shippingOption = fixtures.get("shipping_option") - const { result, waitFor } = renderHook( - () => useAdminShippingOption(shippingOption.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.shipping_option).toEqual(shippingOption) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/shipping-profiles/mutations.test.ts b/packages/medusa-react/test/hooks/admin/shipping-profiles/mutations.test.ts deleted file mode 100644 index b40f19c13c..0000000000 --- a/packages/medusa-react/test/hooks/admin/shipping-profiles/mutations.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateShippingProfile, - useAdminDeleteShippingProfile, - useAdminUpdateShippingProfile, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateShippingProfile hook", () => { - test("creates a shipping profile and returns it", async () => { - const sp = { - name: "test-sp", - } - - const { result, waitFor } = renderHook( - () => useAdminCreateShippingProfile(), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(sp) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.shipping_profile).toEqual( - expect.objectContaining({ - ...fixtures.get("shipping_profile"), - ...sp, - }) - ) - }) -}) - -describe("useAdminUpdateShippingProfile hook", () => { - test("updates a shipping profile and returns it", async () => { - const sp = { - name: "test-sp", - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateShippingProfile(fixtures.get("shipping_profile").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(sp) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.shipping_profile).toEqual( - expect.objectContaining({ - ...fixtures.get("shipping_profile"), - ...sp, - }) - ) - }) -}) - -describe("useAdminDeleteShippingProfile hook", () => { - test("deletes a shipping profile", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteShippingProfile(fixtures.get("shipping_profile").id), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: fixtures.get("shipping_profile").id, - deleted: true, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/shipping-profiles/queries.test.ts b/packages/medusa-react/test/hooks/admin/shipping-profiles/queries.test.ts deleted file mode 100644 index e794d862bd..0000000000 --- a/packages/medusa-react/test/hooks/admin/shipping-profiles/queries.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminShippingProfile, - useAdminShippingProfiles, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminShippingProfiles hook", () => { - test("returns a list of shipping profiles", async () => { - const shippingProfiles = fixtures.list("shipping_profile") - const { result, waitFor } = renderHook(() => useAdminShippingProfiles(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.shipping_profiles).toEqual(shippingProfiles) - }) -}) - -describe("useAdminShippingProfile hook", () => { - test("returns a shipping profile", async () => { - const shippingProfile = fixtures.get("shipping_profile") - const { result, waitFor } = renderHook( - () => useAdminShippingProfile(shippingProfile.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.shipping_profile).toEqual(shippingProfile) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/stock-location/mutations.test.ts b/packages/medusa-react/test/hooks/admin/stock-location/mutations.test.ts deleted file mode 100644 index b1c444ceb9..0000000000 --- a/packages/medusa-react/test/hooks/admin/stock-location/mutations.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateStockLocation, - useAdminDeleteStockLocation, - useAdminUpdateStockLocation, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminUpdateStockLocation hook", () => { - test("updates a stock location", async () => { - const payload = { - name: "updated name", - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateStockLocation("stock-location-id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.stock_location).toEqual( - expect.objectContaining({ - id: "stock-location-id", - name: "updated name", - }) - ) - }) -}) - -describe("useAdminCreateStockLocation hook", () => { - test("creates a stock location", async () => { - const locationFixture = fixtures.get("stock_location") - const payload = { - name: "updated name", - } - - const { result, waitFor } = renderHook( - () => useAdminCreateStockLocation(), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.stock_location).toEqual( - expect.objectContaining({ - ...locationFixture, - ...payload, - }) - ) - }) -}) - -describe("useAdminDeleteStockLocation hook", () => { - test("deletes a stock location", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteStockLocation("stock-location-id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id: "stock-location-id", - object: "stock_location", - deleted: true, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/stock-location/queries.test.ts b/packages/medusa-react/test/hooks/admin/stock-location/queries.test.ts deleted file mode 100644 index 0e5c407d9c..0000000000 --- a/packages/medusa-react/test/hooks/admin/stock-location/queries.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminStockLocation, useAdminStockLocations } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminUpdateStockLocation hook", () => { - test("gets a stock location", async () => { - const stockLocation = fixtures.get("stock_location") - const { result, waitFor } = renderHook( - () => useAdminStockLocation("stock-location-id"), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.stock_location).toEqual( - expect.objectContaining({ - ...stockLocation, - id: "stock-location-id", - }) - ) - }) -}) - -describe("useAdminUpdateStockLocations hook", () => { - test("lists stock locations", async () => { - const stockLocation = fixtures.list("stock_location") - const { result, waitFor } = renderHook(() => useAdminStockLocations(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.stock_locations).toEqual(stockLocation) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/store/mutations.test.ts b/packages/medusa-react/test/hooks/admin/store/mutations.test.ts deleted file mode 100644 index 3ecc824004..0000000000 --- a/packages/medusa-react/test/hooks/admin/store/mutations.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminAddStoreCurrency, - useAdminDeleteStoreCurrency, - useAdminUpdateStore, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminUpdateStore hook", () => { - test("updates a store", async () => { - const store = { - name: "medusa-store", - swap_link_template: "template", - payment_link_template: "payment", - } - - const { result, waitFor } = renderHook(() => useAdminUpdateStore(), { - wrapper: createWrapper(), - }) - - result.current.mutate(store) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.store).toEqual({ - ...fixtures.get("store"), - ...store, - }) - }) -}) - -describe("useAdminAddStoreCurrency hook", () => { - test("adds a currency to the store", async () => { - const { result, waitFor } = renderHook(() => useAdminAddStoreCurrency(), { - wrapper: createWrapper(), - }) - - result.current.mutate("eur") - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.store).toEqual(fixtures.get("store")) - }) -}) - -describe("useAdminDeleteStoreCurrency hook", () => { - test("deletes a currency from the store", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteStoreCurrency(), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate("eur") - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.store).toEqual(fixtures.get("store")) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/store/queries.test.ts b/packages/medusa-react/test/hooks/admin/store/queries.test.ts deleted file mode 100644 index 6181ecff24..0000000000 --- a/packages/medusa-react/test/hooks/admin/store/queries.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminStore, useAdminStorePaymentProviders } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminStore hook", () => { - test("returns the store", async () => { - const store = fixtures.get("store") - const { result, waitFor } = renderHook(() => useAdminStore(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.store).toEqual(store) - }) -}) - -describe("useAdminListPaymentProviders hook", () => { - test("returns a list of the store's payment providers", async () => { - const store = fixtures.get("store") - const { result, waitFor } = renderHook( - () => useAdminStorePaymentProviders(), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.payment_providers).toEqual(store.payment_providers) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/swaps/mutations.test.ts b/packages/medusa-react/test/hooks/admin/swaps/mutations.test.ts deleted file mode 100644 index a36f9a39d0..0000000000 --- a/packages/medusa-react/test/hooks/admin/swaps/mutations.test.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCancelSwap, - useAdminCancelSwapFulfillment, - useAdminCreateSwap, - useAdminCreateSwapShipment, - useAdminFulfillSwap, - useAdminProcessSwapPayment, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateSwap hook", () => { - test("creates a swap and returns the order", async () => { - const orderId = fixtures.get("order").id - const swap = { - return_items: [ - { - item_id: "test-item", - quantity: 1, - }, - ], - additional_items: [ - { - variant_id: "another-item", - quantity: 1, - }, - ], - } - - const { result, waitFor } = renderHook(() => useAdminCreateSwap(orderId), { - wrapper: createWrapper(), - }) - - result.current.mutate(swap) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminFulfillSwap hook", () => { - test("receives a swap", async () => { - const orderId = fixtures.get("order").id - const swapId = "test-swap" - const payload = { - no_notification: false, - } - - const { result, waitFor } = renderHook(() => useAdminFulfillSwap(orderId), { - wrapper: createWrapper(), - }) - - result.current.mutate({ swap_id: swapId, ...payload }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminCreateSwapShipment hook", () => { - test("creates a swap shipment", async () => { - const orderId = fixtures.get("order").id - const swapId = "test-swap" - const payload = { - fulfillment_id: "test-ful", - tracking_numbers: [], - } - - const { result, waitFor } = renderHook( - () => useAdminCreateSwapShipment(orderId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ swap_id: swapId, ...payload }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminProcessSwapPayment hook", () => { - test("process a swap's payment", async () => { - const orderId = fixtures.get("order").id - const swapId = "test-swap" - - const { result, waitFor } = renderHook( - () => useAdminProcessSwapPayment(orderId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(swapId) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminCancelSwap hook", () => { - test("cancels a swap", async () => { - const orderId = fixtures.get("order").id - const swapId = "test-swap" - - const { result, waitFor } = renderHook(() => useAdminCancelSwap(orderId), { - wrapper: createWrapper(), - }) - - result.current.mutate(swapId) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) - -describe("useAdminCancelSwapFulfillment hook", () => { - test("cancels a swap", async () => { - const orderId = fixtures.get("order").id - const swapId = "test-swap" - const fulfillmentId = "test-ful" - - const { result, waitFor } = renderHook( - () => useAdminCancelSwapFulfillment(orderId), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ swap_id: swapId, fulfillment_id: fulfillmentId }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order).toEqual(fixtures.get("order")) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/swaps/queries.test.ts b/packages/medusa-react/test/hooks/admin/swaps/queries.test.ts deleted file mode 100644 index 8dfb8199d8..0000000000 --- a/packages/medusa-react/test/hooks/admin/swaps/queries.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminSwap, useAdminSwaps } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminSwaps hook", () => { - test("returns a list of swaps", async () => { - const swaps = fixtures.list("swap") - const { result, waitFor } = renderHook(() => useAdminSwaps(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.swaps).toEqual(swaps) - }) -}) - -describe("useAdminSwap hook", () => { - test("returns a swap", async () => { - const swap = fixtures.get("swap") - const { result, waitFor } = renderHook(() => useAdminSwap(swap.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.swap).toEqual(swap) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/uploads/mutations.test.ts b/packages/medusa-react/test/hooks/admin/uploads/mutations.test.ts deleted file mode 100644 index 2e575f3668..0000000000 --- a/packages/medusa-react/test/hooks/admin/uploads/mutations.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreatePresignedDownloadUrl, - useAdminDeleteFile, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminDeleteFile hook", () => { - test("Removes file with key and returns delete result", async () => { - const file_key = "test" - - const { result, waitFor } = renderHook(() => useAdminDeleteFile(), { - wrapper: createWrapper(), - }) - - result.current.mutate({ file_key }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ id: file_key, object: "file", deleted: true }) - ) - }) -}) - -describe("useAdminCreatePresignedDownloadUrl hook", () => { - test("", async () => { - const file_key = "test" - - const { result, waitFor } = renderHook( - () => useAdminCreatePresignedDownloadUrl(), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ file_key }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.download_url).toEqual(fixtures.get("upload").url) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/users/mutations.test.ts b/packages/medusa-react/test/hooks/admin/users/mutations.test.ts deleted file mode 100644 index c19cec2c40..0000000000 --- a/packages/medusa-react/test/hooks/admin/users/mutations.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateUser, - useAdminDeleteUser, - useAdminResetPassword, - useAdminSendResetPasswordToken, - useAdminUpdateUser, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateUser hook", () => { - test("creates a user and returns it", async () => { - const user = { - email: "lebron@james.com", - first_name: "Lebron", - last_name: "James", - role: "admin" as const, - password: "test-password", - } - - const { result, waitFor } = renderHook(() => useAdminCreateUser(), { - wrapper: createWrapper(), - }) - - result.current.mutate(user) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.user).toEqual( - expect.objectContaining({ - ...fixtures.get("user"), - ...user, - }) - ) - }) -}) - -describe("useAdminUpdateUser hook", () => { - test("updates a user and returns it", async () => { - const id = fixtures.get("user").id - const user = { - first_name: "Zack", - last_name: "Medusa", - } - - const { result, waitFor } = renderHook(() => useAdminUpdateUser(id), { - wrapper: createWrapper(), - }) - - result.current.mutate(user) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.user).toEqual( - expect.objectContaining({ - ...fixtures.get("user"), - ...user, - }) - ) - }) -}) - -describe("useAdminDeleteUser hook", () => { - test("deletes a user", async () => { - const id = fixtures.get("user").id - - const { result, waitFor } = renderHook(() => useAdminDeleteUser(id), { - wrapper: createWrapper(), - }) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - id, - deleted: true, - }) - ) - }) -}) - -describe("useAdminSendResetPasswordToken hook", () => { - test("sends a token to reset the password", async () => { - const payload = { - email: "admin@user.com", - } - - const { result, waitFor } = renderHook( - () => useAdminSendResetPasswordToken(), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - }) -}) - -describe("useAdminResetPassword hook", () => { - test("reset the password", async () => { - const payload = { - token: "test-token", - password: "new-password", - } - - const { result, waitFor } = renderHook(() => useAdminResetPassword(), { - wrapper: createWrapper(), - }) - - result.current.mutate(payload) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.user).toEqual( - expect.objectContaining(fixtures.get("user")) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/users/queries.test.ts b/packages/medusa-react/test/hooks/admin/users/queries.test.ts deleted file mode 100644 index 31a86c7a65..0000000000 --- a/packages/medusa-react/test/hooks/admin/users/queries.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useAdminUser, useAdminUsers } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useAdminUsers hook", () => { - test("returns a list of users", async () => { - const users = fixtures.list("user") - const { result, waitFor } = renderHook(() => useAdminUsers(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.users).toEqual(users) - }) -}) - -describe("useAdminUser hook", () => { - test("returns a user", async () => { - const user = fixtures.get("user") - const { result, waitFor } = renderHook(() => useAdminUser(user.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.user).toEqual(user) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/variants/mutations.test.ts b/packages/medusa-react/test/hooks/admin/variants/mutations.test.ts deleted file mode 100644 index ca932e6d3d..0000000000 --- a/packages/medusa-react/test/hooks/admin/variants/mutations.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAdminCreateVariant, - useAdminDeleteVariant, - useAdminUpdateVariant, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useAdminCreateVariant hook", () => { - test("creates a variant and returns it", async () => { - const variant = { - title: "Test variant", - inventory_quantity: 10, - prices: [ - { - amount: 1000, - }, - ], - options: [], - } - - const { result, waitFor } = renderHook( - () => useAdminCreateVariant("test-product"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(variant) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.product).toEqual(fixtures.get("product")) - }) -}) - -describe("useAdminUpdateVariant hook", () => { - test("updates a variant and returns it", async () => { - const variant = { - title: "Example variant", - inventory_quantity: 5, - prices: [], - options: [], - } - - const { result, waitFor } = renderHook( - () => useAdminUpdateVariant("test-product"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - ...variant, - variant_id: "test-variant", - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.product).toEqual(fixtures.get("product")) - }) -}) - -describe("useAdminDeleteVariant hook", () => { - test("deletes a variant", async () => { - const { result, waitFor } = renderHook( - () => useAdminDeleteVariant("test-product"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate("test-variant") - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data).toEqual( - expect.objectContaining({ - variant_id: "test-variant", - deleted: true, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/admin/variants/queries.test.ts b/packages/medusa-react/test/hooks/admin/variants/queries.test.ts deleted file mode 100644 index 907cae145b..0000000000 --- a/packages/medusa-react/test/hooks/admin/variants/queries.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { useAdminVariant, useAdminVariants, useAdminVariantsInventory } from "../../../../src" - -import { createWrapper } from "../../../utils" -import { fixtures } from "../../../../mocks/data" -import { renderHook } from "@testing-library/react-hooks" - -describe("useAdminVariants hook", () => { - test("returns a list of variants", async () => { - const variants = fixtures.list("product_variant") - const { result, waitFor } = renderHook(() => useAdminVariants(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.variants).toEqual(variants) - }) -}) - -describe("useAdminVariant hook", () => { - test("returns a variant", async () => { - const variant = fixtures.get("product_variant") - const { result, waitFor } = renderHook(() => useAdminVariant(variant.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.variant).toEqual(variant) - }) -}) - -describe("useAdminVariants hook", () => { - test("returns a variant with saleschannel locations", async () => { - const variant = fixtures.get("product_variant") - const { result, waitFor } = renderHook( - () => useAdminVariantsInventory(variant.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.variant).toEqual({ - ...variant, - sales_channel_availability: [ - { - channel_name: "default channel", - channel_id: "1", - available_quantity: 10, - }, - ], - }) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/carts/mutations.test.ts b/packages/medusa-react/test/hooks/store/carts/mutations.test.ts deleted file mode 100644 index a09f8fddab..0000000000 --- a/packages/medusa-react/test/hooks/store/carts/mutations.test.ts +++ /dev/null @@ -1,203 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useAddShippingMethodToCart, - useCompleteCart, - useCreateCart, - useCreatePaymentSession, - useDeletePaymentSession, - useRefreshPaymentSession, - useSetPaymentSession, - useUpdateCart, - useUpdatePaymentSession, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useCreateCart hook", () => { - test("creates a cart", async () => { - const { result, waitFor } = renderHook(() => useCreateCart(), { - wrapper: createWrapper(), - }) - - result.current.mutate({}) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.cart).toEqual(fixtures.get("cart")) - }) -}) - -describe("useUpdateCart hook", () => { - test("updates a cart", async () => { - const { result, waitFor } = renderHook(() => useUpdateCart("some-cart"), { - wrapper: createWrapper(), - }) - - result.current.mutate({ - email: "new@email.com", - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.cart).toEqual({ - ...fixtures.get("cart"), - id: "some-cart", - email: "new@email.com", - }) - }) -}) - -describe("useCompleteCart hook", () => { - test("completes a cart", async () => { - const { result, waitFor } = renderHook(() => useCompleteCart("test-cart"), { - wrapper: createWrapper(), - }) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.type).toEqual("order") - expect(result.current.data.data).toEqual(fixtures.get("order")) - }) -}) - -describe("useCreatePaymentSession hook", () => { - test("creates a payment session", async () => { - const { result, waitFor } = renderHook( - () => useCreatePaymentSession("test-cart"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.cart).toEqual({ - ...fixtures.get("cart"), - id: "test-cart", - }) - }) -}) - -describe("useUpdatePaymentSession hook", () => { - test("updates a payment session", async () => { - const { result, waitFor } = renderHook( - () => useUpdatePaymentSession("test-cart"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - data: {}, - provider_id: "stripe", - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.cart).toEqual({ - ...fixtures.get("cart"), - id: "test-cart", - }) - }) -}) - -describe("useRefreshPaymentSession hook", () => { - test("refreshes a payment session", async () => { - const { result, waitFor } = renderHook( - () => useRefreshPaymentSession("test-cart"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - provider_id: "stripe", - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.cart).toEqual({ - ...fixtures.get("cart"), - id: "test-cart", - }) - }) -}) - -describe("useSetPaymentSession hook", () => { - test("sets a payment session", async () => { - const { result, waitFor } = renderHook( - () => useSetPaymentSession("test-cart"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - provider_id: "stripe", - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.cart).toEqual({ - ...fixtures.get("cart"), - id: "test-cart", - }) - }) -}) - -describe("useDeletePaymentSession hook", () => { - test("deletes a payment session", async () => { - const { result, waitFor } = renderHook( - () => useDeletePaymentSession("test-cart"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - provider_id: "stripe", - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.cart).toEqual({ - ...fixtures.get("cart"), - id: "test-cart", - }) - }) -}) - -describe("useAddShippingMethodToCart hook", () => { - test("adds a shipping method to a cart", async () => { - const { result, waitFor } = renderHook( - () => useAddShippingMethodToCart("test-cart"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - option_id: "test-option", - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.cart).toEqual({ - ...fixtures.get("cart"), - id: "test-cart", - }) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/carts/queries.test.ts b/packages/medusa-react/test/hooks/store/carts/queries.test.ts deleted file mode 100644 index e37f129d50..0000000000 --- a/packages/medusa-react/test/hooks/store/carts/queries.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useGetCart } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useGetCart hook", () => { - test("returns a cart", async () => { - const cart = fixtures.get("cart") - const { result, waitFor } = renderHook(() => useGetCart(cart.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.cart).toEqual(cart) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/collections/queries.test.ts b/packages/medusa-react/test/hooks/store/collections/queries.test.ts deleted file mode 100644 index 70f5270d12..0000000000 --- a/packages/medusa-react/test/hooks/store/collections/queries.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useCollection, useCollections } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useCollections hook", () => { - test("returns a list of collections", async () => { - const collections = fixtures.list("product_collection") - const { result, waitFor } = renderHook(() => useCollections(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.collections).toEqual(collections) - }) -}) - -describe("useCollection hook", () => { - test("returns a collection", async () => { - const collection = fixtures.get("product_collection") - const { result, waitFor } = renderHook(() => useCollection(collection.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.collection).toEqual(collection) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/customers/mutations.test.ts b/packages/medusa-react/test/hooks/store/customers/mutations.test.ts deleted file mode 100644 index ef0bd27487..0000000000 --- a/packages/medusa-react/test/hooks/store/customers/mutations.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useCreateCustomer, useUpdateMe } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useCreateCustomer hook", () => { - test("creates a new customer", async () => { - const customer = { - first_name: "john", - last_name: "wick", - email: "johnwick@medusajs.com", - password: "supersecret", - phone: "111111", - } - - const { result, waitFor } = renderHook(() => useCreateCustomer(), { - wrapper: createWrapper(), - }) - - result.current.mutate(customer) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.customer).toEqual({ - ...fixtures.get("customer"), - ...customer, - }) - }) -}) - -describe("useUpdateMe hook", () => { - test("updates current customer", async () => { - const customer = { - first_name: "lebron", - last_name: "james", - email: "lebronjames@medusajs.com", - password: "supersecret", - phone: "111111", - } - - const { result, waitFor } = renderHook(() => useUpdateMe(), { - wrapper: createWrapper(), - }) - - result.current.mutate({ - id: "cus_test", - ...customer, - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.customer).toEqual({ - ...fixtures.get("customer"), - ...customer, - }) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/customers/queries.test.ts b/packages/medusa-react/test/hooks/store/customers/queries.test.ts deleted file mode 100644 index 53ec50ec26..0000000000 --- a/packages/medusa-react/test/hooks/store/customers/queries.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { rest } from "msw" -import { fixtures } from "../../../../mocks/data" -import { server } from "../../../../mocks/server" -import { useCustomerOrders, useMeCustomer } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useMeCustomer hook", () => { - test("returns customer", async () => { - const customer = fixtures.get("customer") - const { result, waitFor } = renderHook(() => useMeCustomer(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.customer).toEqual(customer) - }) -}) - -describe("useCustomerOrders hook", () => { - test("returns customer's orders", async () => { - const orders = fixtures.list("order", 5) - - const { result, waitFor } = renderHook(() => useCustomerOrders(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.orders).toEqual(orders) - expect(result.current.limit).toEqual(5) - expect(result.current.offset).toEqual(0) - }) - - test("propagates query params and returns customer's orders", async () => { - const orders = fixtures.list("order") - - server.use( - rest.get("/store/customers/me/orders", (req, res, ctx) => { - const limit = req.url.searchParams.get("limit") - const offset = req.url.searchParams.get("offset") - const expand = req.url.searchParams.get("expand") - const fields = req.url.searchParams.get("fields") - expect({ - limit, - offset, - expand, - fields, - }).toEqual({ - limit: "2", - offset: "5", - expand: "relation_1,relation_2", - fields: "field_1,field_2", - }) - return res( - ctx.status(200), - ctx.json({ - orders, - limit: 2, - offset: 5, - }) - ) - }) - ) - - const { result, waitFor } = renderHook( - () => - useCustomerOrders({ - limit: 2, - offset: 5, - expand: "relation_1,relation_2", - fields: "field_1,field_2", - }), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.orders).toEqual(orders) - expect(result.current.limit).toEqual(2) - expect(result.current.offset).toEqual(5) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/gift_cards/queries.test.ts b/packages/medusa-react/test/hooks/store/gift_cards/queries.test.ts deleted file mode 100644 index e9e281f776..0000000000 --- a/packages/medusa-react/test/hooks/store/gift_cards/queries.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useGiftCard } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useGiftCard hook", () => { - test("returns a gift card", async () => { - const giftCard = fixtures.get("gift_card") - const { result, waitFor } = renderHook(() => useGiftCard(giftCard.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.gift_card).toEqual(giftCard) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/line-items/mutations.test.ts b/packages/medusa-react/test/hooks/store/line-items/mutations.test.ts deleted file mode 100644 index e745855549..0000000000 --- a/packages/medusa-react/test/hooks/store/line-items/mutations.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { - useCreateLineItem, - useDeleteLineItem, - useUpdateLineItem, -} from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useCreateLineItem hook", () => { - test("creates a line item", async () => { - const lineItem = { - variant_id: "test-variant", - quantity: 1, - } - - const { result, waitFor } = renderHook( - () => useCreateLineItem("test-cart"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(lineItem) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.cart.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - ...lineItem, - }), - ]) - ) - }) -}) - -describe("useUpdateLineItem hook", () => { - test("updates a line item", async () => { - const lineItem = { - lineId: "some-item-id", - quantity: 3, - } - - const { result, waitFor } = renderHook( - () => useUpdateLineItem("test-cart"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(lineItem) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.cart.items).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: lineItem.lineId, - quantity: lineItem.quantity, - }), - ]) - ) - }) -}) - -describe("useDeleteLineItem hook", () => { - test("deletes a line item", async () => { - const lineItem = { - lineId: "some-item-id", - } - - const { result, waitFor } = renderHook( - () => useDeleteLineItem("test-cart"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(lineItem) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.cart).toEqual(fixtures.get("cart")) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/order-edits/mutations.test.ts b/packages/medusa-react/test/hooks/store/order-edits/mutations.test.ts deleted file mode 100644 index e0e9bfd9f7..0000000000 --- a/packages/medusa-react/test/hooks/store/order-edits/mutations.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { useCompleteOrderEdit, useDeclineOrderEdit } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useDeclineOrderEdit hook", () => { - test("decline an order edit", async () => { - const declineBody = { - declined_reason: "Wrong color", - } - - const { result, waitFor } = renderHook( - () => useDeclineOrderEdit("store_order_edit"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate(declineBody) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order_edit).toEqual( - expect.objectContaining({ - status: "declined", - ...declineBody, - }) - ) - }) -}) - -describe("useCompleteOrderEdit hook", () => { - test("complete an order edit", async () => { - const { result, waitFor } = renderHook( - () => useCompleteOrderEdit("store_order_edit"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate() - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.order_edit).toEqual( - expect.objectContaining({ - status: "confirmed", - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/order-edits/queries.test.ts b/packages/medusa-react/test/hooks/store/order-edits/queries.test.ts deleted file mode 100644 index 53eb1f8bca..0000000000 --- a/packages/medusa-react/test/hooks/store/order-edits/queries.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useOrderEdit } from "../../../../src/hooks/store/order-edits" -import { createWrapper } from "../../../utils" - -describe("useOrderEdit hook", () => { - test("returns an order", async () => { - const store_order_edit = fixtures.get("store_order_edit") - const { result, waitFor } = renderHook( - () => useOrderEdit(store_order_edit.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.order_edit).toEqual(store_order_edit) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/orders/mutations.test.ts b/packages/medusa-react/test/hooks/store/orders/mutations.test.ts deleted file mode 100644 index 9e5ac715ff..0000000000 --- a/packages/medusa-react/test/hooks/store/orders/mutations.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { useGrantOrderAccess, useRequestOrderAccess } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useGrantOrderAccess hook", () => { - test("Grant access to token", async () => { - const { result, waitFor } = renderHook(() => useGrantOrderAccess(), { - wrapper: createWrapper(), - }) - - result.current.mutate({ token: "store_order_edit" }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - }) -}) - -describe("useRequestOrderAccess hook", () => { - test("Requests access to ids", async () => { - const { result, waitFor } = renderHook(() => useRequestOrderAccess(), { - wrapper: createWrapper(), - }) - - result.current.mutate({ order_ids: [""] }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/orders/queries.test.ts b/packages/medusa-react/test/hooks/store/orders/queries.test.ts deleted file mode 100644 index f2ba2778f4..0000000000 --- a/packages/medusa-react/test/hooks/store/orders/queries.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { rest } from "msw" -import { fixtures } from "../../../../mocks/data" -import { server } from "../../../../mocks/server" -import { useCartOrder, useOrder } from "../../../../src/" -import { useOrders } from "../../../../src/hooks" -import { createWrapper } from "../../../utils" - -describe("useOrder hook", () => { - test("returns an order", async () => { - const order = fixtures.get("order") - const { result, waitFor } = renderHook(() => useOrder(order.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.order).toEqual(order) - }) -}) - -describe("useCartOrder hook", () => { - test("returns a cart order", async () => { - const order = fixtures.get("order") - const { result, waitFor } = renderHook(() => useCartOrder("test_cart"), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.order).toEqual(order) - }) -}) - -describe("useOrders hook", () => { - test("propagates the query params and returns an order", async () => { - const order = fixtures.get("order") - const displayId = 400, - emailParam = "customer@test.com" - - server.use( - rest.get("/store/orders", (req, res, ctx) => { - const display_id = req.url.searchParams.get("display_id") - const email = req.url.searchParams.get("email") - expect({ - display_id, - email, - }).toEqual({ - email: emailParam, - display_id: displayId.toString(), - }) - return res( - ctx.status(200), - ctx.json({ - order, - }) - ) - }) - ) - - const { result, waitFor } = renderHook( - () => - useOrders({ - display_id: displayId, - email: emailParam, - }), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.order).toEqual(order) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/payment-collections/mutations.test.ts b/packages/medusa-react/test/hooks/store/payment-collections/mutations.test.ts deleted file mode 100644 index 78b7e5e834..0000000000 --- a/packages/medusa-react/test/hooks/store/payment-collections/mutations.test.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { - useAuthorizePaymentSession, - useAuthorizePaymentSessionsBatch, - useManageMultiplePaymentSessions, - useManagePaymentSession, - usePaymentCollectionRefreshPaymentSession, -} from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useManageMultiplePaymentSessions hook", () => { - test("Manage multiple payment sessions of a payment collection", async () => { - const { result, waitFor } = renderHook( - () => useManageMultiplePaymentSessions("payment_collection_id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - sessions: { - provider_id: "manual", - amount: 900, - }, - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data?.payment_collection).toEqual( - expect.objectContaining({ - id: "payment_collection_id", - amount: 900, - }) - ) - }) -}) - -describe("useManagePaymentSession hook", () => { - test("Manage payment session of a payment collection", async () => { - const { result, waitFor } = renderHook( - () => useManagePaymentSession("payment_collection_id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - provider_id: "manual", - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data?.payment_collection).toEqual( - expect.objectContaining({ - id: "payment_collection_id", - amount: 900, - }) - ) - }) -}) - -describe("useAuthorizePaymentSession hook", () => { - test("Authorize a payment session of a Payment Collection", async () => { - const { result, waitFor } = renderHook( - () => useAuthorizePaymentSession("payment_collection_id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate("123") - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.payment_session).toEqual( - expect.objectContaining({ - id: "123", - amount: 900, - }) - ) - }) -}) - -describe("authorizePaymentSessionsBatch hook", () => { - test("Authorize all payment sessions of a Payment Collection", async () => { - const { result, waitFor } = renderHook( - () => useAuthorizePaymentSessionsBatch("payment_collection_id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate({ - session_ids: ["abc"], - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(207) - - expect(result.current.data.payment_collection).toEqual( - expect.objectContaining({ - id: "payment_collection_id", - payment_sessions: expect.arrayContaining([ - expect.objectContaining({ - amount: 900, - }), - ]), - }) - ) - }) -}) - -describe("usePaymentCollectionRefreshPaymentSession hook", () => { - test("Refresh a payment sessions of a Payment Collection", async () => { - const { result, waitFor } = renderHook( - () => usePaymentCollectionRefreshPaymentSession("payment_collection_id"), - { - wrapper: createWrapper(), - } - ) - - result.current.mutate("session_id") - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.payment_session).toEqual( - expect.objectContaining({ - id: "new_session_id", - amount: 900, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/payment-collections/queries.test.ts b/packages/medusa-react/test/hooks/store/payment-collections/queries.test.ts deleted file mode 100644 index e6379dd5e8..0000000000 --- a/packages/medusa-react/test/hooks/store/payment-collections/queries.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { usePaymentCollection } from "../../../../src/hooks/store/payment-collections" -import { createWrapper } from "../../../utils" - -describe("usePaymentCollection hook", () => { - test("returns a payment collection", async () => { - const payment_collection = fixtures.get("payment_collection") - const { result, waitFor } = renderHook( - () => usePaymentCollection(payment_collection.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.payment_collection).toEqual(payment_collection) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/product-tags/queries.test.ts b/packages/medusa-react/test/hooks/store/product-tags/queries.test.ts deleted file mode 100644 index 5174650776..0000000000 --- a/packages/medusa-react/test/hooks/store/product-tags/queries.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data/index" -import { useProductTags } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useProductTags hook", () => { - test("gets a list of products", async () => { - const { result, waitFor } = renderHook(() => useProductTags(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.product_tags).toEqual( - fixtures.list("product_tag", 10) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/products/queries.test.ts b/packages/medusa-react/test/hooks/store/products/queries.test.ts deleted file mode 100644 index 4171d2fd26..0000000000 --- a/packages/medusa-react/test/hooks/store/products/queries.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data/index" -import { useProduct, useProducts } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useProducts hook", () => { - test("gets a list of products", async () => { - const { result, waitFor } = renderHook(() => useProducts(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.products).toEqual(fixtures.list("product")) - }) - - test("gets a list of products based on limit and offset", async () => { - const { result, waitFor } = renderHook( - () => - useProducts({ - limit: 2, - offset: 5, - }), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.products).toEqual(fixtures.list("product")) - expect(result.current.limit).toEqual(2) - expect(result.current.offset).toEqual(5) - }) -}) - -describe("useProducts hook", () => { - test("success", async () => { - const { result, waitFor } = renderHook( - () => useProduct("prod_01F0YESHQ27Y31CAMD0NV6W9YP"), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.product).toEqual(fixtures.get("product")) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/regions/queries.test.ts b/packages/medusa-react/test/hooks/store/regions/queries.test.ts deleted file mode 100644 index 86fdf4a2c9..0000000000 --- a/packages/medusa-react/test/hooks/store/regions/queries.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useRegion, useRegions } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useRegions hook", () => { - test("success", async () => { - const regions = fixtures.list("region") - const { result, waitFor } = renderHook(() => useRegions(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.regions).toEqual(regions) - }) -}) - -describe("useRegion hook", () => { - test("success", async () => { - const region = fixtures.get("region") - const { result, waitFor } = renderHook(() => useRegion(region.id), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.region).toEqual(region) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/return-reasons/queries.test.ts b/packages/medusa-react/test/hooks/store/return-reasons/queries.test.ts deleted file mode 100644 index 6dc8855503..0000000000 --- a/packages/medusa-react/test/hooks/store/return-reasons/queries.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useReturnReason, useReturnReasons } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useReturnReasons hook", () => { - test("returns a list of return reasons", async () => { - const return_reasons = fixtures.list("return_reason") - const { result, waitFor } = renderHook(() => useReturnReasons(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.return_reasons).toEqual(return_reasons) - }) -}) - -describe("useReturnReason hook", () => { - test("returns a return reason", async () => { - const return_reason = fixtures.get("return_reason") - const { result, waitFor } = renderHook( - () => useReturnReason(return_reason.id), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.return_reason).toEqual(return_reason) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/returns/mutations.test.ts b/packages/medusa-react/test/hooks/store/returns/mutations.test.ts deleted file mode 100644 index 1ecf3f6143..0000000000 --- a/packages/medusa-react/test/hooks/store/returns/mutations.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useCreateReturn } from "../../../../src" -import { createWrapper } from "../../../utils" - -describe("useCreateReturn hook", () => { - test("creates a return", async () => { - const ret = { - order_id: "order_38", - items: [ - { - item_id: "test-item", - quantity: 1, - }, - ], - } - - const { result, waitFor } = renderHook(() => useCreateReturn(), { - wrapper: createWrapper(), - }) - - result.current.mutate(ret) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.return).toEqual( - expect.objectContaining({ - ...fixtures.get("return"), - order_id: ret.order_id, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/shipping-options/queries.test.ts b/packages/medusa-react/test/hooks/store/shipping-options/queries.test.ts deleted file mode 100644 index 14f1b6b781..0000000000 --- a/packages/medusa-react/test/hooks/store/shipping-options/queries.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { rest } from "msw" -import { fixtures } from "../../../../mocks/data" -import { server } from "../../../../mocks/server" -import { useCartShippingOptions, useShippingOptions } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useShippingOptions hook", () => { - test("returns a list of shipping options", async () => { - const shippingOptions = fixtures.list("shipping_option", 5) - const { result, waitFor } = renderHook(() => useShippingOptions(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.shipping_options).toEqual(shippingOptions) - }) - - test("when shipping options params are provided, then they should be sent as query params", async () => { - const shippingOptions = fixtures.list("shipping_option") - - server.use( - rest.get("/store/shipping-options/", (req, res, ctx) => { - const product_ids = req.url.searchParams.get("product_ids") - const is_return = req.url.searchParams.get("is_return") - const region_id = req.url.searchParams.get("region_id") - - expect({ - product_ids, - is_return, - region_id, - }).toEqual({ - product_ids: "1,2,3", - is_return: "false", - region_id: "test-region", - }) - - return res( - ctx.status(200), - ctx.json({ - shipping_options: fixtures.list("shipping_option"), - }) - ) - }) - ) - - const { result, waitFor } = renderHook( - () => - useShippingOptions({ - product_ids: "1,2,3", - is_return: "false", - region_id: "test-region", - }), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.shipping_options).toEqual(shippingOptions) - }) -}) - -describe("useCartShippingOptions hook", () => { - test("success", async () => { - const cartShippingOptions = fixtures.list("shipping_option") - const { result, waitFor } = renderHook( - () => useCartShippingOptions("cart_test"), - { - wrapper: createWrapper(), - } - ) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.shipping_options).toEqual(cartShippingOptions) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/swaps/mutations.test.ts b/packages/medusa-react/test/hooks/store/swaps/mutations.test.ts deleted file mode 100644 index e2513c4996..0000000000 --- a/packages/medusa-react/test/hooks/store/swaps/mutations.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useCreateSwap } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useCreateSwap hook", () => { - test("creates a return", async () => { - const swap = { - order_id: "order_test", - additional_items: [ - { - variant_id: "new-item", - quantity: 1, - }, - ], - return_items: [ - { - item_id: "return-item", - quantity: 1, - }, - ], - } - - const { result, waitFor } = renderHook(() => useCreateSwap(), { - wrapper: createWrapper(), - }) - - result.current.mutate(swap) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.data.response.status).toEqual(200) - expect(result.current.data.swap).toEqual( - expect.objectContaining({ - ...fixtures.get("swap"), - order_id: swap.order_id, - }) - ) - }) -}) diff --git a/packages/medusa-react/test/hooks/store/swaps/queries.test.ts b/packages/medusa-react/test/hooks/store/swaps/queries.test.ts deleted file mode 100644 index aae9f7bacc..0000000000 --- a/packages/medusa-react/test/hooks/store/swaps/queries.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { renderHook } from "@testing-library/react-hooks/dom" -import { fixtures } from "../../../../mocks/data" -import { useCartSwap } from "../../../../src/" -import { createWrapper } from "../../../utils" - -describe("useCartSwap hook", () => { - test("returns a swap", async () => { - const swap = fixtures.get("swap") - const { result, waitFor } = renderHook(() => useCartSwap("cart_test"), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.swap).toEqual(swap) - }) -}) diff --git a/packages/medusa-react/test/session-cart-context/session-cart.test.ts b/packages/medusa-react/test/session-cart-context/session-cart.test.ts deleted file mode 100644 index 12887eca7e..0000000000 --- a/packages/medusa-react/test/session-cart-context/session-cart.test.ts +++ /dev/null @@ -1,322 +0,0 @@ -import { generateCartState } from "../../src/contexts/session-cart" -import { ProductVariant } from "@medusajs/medusa" -import { useSessionCart } from "../../src" -import { act, renderHook } from "@testing-library/react-hooks" -import { fixtures } from "../../mocks/data" -import { createSessionCartWrapper } from "../utils" - -const initialSessionCartState = { - region: fixtures.get("region"), - totalItems: 0, - total: 0, - items: [], -} - -describe("useSessionCart hook", () => { - describe("sets a region", () => { - test("success", async () => { - const { result } = renderHook(() => useSessionCart(), { - wrapper: createSessionCartWrapper(), - }) - const { setRegion } = result.current - - act(() => { - setRegion(fixtures.get("region")) - }) - - const { region, total, totalItems } = result.current - - expect(region).toEqual(fixtures.get("region")) - expect(total).toEqual(0) - expect(totalItems).toEqual(0) - }) - }) - - describe("item operations", () => { - test("addItem", () => { - const { result } = renderHook(() => useSessionCart(), { - wrapper: createSessionCartWrapper(), - initialProps: { - initialState: initialSessionCartState, - }, - }) - const { addItem } = result.current - const variant = fixtures.get("product_variant") - - act(() => { - addItem({ - variant: (variant as unknown) as ProductVariant, - quantity: 1, - }) - }) - - const { items, totalItems, total } = result.current - - expect(totalItems).toBe(1) - expect(total).toBe(1000) - expect(items).toEqual([ - { - variant: expect.objectContaining(variant), - quantity: 1, - total: 1000, - }, - ]) - }) - - test("updateItem", () => { - const variant = fixtures.get("product_variant") - const { result } = renderHook(() => useSessionCart(), { - wrapper: createSessionCartWrapper(), - initialProps: { - initialState: generateCartState(initialSessionCartState, [ - { - variant: (variant as unknown) as ProductVariant, - quantity: 1, - }, - { - variant: ({ - ...variant, - id: "test-variant", - } as unknown) as ProductVariant, - quantity: 1, - }, - ]), - }, - }) - - const { updateItem } = result.current - - act(() => { - updateItem(variant.id, { - quantity: 4, - }) - }) - - const { items, totalItems, total } = result.current - - expect(totalItems).toBe(5) - expect(total).toBe(5 * 1000) - expect(items).toEqual([ - { - variant: expect.objectContaining(variant), - quantity: 4, - total: 1000, - }, - { - variant: { - ...variant, - id: "test-variant", - }, - quantity: 1, - total: 1000, - }, - ]) - }) - - test("removeItem", () => { - const variant = fixtures.get("product_variant") - const { result } = renderHook(() => useSessionCart(), { - wrapper: createSessionCartWrapper(), - initialProps: { - initialState: generateCartState(initialSessionCartState, [ - { - variant: (variant as unknown) as ProductVariant, - quantity: 3, - }, - { - variant: ({ - ...variant, - id: "test-variant", - } as unknown) as ProductVariant, - quantity: 1, - }, - ]), - }, - }) - - const { removeItem } = result.current - - act(() => { - removeItem(variant.id) - }) - - const { items, totalItems, total } = result.current - - expect(totalItems).toBe(1) - expect(total).toBe(1000) - expect(items).toEqual([ - { - variant: { - ...variant, - id: "test-variant", - }, - quantity: 1, - total: 1000, - }, - ]) - }) - - test("incrementItemQuantity", () => { - const variant = fixtures.get("product_variant") - const { result } = renderHook(() => useSessionCart(), { - wrapper: createSessionCartWrapper(), - initialProps: { - initialState: generateCartState(initialSessionCartState, [ - { - variant: (variant as unknown) as ProductVariant, - quantity: 2, - }, - ]), - }, - }) - - const { incrementItemQuantity } = result.current - - act(() => { - incrementItemQuantity(variant.id) - }) - - const { items, totalItems, total } = result.current - - expect(totalItems).toBe(3) - expect(total).toBe(3 * 1000) - expect(items).toEqual([ - { - variant, - quantity: 3, - total: 1000, - }, - ]) - }) - - test("decrementItemQuantity", () => { - const variant = fixtures.get("product_variant") - const { result } = renderHook(() => useSessionCart(), { - wrapper: createSessionCartWrapper(), - initialProps: { - initialState: generateCartState(initialSessionCartState, [ - { - variant: (variant as unknown) as ProductVariant, - quantity: 4, - }, - ]), - }, - }) - - const { decrementItemQuantity } = result.current - - act(() => { - decrementItemQuantity(variant.id) - }) - - const { items, totalItems, total } = result.current - - expect(totalItems).toBe(3) - expect(total).toBe(3 * 1000) - expect(items).toEqual([ - { - variant, - quantity: 3, - total: 1000, - }, - ]) - }) - - test("setItems", () => { - const variant = fixtures.get("product_variant") - const { result } = renderHook(() => useSessionCart(), { - wrapper: createSessionCartWrapper(), - initialProps: { - initialState: generateCartState(initialSessionCartState, [ - { - variant: (variant as unknown) as ProductVariant, - quantity: 4, - }, - ]), - }, - }) - - const { setItems } = result.current - - act(() => { - setItems([ - { - variant: ({ - ...variant, - id: "test-variant", - } as unknown) as ProductVariant, - quantity: 1, - }, - ]) - }) - - const { items, totalItems, total } = result.current - - expect(totalItems).toBe(1) - expect(total).toBe(1000) - expect(items).toEqual([ - { - variant: expect.objectContaining({ - id: "test-variant", - }), - quantity: 1, - total: 1000, - }, - ]) - }) - - test("getItem", () => { - const variant = fixtures.get("product_variant") - const { result } = renderHook(() => useSessionCart(), { - wrapper: createSessionCartWrapper(), - initialProps: { - initialState: generateCartState(initialSessionCartState, [ - { - variant: (variant as unknown) as ProductVariant, - quantity: 1, - }, - ]), - }, - }) - - const { getItem } = result.current - let item - act(() => { - item = getItem(variant.id) - }) - - expect(item).toEqual({ - variant, - quantity: 1, - total: 1000, - }) - }) - - test("clearItems", () => { - const variant = fixtures.get("product_variant") - const { result } = renderHook(() => useSessionCart(), { - wrapper: createSessionCartWrapper(), - initialProps: { - initialState: generateCartState(initialSessionCartState, [ - { - variant: (variant as unknown) as ProductVariant, - quantity: 4, - }, - ]), - }, - }) - - const { clearItems } = result.current - - act(() => { - clearItems() - }) - - const { items, totalItems, total } = result.current - - expect(totalItems).toBe(0) - expect(total).toBe(0) - expect(items).toEqual([]) - }) - }) -}) diff --git a/packages/medusa-react/test/utils.tsx b/packages/medusa-react/test/utils.tsx deleted file mode 100644 index 855e35c806..0000000000 --- a/packages/medusa-react/test/utils.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { QueryClient } from "@tanstack/react-query" -import * as React from "react" -import { - CartProvider, - MedusaProvider, - SessionCartProvider, - SessionCartState, -} from "../src" -import { Cart } from "../src/types" - -const createTestQueryClient = () => - new QueryClient({ - defaultOptions: { - queries: { - retry: false, - }, - }, - }) - -export function createWrapper() { - const qc = createTestQueryClient() - - return ({ children }) => ( - - {children} - - ) -} - -export function createSessionCartWrapper() { - const qc = createTestQueryClient() - - return ({ - children, - initialState, - }: { - initialState: SessionCartState - children?: React.ReactNode - }) => { - return ( - - - {children} - - - ) - } -} - -export function createCartWrapper() { - const qc = createTestQueryClient() - - return ({ - children, - initialSessionCartState, - initialCartState, - }: { - initialSessionCartState?: SessionCartState - initialCartState?: Cart - children?: React.ReactNode - }) => { - return ( - - - - {children} - - - - ) - } -} diff --git a/packages/medusa-react/test/utils/utils.test.ts b/packages/medusa-react/test/utils/utils.test.ts deleted file mode 100644 index a7adc834f8..0000000000 --- a/packages/medusa-react/test/utils/utils.test.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { RegionInfo, ProductVariantInfo } from "./../../src/types" -import { fixtures } from "./../../mocks/data/" -import { - computeVariantPrice, - getVariantPrice, - computeAmount, - formatAmount, - formatVariantPrice, -} from "./../../src/" - -describe("getVariantPrice", () => { - test("finds the variant price and returns its amount", () => { - const variant = fixtures.get("product_variant") - const region = fixtures.get("region") - const amount = getVariantPrice( - (variant as unknown) as ProductVariantInfo, - region - ) - - expect(amount).toEqual(1000) - }) - - test("when no region is provided, then it should return 0", () => { - const variant = fixtures.get("product_variant") - const amount = getVariantPrice( - (variant as unknown) as ProductVariantInfo, - {} as RegionInfo - ) - - expect(amount).toEqual(0) - }) - - test("when no product variant is provided, then it should return 0", () => { - const region = fixtures.get("region") - const amount = getVariantPrice({} as ProductVariantInfo, region) - - expect(amount).toEqual(0) - }) - - test("when no product variant and region are provided, then it should return 0", () => { - const amount = getVariantPrice({} as ProductVariantInfo, {} as RegionInfo) - - expect(amount).toEqual(0) - }) -}) - -describe("computeAmount", () => { - test("given an amount and a region, it should return a decimal amount not including taxes", () => { - const region = fixtures.get("region") - const amount = computeAmount({ amount: 3000, region, includeTaxes: false }) - - expect(amount).toEqual(30) - }) - - test("given an amount and a region, it should return a decimal amount including taxes", () => { - const region = fixtures.get("region") - const amount = computeAmount({ - amount: 3000, - region: { - ...region, - tax_rate: 10, - }, - }) - - expect(amount).toEqual(33) - }) - - test("when no region is provided, then it should return the decimal amount", () => { - const region = fixtures.get("region") - const amount = computeAmount({ amount: 2000, region }) - - expect(amount).toEqual(20) - }) -}) - -describe("computeVariantPrice", () => { - test("finds the variant price and returns a decimal amount not including taxes", () => { - const variant = fixtures.get("product_variant") - const region = fixtures.get("region") - const price = computeVariantPrice({ - variant: (variant as unknown) as ProductVariantInfo, - region, - }) - - expect(price).toEqual(10) - }) - - test("finds the variant price and returns a decimal amount including taxes", () => { - const variant = fixtures.get("product_variant") - const region = fixtures.get("region") - const price = computeVariantPrice({ - variant: (variant as unknown) as ProductVariantInfo, - region: { - ...region, - tax_rate: 15, - }, - includeTaxes: true, - }) - - expect(price).toEqual(11.5) - }) -}) - -describe("formatVariantPrice", () => { - test("given a variant and region, should return a decimal localized amount including taxes and the region's currency code", () => { - const region = fixtures.get("region") - const variant = fixtures.get("product_variant") - const price = formatVariantPrice({ - variant: (variant as unknown) as ProductVariantInfo, - region: { - ...region, - tax_rate: 15, - }, - }) - - expect(price).toEqual("$11.50") - }) - - test("given a variant, region, and a custom locale, should return a decimal localized amount including taxes and the region's currency code", () => { - const region = fixtures.get("region") - const variant = fixtures.get("product_variant") - const price = formatVariantPrice({ - variant: (variant as unknown) as ProductVariantInfo, - region: { - ...region, - tax_rate: 15, - }, - locale: "fr-FR", - }) - - expect(price.replace(/\s/, " ")).toEqual("11,50 $US") - }) -}) - -describe("formatAmount", () => { - test("given an amount and region, should return a decimal localized amount including taxes and the region's currency code", () => { - const region = fixtures.get("region") - const price = formatAmount({ - amount: 3000, - region: { - ...region, - tax_rate: 15, - }, - }) - - expect(price).toEqual("$34.50") - }) - - test("given an amount and no region, should return a decimal localized amount", () => { - const price = formatAmount({ amount: 3000, region: {} as RegionInfo }) - - expect(price).toEqual("30") - }) -}) diff --git a/packages/medusa-react/tsconfig.json b/packages/medusa-react/tsconfig.json deleted file mode 100644 index 70b7fabb60..0000000000 --- a/packages/medusa-react/tsconfig.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs - "include": ["src", "types", "node_modules/@types"], - "compilerOptions": { - "module": "esnext", - "lib": ["dom", "esnext"], - "importHelpers": true, - // output .d.ts declaration files for consumers - "declaration": true, - // output .js.map sourcemap files for consumers - "sourceMap": true, - // match output dir to input dir. e.g. dist/index instead of dist/src/index - "rootDir": "./src", - // stricter type-checking for stronger correctness. Recommended by TS - "strict": true, - // linter checks for common issues - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative - "noUnusedLocals": true, - "noUnusedParameters": true, - // use Node's module resolution algorithm, instead of the legacy TS one - "moduleResolution": "node", - // transpile JSX to React.createElement - "jsx": "react", - // interop between ESM and CJS modules. Recommended by TS - "esModuleInterop": true, - // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS - "skipLibCheck": true, - // error out if import and file system have a casing mismatch. Recommended by TS - "forceConsistentCasingInFileNames": true, - // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc` - "noEmit": true, - }, -} diff --git a/packages/medusa-react/tsup.config.ts b/packages/medusa-react/tsup.config.ts deleted file mode 100644 index 9f81bac28c..0000000000 --- a/packages/medusa-react/tsup.config.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Options } from "tsup" -import { peerDependencies } from "./package.json" - -const config: Options = { - entry: ["src/**/*.ts"], - dts: true, - clean: true, - minify: true, - bundle: true, - sourcemap: true, - format: ["cjs", "esm"], - target: "es2020", - skipNodeModulesBundle: true, - tsconfig: "./tsconfig.json", - external: Object.keys(peerDependencies), -} - -export default config diff --git a/packages/medusa/src/api/index.js b/packages/medusa/src/api/index.js deleted file mode 100644 index fd08f26953..0000000000 --- a/packages/medusa/src/api/index.js +++ /dev/null @@ -1,88 +0,0 @@ -import compression from "compression" -import { Router } from "express" -import { compressionOptions, shouldCompressResponse } from "../utils/api" -import errorHandler from "./middlewares/error-handler" -import admin from "./routes/admin" -import store from "./routes/store" - -// guaranteed to get dependencies -export default (container, config) => { - const app = Router() - const httpCompressionOptions = compressionOptions(config) - - if (httpCompressionOptions.enabled) { - app.use( - compression({ - filter: shouldCompressResponse, - ...httpCompressionOptions, - }) - ) - } - - admin(app, container, config) - store(app, container, config) - - app.use(errorHandler()) - - return app -} - -// Admin -export * from "./routes/admin/analytics-configs" -export * from "./routes/admin/auth" -export * from "./routes/admin/batch" -export * from "./routes/admin/collections" -export * from "./routes/admin/currencies" -export * from "./routes/admin/customer-groups" -export * from "./routes/admin/customers" -export * from "./routes/admin/discounts" -export * from "./routes/admin/draft-orders" -export * from "./routes/admin/gift-cards" -export * from "./routes/admin/inventory-items" -export * from "./routes/admin/invites" -export * from "./routes/admin/notes" -export * from "./routes/admin/notifications" -export * from "./routes/admin/order-edits" -export * from "./routes/admin/orders" -export * from "./routes/admin/payment-collections" -export * from "./routes/admin/payments" -export * from "./routes/admin/price-lists" -export * from "./routes/admin/product-categories" -export * from "./routes/admin/product-tags" -export * from "./routes/admin/product-types" -export * from "./routes/admin/products" -export * from "./routes/admin/publishable-api-keys" -export * from "./routes/admin/regions" -export * from "./routes/admin/reservations" -export * from "./routes/admin/return-reasons" -export * from "./routes/admin/returns" -export * from "./routes/admin/sales-channels" -export * from "./routes/admin/shipping-options" -export * from "./routes/admin/shipping-profiles" -export * from "./routes/admin/stock-locations" -export * from "./routes/admin/store" -export * from "./routes/admin/swaps" -export * from "./routes/admin/tax-rates" -export * from "./routes/admin/uploads" -export * from "./routes/admin/users" -export * from "./routes/admin/variants" -export * from "./routes/admin/workflows-executions" -// Store -export * from "./routes/store/auth" -export * from "./routes/store/carts" -export * from "./routes/store/collections" -export * from "./routes/store/customers" -export * from "./routes/store/gift-cards" -export * from "./routes/store/order-edits" -export * from "./routes/store/orders" -export * from "./routes/store/payment-collections" -export * from "./routes/store/product-categories" -export * from "./routes/store/product-tags" -export * from "./routes/store/product-types" -export * from "./routes/store/products" -export * from "./routes/store/regions" -export * from "./routes/store/return-reasons" -export * from "./routes/store/returns" -export * from "./routes/store/shipping-options" -export * from "./routes/store/swaps" -export * from "./routes/store/variants" diff --git a/packages/medusa/src/api/middlewares/batch-job/can-access-batch-job.ts b/packages/medusa/src/api/middlewares/batch-job/can-access-batch-job.ts deleted file mode 100644 index a521a8b348..0000000000 --- a/packages/medusa/src/api/middlewares/batch-job/can-access-batch-job.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import BatchJobService from "../../../services/batch-job" - -export async function canAccessBatchJob(req, res, next) { - const id = req.params.id - const batchJobService: BatchJobService = req.scope.resolve("batchJobService") - const batch_job = req.batch_job ?? (await batchJobService.retrieve(id)) - - const userId = req.user.id ?? req.user.userId - if (batch_job.created_by !== userId) { - return next( - new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot access a batch job that does not belong to the logged in user" - ) - ) - } - - next() -} diff --git a/packages/medusa/src/api/middlewares/batch-job/get-requested-batch-job.ts b/packages/medusa/src/api/middlewares/batch-job/get-requested-batch-job.ts deleted file mode 100644 index 2920d66ab7..0000000000 --- a/packages/medusa/src/api/middlewares/batch-job/get-requested-batch-job.ts +++ /dev/null @@ -1,14 +0,0 @@ -import BatchJobService from "../../../services/batch-job" - -export async function getRequestedBatchJob(req, res, next) { - const id = req.params.id - const batchJobService: BatchJobService = req.scope.resolve("batchJobService") - - try { - req.batch_job = await batchJobService.retrieve(id) - } catch (error) { - return next(error) - } - - next() -} diff --git a/packages/medusa/src/api/middlewares/discount/does-condition-belong-to-discount.ts b/packages/medusa/src/api/middlewares/discount/does-condition-belong-to-discount.ts deleted file mode 100644 index fa478a8554..0000000000 --- a/packages/medusa/src/api/middlewares/discount/does-condition-belong-to-discount.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { DiscountConditionService, DiscountService } from "../../../services" - -export async function doesConditionBelongToDiscount(req, res, next) { - try { - const { discount_id, condition_id } = req.params - const conditionService: DiscountConditionService = req.scope.resolve( - "discountConditionService" - ) - const discountService: DiscountService = - req.scope.resolve("discountService") - - const discount = await discountService.retrieve(discount_id, { - select: ["id", "rule_id"], - }) - const condition = await conditionService.retrieve(condition_id, { - select: ["id", "discount_rule_id"], - }) - - if (condition.discount_rule_id !== discount.rule_id) { - return next( - new MedusaError( - MedusaError.Types.INVALID_DATA, - `Condition with id ${condition_id} does not belong to Discount with id ${discount_id}` - ) - ) - } - - next() - } catch (e) { - next(e) - } -} diff --git a/packages/medusa/src/api/middlewares/index.ts b/packages/medusa/src/api/middlewares/index.ts deleted file mode 100644 index f34c92648e..0000000000 --- a/packages/medusa/src/api/middlewares/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { default as authenticate } from "./authenticate" -import { default as authenticateCustomer } from "./authenticate-customer" -import { default as wrap } from "./await-middleware" -import { default as normalizeQuery } from "./normalized-query" -import { default as requireCustomerAuthentication } from "./require-customer-authentication" - -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 errorHandler } from "./error-handler" -export { isFeatureFlagEnabled } from "./feature-flag-enabled" -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" - -/** - * @deprecated you can now import the middlewares directly without passing by the default export - * e.g `import { authenticate } from "@medusajs/medusa" - */ -export default { - authenticate, - authenticateCustomer, - requireCustomerAuthentication, - normalizeQuery, - /** - * @deprecated use `import { wrapHandler } from "@medusajs/medusa"` - */ - wrap, -} diff --git a/packages/medusa/src/api/middlewares/publishable-api-key/extend-request-params.ts b/packages/medusa/src/api/middlewares/publishable-api-key/extend-request-params.ts deleted file mode 100644 index f563cfd17f..0000000000 --- a/packages/medusa/src/api/middlewares/publishable-api-key/extend-request-params.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { NextFunction, Request, Response } from "express" - -import PublishableApiKeyService from "../../../services/publishable-api-key" - -export type PublishableApiKeyScopes = { - sales_channel_ids: string[] -} - -/** - * The middleware, in case that a key is present in the request header, - * attaches ids of resources within the scope of the key to the req object. - * - * @param req - request object - * @param res - response object - * @param next - next middleware call - * - * @throws if sales channel id is passed as a url or body param - * but that id is not in the scope defined by the PK from the header - */ -async function extendRequestParams( - req: Request & { publishableApiKeyScopes: PublishableApiKeyScopes }, - res: Response, - next: NextFunction -) { - const pubKey = req.get("x-publishable-api-key") - - if (pubKey) { - const publishableKeyService: PublishableApiKeyService = req.scope.resolve( - "publishableApiKeyService" - ) - - req.publishableApiKeyScopes = await publishableKeyService.getResourceScopes( - pubKey - ) - } - - next() -} - -export { extendRequestParams } diff --git a/packages/medusa/src/api/middlewares/publishable-api-key/validate-product-sales-channel-association.ts b/packages/medusa/src/api/middlewares/publishable-api-key/validate-product-sales-channel-association.ts deleted file mode 100644 index 6ee0c8daac..0000000000 --- a/packages/medusa/src/api/middlewares/publishable-api-key/validate-product-sales-channel-association.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { NextFunction, Request, Response } from "express" - -import PublishableApiKeyService from "../../../services/publishable-api-key" -import { ProductService } from "../../../services" - -/** - * The middleware check if requested product is assigned to a SC associated with PK in the header. - * - * @param req - request object - * @param res - response object - * @param next - next middleware call - */ -async function validateProductSalesChannelAssociation( - req: Request, - res: Response, - next: NextFunction -) { - const pubKey = req.get("x-publishable-api-key") - - if (pubKey) { - const productService: ProductService = req.scope.resolve("productService") - const publishableKeyService: PublishableApiKeyService = req.scope.resolve( - "publishableApiKeyService" - ) - - const { sales_channel_ids: salesChannelIds } = - await publishableKeyService.getResourceScopes(pubKey) - - let isProductInSalesChannel = false - - try { - isProductInSalesChannel = await productService.isProductInSalesChannels( - req.params.id, - salesChannelIds - ) - } catch (error) { - next(error) - } - - if (salesChannelIds.length && !isProductInSalesChannel) { - req.errors = req.errors ?? [] - req.errors.push( - `Product with id: ${req.params.id} is not associated with sales channels defined by the Publishable API Key passed in the header of the request.` - ) - } - } - - next() -} - -export { validateProductSalesChannelAssociation } diff --git a/packages/medusa/src/api/middlewares/publishable-api-key/validate-sales-channel-param.ts b/packages/medusa/src/api/middlewares/publishable-api-key/validate-sales-channel-param.ts deleted file mode 100644 index e6959d5a4a..0000000000 --- a/packages/medusa/src/api/middlewares/publishable-api-key/validate-sales-channel-param.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { NextFunction, Request, Response } from "express" - -import { PublishableApiKeyScopes } from "./extend-request-params" - -/** - * The middleware will return 400 if sales channel id is passed as an url or body param - * but that id is not in the scope of the PK from the header. - * - * NOTE: must be applied after the `extendRequestParams` middleware - * - * @param req - request object - * @param res - response object - * @param next - next middleware call - */ -async function validateSalesChannelParam( - req: Request & { publishableApiKeyScopes: PublishableApiKeyScopes }, - res: Response, - next: NextFunction -) { - const pubKey = req.get("x-publishable-api-key") - - if (pubKey) { - const scopes = req.publishableApiKeyScopes - let channelIds = req.body.sales_channel_id || req.query.sales_channel_id - - if (!channelIds) { - return next() - } - - channelIds = !Array.isArray(channelIds) ? [channelIds] : channelIds - - if ( - scopes.sales_channel_ids.length && - !channelIds.every((sc) => scopes.sales_channel_ids.includes(sc)) - ) { - req.errors = req.errors ?? [] - req.errors.push( - `Provided sales channel id param: ${channelIds} is not associated with the Publishable API Key passed in the header of the request.` - ) - } - } - - next() -} - -export { validateSalesChannelParam } diff --git a/packages/medusa/src/api/middlewares/publishable-api-key/validate-variant-sales-channel-association.ts b/packages/medusa/src/api/middlewares/publishable-api-key/validate-variant-sales-channel-association.ts deleted file mode 100644 index fe0785ec71..0000000000 --- a/packages/medusa/src/api/middlewares/publishable-api-key/validate-variant-sales-channel-association.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { NextFunction, Request, Response } from "express" - -import PublishableApiKeyService from "../../../services/publishable-api-key" -import { ProductVariantService } from "../../../services" - -/** - * The middleware check if requested product is assigned to a SC associated with PK in the header. - * - * @param req - request object - * @param res - response object - * @param next - next middleware call - */ -async function validateProductVariantSalesChannelAssociation( - req: Request, - res: Response, - next: NextFunction -) { - const pubKey = req.get("x-publishable-api-key") - - if (pubKey) { - const productVariantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - const publishableKeyService: PublishableApiKeyService = req.scope.resolve( - "publishableApiKeyService" - ) - - const { sales_channel_ids: salesChannelIds } = - await publishableKeyService.getResourceScopes(pubKey) - - let isVariantInSalesChannel = false - - try { - isVariantInSalesChannel = - await productVariantService.isVariantInSalesChannels( - req.params.id, - salesChannelIds - ) - } catch (error) { - next(error) - } - - if (salesChannelIds.length && !isVariantInSalesChannel) { - req.errors = req.errors ?? [] - req.errors.push( - `Variant with id: ${req.params.id} is not associated with sales channels defined by the Publishable API Key passed in the header of the request.` - ) - } - } - - next() -} - -export { validateProductVariantSalesChannelAssociation } diff --git a/packages/medusa/src/api/middlewares/validators/product-existence.ts b/packages/medusa/src/api/middlewares/validators/product-existence.ts deleted file mode 100644 index a601b58199..0000000000 --- a/packages/medusa/src/api/middlewares/validators/product-existence.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { NextFunction, Request, Response } from "express" - -type GetProductsRequiredParams = { - id: string -} - -export function validateProductsExist( - getProducts: (req) => T[] -): (req: Request, res: Response, next: NextFunction) => Promise { - return async (req: Request, res: Response, next: NextFunction) => { - const requestedProducts = getProducts(req) - - if (!requestedProducts?.length) { - return next() - } - - const productService = req.scope.resolve("productService") - const requestedProductIds = requestedProducts.map((product) => product.id) - const [productRecords] = await productService.listAndCount({ - id: requestedProductIds, - }) - - const nonExistingProducts = requestedProductIds.filter( - (requestedProductId) => - productRecords.findIndex( - (productRecord) => productRecord.id === requestedProductId - ) === -1 - ) - - if (nonExistingProducts.length) { - req.errors = req.errors ?? [] - req.errors.push(`Products ${nonExistingProducts.join(", ")} do not exist`) - } - - return next() - } -} diff --git a/packages/medusa/src/api/middlewares/validators/sales-channel-existence.ts b/packages/medusa/src/api/middlewares/validators/sales-channel-existence.ts deleted file mode 100644 index 1e4c7cb7f4..0000000000 --- a/packages/medusa/src/api/middlewares/validators/sales-channel-existence.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { NextFunction, Request, Response } from "express" -import { SalesChannelService } from "../../../services" -import { ProductSalesChannelReq } from "../../../types/product" - -export function validateSalesChannelsExist( - getSalesChannels: (req) => ProductSalesChannelReq[] | undefined -): (req: Request, res: Response, next: NextFunction) => Promise { - return async (req: Request, res: Response, next: NextFunction) => { - const salesChannels = getSalesChannels(req) - - if (!salesChannels?.length) { - return next() - } - - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - - const salesChannelIds = salesChannels.map((salesChannel) => salesChannel.id) - const [existingChannels] = await salesChannelService.listAndCount({ - id: salesChannelIds, - }) - - const nonExistingSalesChannels = salesChannelIds.filter( - (scId) => existingChannels.findIndex((sc) => sc.id === scId) === -1 - ) - - if (nonExistingSalesChannels.length) { - req.errors = req.errors ?? [] - req.errors.push( - `Sales Channels ${nonExistingSalesChannels.join(", ")} do not exist` - ) - } - - return next() - } -} diff --git a/packages/medusa/src/api/middlewares/with-default-sales-channel.ts b/packages/medusa/src/api/middlewares/with-default-sales-channel.ts deleted file mode 100644 index 248d3db07b..0000000000 --- a/packages/medusa/src/api/middlewares/with-default-sales-channel.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { NextFunction, Request, Response } from "express" - -import { FlagRouter, MedusaV2Flag } from "@medusajs/utils" -import SalesChannelFeatureFlag from "../../loaders/feature-flags/sales-channels" -import { SalesChannelService } from "../../services" - -/** - * Middleware that includes the default sales channel on the request, if no sales channels present - * @param context Object of options - * @param context.attachChannelAsArray Whether to attach the default sales channel as an array or just a string - */ -export function withDefaultSalesChannel( - { - attachChannelAsArray, - }: { - attachChannelAsArray: boolean - } = { attachChannelAsArray: false } -): (req: Request, res: Response, next: NextFunction) => Promise { - return async (req: Request, _, next: NextFunction) => { - const featureFlagRouter = req.scope.resolve( - "featureFlagRouter" - ) as FlagRouter - - if ( - !featureFlagRouter.isFeatureEnabled(SalesChannelFeatureFlag.key) || - // Do not attach the default SC if the isolate product domain feature flag is enabled - featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key) || - req.query.sales_channel_id?.length || - req.get("x-publishable-api-key") - ) { - return next() - } - - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - - try { - const defaultSalesChannel = await salesChannelService.retrieveDefault() - if (defaultSalesChannel?.id) { - req.query.sales_channel_id = attachChannelAsArray - ? [defaultSalesChannel.id] - : defaultSalesChannel.id - } - } catch { - // noop - } finally { - next() - } - } -} diff --git a/packages/medusa/src/api/routes/admin/analytics-configs/create-analytics-config.ts b/packages/medusa/src/api/routes/admin/analytics-configs/create-analytics-config.ts deleted file mode 100644 index bd0a5d6193..0000000000 --- a/packages/medusa/src/api/routes/admin/analytics-configs/create-analytics-config.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { IsBoolean } from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { AnalyticsConfigService } from "../../../../services" -import { CreateAnalyticsConfig } from "../../../../types/analytics-config" - -// No OAS for this route, for internal use only. -export default async (req: Request, res: Response) => { - const userId = (req.user?.userId ?? req.user?.id)! - const validatedBody = req.validatedBody as CreateAnalyticsConfig - const analyticsConfigService: AnalyticsConfigService = req.scope.resolve( - "analyticsConfigService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const analyticsConfig = await manager.transaction( - async (transactionManager) => { - return await analyticsConfigService - .withTransaction(transactionManager) - .create(userId, validatedBody) - } - ) - - res.status(200).json({ analytics_config: analyticsConfig }) -} - -export class AdminPostAnalyticsConfigReq { - @IsBoolean() - opt_out: boolean - - @IsBoolean() - anonymize?: boolean = false -} diff --git a/packages/medusa/src/api/routes/admin/analytics-configs/delete-analytics-config.ts b/packages/medusa/src/api/routes/admin/analytics-configs/delete-analytics-config.ts deleted file mode 100644 index 56fbcbe0cd..0000000000 --- a/packages/medusa/src/api/routes/admin/analytics-configs/delete-analytics-config.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { AnalyticsConfigService } from "../../../../services" - -// No OAS for this route, for internal use only. -export default async (req: Request, res: Response) => { - const userId = (req.user?.userId ?? req.user?.id)! - - const analyticsConfigService: AnalyticsConfigService = req.scope.resolve( - "analyticsConfigService" - ) - const manager: EntityManager = req.scope.resolve("manager") - - await manager.transaction(async (transactionManager) => { - return await analyticsConfigService - .withTransaction(transactionManager) - .delete(userId) - }) - - res - .status(200) - .json({ user_id: userId, object: "analytics_config", deleted: true }) -} diff --git a/packages/medusa/src/api/routes/admin/analytics-configs/get-analytics-config.ts b/packages/medusa/src/api/routes/admin/analytics-configs/get-analytics-config.ts deleted file mode 100644 index 4ff2450b07..0000000000 --- a/packages/medusa/src/api/routes/admin/analytics-configs/get-analytics-config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Request, Response } from "express" -import { AnalyticsConfigService } from "../../../../services" - -// No OAS for this route, for internal use only. -export default async (req: Request, res: Response): Promise => { - const userId = (req.user?.userId ?? req.user?.id)! - - const analyticsConfigService: AnalyticsConfigService = req.scope.resolve( - "analyticsConfigService" - ) - - const analyticsConfig = await analyticsConfigService.retrieve(userId) - res.status(200).json({ analytics_config: analyticsConfig }) -} diff --git a/packages/medusa/src/api/routes/admin/analytics-configs/index.ts b/packages/medusa/src/api/routes/admin/analytics-configs/index.ts deleted file mode 100644 index 3847efb732..0000000000 --- a/packages/medusa/src/api/routes/admin/analytics-configs/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Router } from "express" -import { AnalyticsConfig } from "../../../.." -import { DeleteResponse } from "../../../../types/common" -import middlewares, { transformBody } from "../../../middlewares" -import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled" -import { AdminPostAnalyticsConfigReq } from "./create-analytics-config" -import { AdminPostAnalyticsConfigAnalyticsConfigReq } from "./update-analytics-config" - -const route = Router() - -export default (app: Router) => { - app.use("/analytics-configs", isFeatureFlagEnabled("analytics"), route) - - route.get("/", middlewares.wrap(require("./get-analytics-config").default)) - - route.post( - "/", - transformBody(AdminPostAnalyticsConfigReq), - middlewares.wrap(require("./create-analytics-config").default) - ) - - route.post( - "/update", - transformBody(AdminPostAnalyticsConfigAnalyticsConfigReq), - middlewares.wrap(require("./update-analytics-config").default) - ) - - route.delete( - "/", - middlewares.wrap(require("./delete-analytics-config").default) - ) - - return app -} - -export type AdminAnalyticsConfigRes = { - analytics_config: AnalyticsConfig -} - -export type AdminAnalyticsConfigDeleteRes = DeleteResponse - -export * from "./create-analytics-config" -export * from "./update-analytics-config" diff --git a/packages/medusa/src/api/routes/admin/analytics-configs/update-analytics-config.ts b/packages/medusa/src/api/routes/admin/analytics-configs/update-analytics-config.ts deleted file mode 100644 index 9e4923fde2..0000000000 --- a/packages/medusa/src/api/routes/admin/analytics-configs/update-analytics-config.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { IsBoolean, IsOptional } from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { AnalyticsConfigService } from "../../../../services" -import { UpdateAnalyticsConfig } from "../../../../types/analytics-config" - -// No OAS for this route, for internal use only. -export default async (req: Request, res: Response) => { - const userId = (req.user?.userId ?? req.user?.id)! - const validatedBody = req.validatedBody as UpdateAnalyticsConfig - const analyticsConfigService: AnalyticsConfigService = req.scope.resolve( - "analyticsConfigService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const analyticsConfig = await manager.transaction( - async (transactionManager) => { - return await analyticsConfigService - .withTransaction(transactionManager) - .update(userId, validatedBody) - } - ) - - res.status(200).json({ analytics_config: analyticsConfig }) -} - -export class AdminPostAnalyticsConfigAnalyticsConfigReq { - @IsOptional() - @IsBoolean() - opt_out?: boolean - - @IsOptional() - @IsBoolean() - anonymize?: boolean -} diff --git a/packages/medusa/src/api/routes/admin/apps/authorize-app.ts b/packages/medusa/src/api/routes/admin/apps/authorize-app.ts deleted file mode 100644 index 6a9aaad963..0000000000 --- a/packages/medusa/src/api/routes/admin/apps/authorize-app.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { IsNotEmpty, IsString } from "class-validator" - -import { OauthService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/apps/authorizations - * operationId: "PostApps" - * summary: "Generate Token for App" - * description: "Use an app's Oauth provider to generate and store a new token for authentication." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostAppsReq" - * x-codegen: - * method: authorize - * x-codeSamples: - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/apps/authorizations' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "application_name": "example", - * "state": "ready", - * "code": "token" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Apps Oauth - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminAppsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminPostAppsReq, req.body) - const oauthService: OauthService = req.scope.resolve("oauthService") - const data = await oauthService.generateToken( - validated.application_name, - validated.code, - validated.state - ) - res.status(200).json({ apps: data }) -} - -/** - * @schema AdminPostAppsReq - * type: object - * required: - * - application_name - * - state - * - code - * properties: - * application_name: - * type: string - * description: Name of the application for to generate the token for. - * state: - * type: string - * description: State of the application. - * code: - * type: string - * description: The code for the generated token. - */ -export class AdminPostAppsReq { - @IsString() - @IsNotEmpty() - application_name: string - - @IsString() - @IsNotEmpty() - state: string - - @IsString() - @IsNotEmpty() - code: string -} diff --git a/packages/medusa/src/api/routes/admin/apps/index.ts b/packages/medusa/src/api/routes/admin/apps/index.ts deleted file mode 100644 index de6d82abcb..0000000000 --- a/packages/medusa/src/api/routes/admin/apps/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Router } from "express" -import { Oauth } from "../../../.." -import middlewares from "../../../middlewares" - -const route = Router() - -export default (app) => { - app.use("/apps", route) - - route.get("/", middlewares.wrap(require("./list").default)) - route.post( - "/authorizations", - middlewares.wrap(require("./authorize-app").default) - ) - - return app -} - -/** - * @schema AdminAppsRes - * type: object - * required: - * - apps - * properties: - * apps: - * description: App details. - * $ref: "#/components/schemas/OAuth" - */ -export type AdminAppsRes = { - apps: Oauth -} - -/** - * @schema AdminAppsListRes - * type: object - * required: - * - apps - * properties: - * apps: - * type: array - * description: An array of app details. - * items: - * $ref: "#/components/schemas/OAuth" - */ -export type AdminAppsListRes = { - apps: Oauth[] -} diff --git a/packages/medusa/src/api/routes/admin/apps/list.ts b/packages/medusa/src/api/routes/admin/apps/list.ts deleted file mode 100644 index e384c035f8..0000000000 --- a/packages/medusa/src/api/routes/admin/apps/list.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { OauthService } from "../../../../services" - -/** - * @oas [get] /admin/apps - * operationId: "GetApps" - * summary: "List Applications" - * description: "Retrieve a list of applications registered in the Medusa backend." - * x-authenticated: true - * x-codegen: - * method: list - * x-codeSamples: - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/apps' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Apps Oauth - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminAppsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const oauthService: OauthService = req.scope.resolve("oauthService") - const data = await oauthService.list({}) - - res.status(200).json({ apps: data }) -} diff --git a/packages/medusa/src/api/routes/admin/auth/create-session.ts b/packages/medusa/src/api/routes/admin/auth/create-session.ts deleted file mode 100644 index f427ceb7d5..0000000000 --- a/packages/medusa/src/api/routes/admin/auth/create-session.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { IsEmail, IsNotEmpty, IsString } from "class-validator" - -import jwt from "jsonwebtoken" -import _ from "lodash" -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import AuthService from "../../../../services/auth" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/auth - * operationId: "PostAuth" - * summary: "User Login" - * x-authenticated: false - * description: "Log a User in and includes the Cookie session in the response header. The cookie session can be used in subsequent requests to authorize the user to perform admin functionalities. - * When using Medusa's JS or Medusa React clients, the cookie is automatically attached to subsequent requests." - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostAuthReq" - * x-codegen: - * method: createSession - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.admin.auth.createSession({ - * email: "user@example.com", - * password: "supersecret" - * }) - * .then(({ user }) => { - * console.log(user.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminLogin } from "medusa-react" - * - * const Login = () => { - * const adminLogin = useAdminLogin() - * // ... - * - * const handleLogin = () => { - * adminLogin.mutate({ - * email: "user@example.com", - * password: "supersecret", - * }, { - * onSuccess: ({ user }) => { - * console.log(user) - * } - * }) - * } - * - * // ... - * } - * - * export default Login - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/auth' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com", - * "password": "supersecret" - * }' - * tags: - * - Auth - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminAuthRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/incorrect_credentials" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminPostAuthReq, req.body) - - const authService: AuthService = req.scope.resolve("authService") - const manager: EntityManager = req.scope.resolve("manager") - const result = await manager.transaction(async (transactionManager) => { - return await authService - .withTransaction(transactionManager) - .authenticate(validated.email, validated.password) - }) - - if (result.success && result.user) { - // Set user id on session, this is stored on the server. - req.session.user_id = result.user.id - - const cleanRes = _.omit(result.user, ["password_hash"]) - - res.json({ user: cleanRes }) - } else { - res.sendStatus(401) - } -} - -/** - * @schema AdminPostAuthReq - * type: object - * description: The admin's credentials used to log in. - * required: - * - email - * - password - * properties: - * email: - * type: string - * description: The user's email. - * format: email - * password: - * type: string - * description: The user's password. - * format: password - */ -export class AdminPostAuthReq { - @IsEmail() - @IsNotEmpty() - email: string - - @IsString() - @IsNotEmpty() - password: string -} diff --git a/packages/medusa/src/api/routes/admin/auth/delete-session.ts b/packages/medusa/src/api/routes/admin/auth/delete-session.ts deleted file mode 100644 index 5141c6c83d..0000000000 --- a/packages/medusa/src/api/routes/admin/auth/delete-session.ts +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @oas [delete] /admin/auth - * operationId: "DeleteAuth" - * summary: "User Logout" - * x-authenticated: true - * description: "Delete the current session for the logged in user. This will only work if you're using Cookie session for authentication. If the API token is still passed in the header, - * the user is still authorized to perform admin functionalities in other API Routes." - * x-codegen: - * method: deleteSession - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in - * medusa.admin.auth.deleteSession() - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteSession } from "medusa-react" - * - * const Logout = () => { - * const adminLogout = useAdminDeleteSession() - * // ... - * - * const handleLogout = () => { - * adminLogout.mutate(undefined, { - * onSuccess: () => { - * // user logged out. - * } - * }) - * } - * - * // ... - * } - * - * export default Logout - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/auth' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Auth - * responses: - * "200": - * description: OK - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - if (req.session.customer_id) { - // if we are also logged in as a customer, persist that session - delete req.session.user_id - } else { - // otherwise, destroy the session - req.session.destroy() - } - - res.sendStatus(200) -} diff --git a/packages/medusa/src/api/routes/admin/auth/get-session.ts b/packages/medusa/src/api/routes/admin/auth/get-session.ts deleted file mode 100644 index 4601a9d096..0000000000 --- a/packages/medusa/src/api/routes/admin/auth/get-session.ts +++ /dev/null @@ -1,84 +0,0 @@ -import UserService from "../../../../services/user" -import _ from "lodash" - -/** - * @oas [get] /admin/auth - * operationId: "GetAuth" - * summary: "Get Current User" - * x-authenticated: true - * description: "Get the currently logged in user's details." - * x-codegen: - * method: getSession - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.auth.getSession() - * .then(({ user }) => { - * console.log(user.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminGetSession } from "medusa-react" - * - * const Profile = () => { - * const { user, isLoading } = useAdminGetSession() - * - * return ( - *
- * {isLoading && Loading...} - * {user && {user.email}} - *
- * ) - * } - * - * export default Profile - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/auth' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Auth - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminAuthRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - try { - const userId = req.user.id || req.user.userId - - const userService: UserService = req.scope.resolve("userService") - const user = await userService.retrieve(userId) - - const cleanRes = _.omit(user, ["password_hash"]) - res.status(200).json({ user: cleanRes }) - } catch (err) { - res.sendStatus(400) - } -} diff --git a/packages/medusa/src/api/routes/admin/auth/get-token.ts b/packages/medusa/src/api/routes/admin/auth/get-token.ts deleted file mode 100644 index dcdf74ecf5..0000000000 --- a/packages/medusa/src/api/routes/admin/auth/get-token.ts +++ /dev/null @@ -1,99 +0,0 @@ -import jwt from "jsonwebtoken" -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import AuthService from "../../../../services/auth" -import { validator } from "../../../../utils/validator" -import { AdminPostAuthReq } from "./create-session" - -/** - * @oas [post] /admin/auth/token - * operationId: "PostToken" - * summary: "User Login (JWT)" - * x-authenticated: false - * description: "After a successful login, a JWT token is returned, which can be used to send authenticated requests." - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostAuthReq" - * x-codegen: - * method: getToken - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.admin.auth.getToken({ - * email: 'user@example.com', - * password: 'supersecret' - * }) - * .then(({ access_token }) => { - * console.log(access_token); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/auth/token' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com", - * "password": "supersecret" - * }' - * tags: - * - Auth - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminBearerAuthRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/incorrect_credentials" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { - projectConfig: { jwt_secret }, - } = req.scope.resolve("configModule") - if (!jwt_secret) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - "Please configure jwt_secret in your environment" - ) - } - const validated = await validator(AdminPostAuthReq, req.body) - - const authService: AuthService = req.scope.resolve("authService") - const manager: EntityManager = req.scope.resolve("manager") - const result = await manager.transaction(async (transactionManager) => { - return await authService - .withTransaction(transactionManager) - .authenticate(validated.email, validated.password) - }) - - if (result.success && result.user) { - // Create jwt token to send back - const token = jwt.sign( - { user_id: result.user.id, domain: "admin" }, - jwt_secret, - { - expiresIn: "24h", - } - ) - - res.json({ access_token: token }) - } else { - res.sendStatus(401) - } -} diff --git a/packages/medusa/src/api/routes/admin/auth/index.ts b/packages/medusa/src/api/routes/admin/auth/index.ts deleted file mode 100644 index cdbb646c14..0000000000 --- a/packages/medusa/src/api/routes/admin/auth/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Router } from "express" -import { User } from "../../../.." -import middlewares from "../../../middlewares" - -const route = Router() - -export default (app) => { - app.use("/auth", route) - - route.get( - "/", - middlewares.authenticate(), - middlewares.wrap(require("./get-session").default) - ) - - route.post("/", middlewares.wrap(require("./create-session").default)) - - route.delete( - "/", - middlewares.authenticate(), - middlewares.wrap(require("./delete-session").default) - ) - - route.post("/token", middlewares.wrap(require("./get-token").default)) - - return app -} - -/** - * @schema AdminAuthRes - * type: object - * description: "The user's details." - * required: - * - user - * properties: - * user: - * description: User details. - * $ref: "#/components/schemas/User" - */ -export type AdminAuthRes = { - user: Omit -} - -/** - * @schema AdminBearerAuthRes - * type: object - * description: "The access token of the user, if they're authenticated successfully." - * properties: - * access_token: - * description: Access token that can be used to send authenticated requests. - * type: string - */ -export type AdminBearerAuthRes = { - access_token: string -} - -export * from "./create-session" -export * from "./delete-session" -export * from "./get-session" -export * from "./get-token" diff --git a/packages/medusa/src/api/routes/admin/batch/cancel-batch-job.ts b/packages/medusa/src/api/routes/admin/batch/cancel-batch-job.ts deleted file mode 100644 index 1a1d546cea..0000000000 --- a/packages/medusa/src/api/routes/admin/batch/cancel-batch-job.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { BatchJobService } from "../../../../services" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/batch-jobs/{id}/cancel - * operationId: "PostBatchJobsBatchJobCancel" - * summary: "Cancel a Batch Job" - * description: "Mark a batch job as canceled. When a batch job is canceled, the processing of the batch job doesn’t automatically stop." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the batch job. - * x-codegen: - * method: cancel - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.batchJobs.cancel(batchJobId) - * .then(({ batch_job }) => { - * console.log(batch_job.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCancelBatchJob } from "medusa-react" - * - * type Props = { - * batchJobId: string - * } - * - * const BatchJob = ({ batchJobId }: Props) => { - * const cancelBatchJob = useAdminCancelBatchJob(batchJobId) - * // ... - * - * const handleCancel = () => { - * cancelBatchJob.mutate(undefined, { - * onSuccess: ({ batch_job }) => { - * console.log(batch_job) - * } - * }) - * } - * - * // ... - * } - * - * export default BatchJob - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/batch-jobs/{id}/cancel' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Batch Jobs - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminBatchJobRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - let batch_job = req.batch_job - - const batchJobService: BatchJobService = req.scope.resolve("batchJobService") - const manager: EntityManager = req.scope.resolve("manager") - batch_job = await manager.transaction(async (transactionManager) => { - return await batchJobService - .withTransaction(transactionManager) - .cancel(batch_job) - }) - - res.json({ batch_job }) -} diff --git a/packages/medusa/src/api/routes/admin/batch/confirm-batch-job.ts b/packages/medusa/src/api/routes/admin/batch/confirm-batch-job.ts deleted file mode 100644 index 138ff04303..0000000000 --- a/packages/medusa/src/api/routes/admin/batch/confirm-batch-job.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { BatchJobService } from "../../../../services" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/batch-jobs/{id}/confirm - * operationId: "PostBatchJobsBatchJobConfirmProcessing" - * summary: "Confirm a Batch Job" - * description: "When a batch job is created, it is not executed automatically if `dry_run` is set to `true`. This API Route confirms that the batch job should be executed." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the batch job. - * x-codegen: - * method: confirm - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.batchJobs.confirm(batchJobId) - * .then(({ batch_job }) => { - * console.log(batch_job.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminConfirmBatchJob } from "medusa-react" - * - * type Props = { - * batchJobId: string - * } - * - * const BatchJob = ({ batchJobId }: Props) => { - * const confirmBatchJob = useAdminConfirmBatchJob(batchJobId) - * // ... - * - * const handleConfirm = () => { - * confirmBatchJob.mutate(undefined, { - * onSuccess: ({ batch_job }) => { - * console.log(batch_job) - * } - * }) - * } - * - * // ... - * } - * - * export default BatchJob - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/batch-jobs/{id}/confirm' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Batch Jobs - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminBatchJobRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - let batch_job = req.batch_job - - const batchJobService: BatchJobService = req.scope.resolve("batchJobService") - const manager: EntityManager = req.scope.resolve("manager") - batch_job = await manager.transaction(async (transactionManager) => { - return await batchJobService - .withTransaction(transactionManager) - .confirm(batch_job) - }) - - res.json({ batch_job }) -} diff --git a/packages/medusa/src/api/routes/admin/batch/create-batch-job.ts b/packages/medusa/src/api/routes/admin/batch/create-batch-job.ts deleted file mode 100644 index 63a5c0b866..0000000000 --- a/packages/medusa/src/api/routes/admin/batch/create-batch-job.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { IsBoolean, IsObject, IsOptional, IsString } from "class-validator" - -import { BatchJob } from "../../../../models" -import BatchJobService from "../../../../services/batch-job" -import { EntityManager } from "typeorm" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/batch-jobs - * operationId: "PostBatchJobs" - * summary: "Create a Batch Job" - * description: "Create a Batch Job to be executed asynchronously in the Medusa backend. If `dry_run` is set to `true`, the batch job will not be executed until the it is confirmed, - * which can be done using the Confirm Batch Job API Route." - * externalDocs: - * description: "How to create a batch job" - * url: "https://docs.medusajs.com/development/batch-jobs/create#create-batch-job" - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostBatchesReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.batchJobs.create({ - * type: 'product-export', - * context: {}, - * dry_run: false - * }).then((({ batch_job }) => { - * console.log(batch_job.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateBatchJob } from "medusa-react" - * - * const CreateBatchJob = () => { - * const createBatchJob = useAdminCreateBatchJob() - * // ... - * - * const handleCreateBatchJob = () => { - * createBatchJob.mutate({ - * type: "publish-products", - * context: {}, - * dry_run: true - * }, { - * onSuccess: ({ batch_job }) => { - * console.log(batch_job) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateBatchJob - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/batch-jobs' \ - * -H 'Content-Type: application/json' \ - * -H 'x-medusa-access-token: {api_token}' \ - * --data-raw '{ - * "type": "product-export", - * "context": { } - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Batch Jobs - * responses: - * 201: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminBatchJobRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminPostBatchesReq, req.body) - - const batchJobService: BatchJobService = req.scope.resolve("batchJobService") - - const userId = req.user.id ?? req.user.userId - - const manager: EntityManager = req.scope.resolve("manager") - const batch_job = await manager.transaction(async (transactionManager) => { - const toCreate = await batchJobService - .withTransaction(transactionManager) - .prepareBatchJobForProcessing(validated, req) - return await batchJobService.withTransaction(transactionManager).create({ - ...toCreate, - created_by: userId, - }) - }) - - res.status(201).json({ batch_job }) -} - -/** - * @schema AdminPostBatchesReq - * type: object - * description: The details of the batch job to create. - * required: - * - type - * - context - * properties: - * type: - * type: string - * description: >- - * The type of batch job to start, which is defined by the `batchType` property of the associated batch job strategy. - * example: product-export - * context: - * type: object - * description: Additional infomration regarding the batch to be used for processing. - * example: - * shape: - * prices: - * - region: null - * currency_code: "eur" - * dynamicImageColumnCount: 4 - * dynamicOptionColumnCount: 2 - * list_config: - * skip: 0 - * take: 50 - * order: - * created_at: "DESC" - * relations: - * - variants - * - variant.prices - * - images - * dry_run: - * type: boolean - * description: Set a batch job in dry_run mode, which would delay executing the batch job until it's confirmed. - * default: false - */ -export class AdminPostBatchesReq { - @IsString() - type: string - - @IsObject() - context: BatchJob["context"] - - @IsBoolean() - @IsOptional() - dry_run = false -} diff --git a/packages/medusa/src/api/routes/admin/batch/get-batch-job.ts b/packages/medusa/src/api/routes/admin/batch/get-batch-job.ts deleted file mode 100644 index 72726bb022..0000000000 --- a/packages/medusa/src/api/routes/admin/batch/get-batch-job.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @oas [get] /admin/batch-jobs/{id} - * operationId: "GetBatchJobsBatchJob" - * summary: "Get a Batch Job" - * description: "Retrieve the details of a batch job." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Batch Job - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.batchJobs.retrieve(batchJobId) - * .then(({ batch_job }) => { - * console.log(batch_job.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminBatchJob } from "medusa-react" - * - * type Props = { - * batchJobId: string - * } - * - * const BatchJob = ({ batchJobId }: Props) => { - * const { batch_job, isLoading } = useAdminBatchJob(batchJobId) - * - * return ( - *
- * {isLoading && Loading...} - * {batch_job && {batch_job.created_by}} - *
- * ) - * } - * - * export default BatchJob - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/batch-jobs/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Batch Jobs - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminBatchJobRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const batch_job = req.batch_job - res.status(200).json({ batch_job: batch_job }) -} diff --git a/packages/medusa/src/api/routes/admin/batch/index.ts b/packages/medusa/src/api/routes/admin/batch/index.ts deleted file mode 100644 index 3eb78dc27e..0000000000 --- a/packages/medusa/src/api/routes/admin/batch/index.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Router } from "express" -import { BatchJob } from "../../../.." -import { PaginatedResponse } from "../../../../types/common" -import middlewares, { - canAccessBatchJob, - getRequestedBatchJob, - transformQuery, -} from "../../../middlewares" -import { AdminGetBatchParams } from "./list-batch-jobs" - -export default (app) => { - const route = Router() - - app.use("/batch-jobs", route) - - route.get( - "/", - transformQuery(AdminGetBatchParams, { - defaultFields: defaultAdminBatchFields, - isList: true, - }), - middlewares.wrap(require("./list-batch-jobs").default) - ) - route.post("/", middlewares.wrap(require("./create-batch-job").default)) - - const batchJobRouter = Router({ mergeParams: true }) - - route.use("/:id", getRequestedBatchJob, canAccessBatchJob, batchJobRouter) - - batchJobRouter.get("/", middlewares.wrap(require("./get-batch-job").default)) - - batchJobRouter.post( - "/confirm", - middlewares.wrap(require("./confirm-batch-job").default) - ) - - batchJobRouter.post( - "/cancel", - middlewares.wrap(require("./cancel-batch-job").default) - ) - - return app -} - -/** - * @schema AdminBatchJobRes - * type: object - * description: "The batch job's details." - * required: - * - batch_job - * properties: - * batch_job: - * description: Batch job details. - * $ref: "#/components/schemas/BatchJob" - */ -export type AdminBatchJobRes = { - batch_job: BatchJob -} - -/** - * @schema AdminBatchJobListRes - * type: object - * required: - * - batch_jobs - * - count - * - offset - * - limit - * properties: - * batch_jobs: - * type: array - * description: An array of batch job details. - * items: - * $ref: "#/components/schemas/BatchJob" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of batch jobs skipped when retrieving the batch jobs. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminBatchJobListRes = PaginatedResponse & { - batch_jobs: BatchJob[] -} - -export const defaultAdminBatchFields = [ - "id", - "type", - "context", - "result", - "created_by", - "created_at", - "updated_at", - "deleted_at", - "confirmed_at", - "pre_processed_at", - "confirmed_at", - "processing_at", - "completed_at", - "canceled_at", - "failed_at", -] - -export * from "./cancel-batch-job" -export * from "./confirm-batch-job" -export * from "./create-batch-job" -export * from "./get-batch-job" -export * from "./list-batch-jobs" diff --git a/packages/medusa/src/api/routes/admin/batch/list-batch-jobs.ts b/packages/medusa/src/api/routes/admin/batch/list-batch-jobs.ts deleted file mode 100644 index e757b482a4..0000000000 --- a/packages/medusa/src/api/routes/admin/batch/list-batch-jobs.ts +++ /dev/null @@ -1,435 +0,0 @@ -import { IsArray, IsNumber, IsOptional, IsString } from "class-validator" -import { Transform, Type } from "class-transformer" - -import BatchJobService from "../../../../services/batch-job" -import { DateComparisonOperator } from "../../../../types/common" -import { IsType } from "../../../../utils/validators/is-type" -import { Request } from "express" -import { pickBy } from "lodash" -import { isDefined } from "medusa-core-utils" - -/** - * @oas [get] /admin/batch-jobs - * operationId: "GetBatchJobs" - * summary: "List Batch Jobs" - * description: "Retrieve a list of Batch Jobs. The batch jobs can be filtered by fields such as `type` or `confirmed_at`. The batch jobs can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) limit=10 {integer} Limit the number of batch jobs returned. - * - (query) offset=0 {integer} The number of batch jobs to skip when retrieving the batch jobs. - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by the batch ID - * schema: - * oneOf: - * - type: string - * description: batch job ID - * - type: array - * description: multiple batch job IDs - * items: - * type: string - * - in: query - * name: type - * style: form - * explode: false - * description: Filter by the batch type - * schema: - * type: array - * items: - * type: string - * - in: query - * name: confirmed_at - * style: form - * explode: false - * description: Filter by a confirmation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: pre_processed_at - * style: form - * explode: false - * description: Filter by a pre-processing date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: completed_at - * style: form - * explode: false - * description: Filter by a completion date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: failed_at - * style: form - * explode: false - * description: Filter by a failure date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: canceled_at - * style: form - * explode: false - * description: Filter by a cancelation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - (query) order {string} A batch-job field to sort-order the retrieved batch jobs by. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned batch jobs. - * - (query) fields {string} Comma-separated fields that should be included in the returned batch jobs. - * - in: query - * name: created_at - * style: form - * explode: false - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * style: form - * explode: false - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: list - * queryParams: AdminGetBatchParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.batchJobs.list() - * .then(({ batch_jobs, limit, offset, count }) => { - * console.log(batch_jobs.length) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminBatchJobs } from "medusa-react" - * - * const BatchJobs = () => { - * const { - * batch_jobs, - * limit, - * offset, - * count, - * isLoading - * } = useAdminBatchJobs() - * - * return ( - *
- * {isLoading && Loading...} - * {batch_jobs?.length && ( - *
    - * {batch_jobs.map((batchJob) => ( - *
  • - * {batchJob.id} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default BatchJobs - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/batch-jobs' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Batch Jobs - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminBatchJobListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res) => { - const batchService: BatchJobService = req.scope.resolve("batchJobService") - - const created_by = req.user?.id || req.user?.userId - - const [jobs, count] = await batchService.listAndCount( - pickBy({ created_by, ...(req.filterableFields ?? {}) }, (val) => - isDefined(val) - ), - req.listConfig - ) - - const { limit, offset } = req.validatedQuery - res.status(200).json({ - batch_jobs: jobs, - count, - offset, - limit, - }) -} - -/** - * Request parameters used to configure and paginate retrieved batch jobs. - */ -export class AdminGetBatchPaginationParams { - /** - * {@inheritDoc FindPaginationParams.limit} - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit = 10 - - /** - * {@inheritDoc FindPaginationParams.offset} - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - offset = 0 - - /** - * {@inheritDoc FindParams.expand} - */ - @IsString() - @IsOptional() - expand?: string - - /** - * {@inheritDoc FindParams.fields} - */ - @IsString() - @IsOptional() - fields?: string - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string -} - -/** - * Parameters used to filter and configure pagination of the retrieved batch jobs. - */ -export class AdminGetBatchParams extends AdminGetBatchPaginationParams { - /** - * IDs to filter batch jobs by. - */ - @IsOptional() - @IsArray() - @IsType([String, [String]]) - id?: string | string[] - - /** - * Types to filter batch jobs by. - */ - @IsArray() - @IsOptional() - type?: string[] - - /** - * Date filters to apply on the batch jobs' `confirmed_at` date. - */ - @IsOptional() - @Transform(({ value }) => { - return value === "null" ? null : value - }) - @Type(() => DateComparisonOperator) - confirmed_at?: DateComparisonOperator | null - - /** - * Date filters to apply on the batch jobs' `pre_processed_at` date. - */ - @IsOptional() - @Transform(({ value }) => { - return value === "null" ? null : value - }) - @Type(() => DateComparisonOperator) - pre_processed_at?: DateComparisonOperator | null - - /** - * Date filters to apply on the batch jobs' `completed_at` date. - */ - @IsOptional() - @Transform(({ value }) => { - return value === "null" ? null : value - }) - @Type(() => DateComparisonOperator) - completed_at?: DateComparisonOperator | null - - /** - * Date filters to apply on the batch jobs' `failed_at` date. - */ - @IsOptional() - @Transform(({ value }) => { - return value === "null" ? null : value - }) - @Type(() => DateComparisonOperator) - failed_at?: DateComparisonOperator | null - - /** - * Date filters to apply on the batch jobs' `canceled_at` date. - */ - @IsOptional() - @Transform(({ value }) => { - return value === "null" ? null : value - }) - @Type(() => DateComparisonOperator) - canceled_at?: DateComparisonOperator | null - - /** - * Date filters to apply on the batch jobs' `created_at` date. - */ - @IsType([DateComparisonOperator]) - @IsOptional() - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the batch jobs' `updated_at` date. - */ - @IsOptional() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator -} diff --git a/packages/medusa/src/api/routes/admin/collections/__tests__/add-products.js b/packages/medusa/src/api/routes/admin/collections/__tests__/add-products.js deleted file mode 100644 index 7e828518f1..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/__tests__/add-products.js +++ /dev/null @@ -1,94 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductCollectionServiceMock } from "../../../../../services/__mocks__/product-collection" - -describe("POST /admin/collections/:id/products/batch", () => { - describe("successfully adds products to collection", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/collections/${IdMap.getId("col")}/products/batch`, - { - payload: { - product_ids: ["prod_1", "prod_2"], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns updated collection with new products", () => { - expect(subject.body.collection.id).toEqual(IdMap.getId("col")) - }) - - it("product collection service update", () => { - expect(ProductCollectionServiceMock.addProducts).toHaveBeenCalledTimes(1) - expect(ProductCollectionServiceMock.addProducts).toHaveBeenCalledWith( - IdMap.getId("col"), - ["prod_1", "prod_2"] - ) - }) - }) - - describe("error on non-existing collection", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/collections/null/products/batch`, - { - payload: { - product_ids: ["prod_1", "prod_2"], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("throws error", () => { - expect(subject.body.message).toBe( - "Product collection with id: null was not found" - ) - }) - }) - - describe("error invalid request", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/collections/${IdMap.getId("col")}/products/batch`, - { - payload: { - product_ids: [], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/collections/__tests__/create-collection.js b/packages/medusa/src/api/routes/admin/collections/__tests__/create-collection.js deleted file mode 100644 index 3ae5b2d752..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/__tests__/create-collection.js +++ /dev/null @@ -1,67 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductCollectionServiceMock } from "../../../../../services/__mocks__/product-collection" - -describe("POST /admin/collections", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/collections", { - payload: { - title: "Suits", - handle: "suits", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns created product collection", () => { - expect(subject.body.collection.id).toEqual(IdMap.getId("col")) - }) - - it("calls production collection service create", () => { - expect(ProductCollectionServiceMock.create).toHaveBeenCalledTimes(1) - expect(ProductCollectionServiceMock.create).toHaveBeenCalledWith({ - title: "Suits", - handle: "suits", - }) - }) - }) - - describe("invalid data returns error details", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/collections", { - payload: { - handle: "no-title-collection", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns error details", () => { - expect(subject.body.type).toEqual("invalid_data") - expect(subject.body.message).toEqual( - "title should not be empty, title must be a string" - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/collections/__tests__/delete-collection.js b/packages/medusa/src/api/routes/admin/collections/__tests__/delete-collection.js deleted file mode 100644 index 9d9ec41034..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/__tests__/delete-collection.js +++ /dev/null @@ -1,42 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductCollectionServiceMock } from "../../../../../services/__mocks__/product-collection" - -describe("DELETE /admin/collections/:id", () => { - describe("successful removes collection", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/collections/${IdMap.getId("collection")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls product collection service delete", () => { - expect(ProductCollectionServiceMock.delete).toHaveBeenCalledTimes(1) - expect(ProductCollectionServiceMock.delete).toHaveBeenCalledWith( - IdMap.getId("collection") - ) - }) - - it("returns delete result", () => { - expect(subject.body).toEqual({ - id: IdMap.getId("collection"), - object: "product-collection", - deleted: true, - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/collections/__tests__/get-collection.js b/packages/medusa/src/api/routes/admin/collections/__tests__/get-collection.js deleted file mode 100644 index 6dc23bf1b6..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/__tests__/get-collection.js +++ /dev/null @@ -1,39 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { defaultAdminCollectionsRelations } from ".." -import { request } from "../../../../../helpers/test-request" -import { ProductCollectionServiceMock } from "../../../../../services/__mocks__/product-collection" - -describe("GET /admin/categories/:id", () => { - describe("get collection by id successfully", () => { - let subject - beforeAll(async () => { - subject = await request( - "GET", - `/admin/collections/${IdMap.getId("col")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls retrieve from product collection service", () => { - expect(ProductCollectionServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(ProductCollectionServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("col"), - {relations: defaultAdminCollectionsRelations} - ) - }) - - it("returns variant decorated", () => { - expect(subject.body.collection.id).toEqual(IdMap.getId("col")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/collections/__tests__/list-collections.js b/packages/medusa/src/api/routes/admin/collections/__tests__/list-collections.js deleted file mode 100644 index d74cc289eb..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/__tests__/list-collections.js +++ /dev/null @@ -1,28 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductCollectionServiceMock } from "../../../../../services/__mocks__/product-collection" - -describe("GET /admin/collections", () => { - describe("successful retrieval", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("GET", `/admin/collections`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls product collection service list", () => { - expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledTimes(1) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/collections/__tests__/remove-products.js b/packages/medusa/src/api/routes/admin/collections/__tests__/remove-products.js deleted file mode 100644 index 9e4e76fb3e..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/__tests__/remove-products.js +++ /dev/null @@ -1,64 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductCollectionServiceMock } from "../../../../../services/__mocks__/product-collection" - -describe("DELETE /admin/collections/:id/products/batch", () => { - describe("successfully removes products from collection", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/collections/${IdMap.getId("col")}/products/batch`, - { - payload: { - product_ids: ["prod_1", "prod_2"], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("product collection service remove products", () => { - expect(ProductCollectionServiceMock.removeProducts).toHaveBeenCalledTimes( - 1 - ) - expect( - ProductCollectionServiceMock.removeProducts - ).toHaveBeenCalledWith(IdMap.getId("col"), ["prod_1", "prod_2"]) - }) - }) - - describe("error on invalid request", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/collections/${IdMap.getId("col")}/products/batch`, - { - payload: { - product_ids: [], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/collections/__tests__/update-collection.js b/packages/medusa/src/api/routes/admin/collections/__tests__/update-collection.js deleted file mode 100644 index 7ed785194b..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/__tests__/update-collection.js +++ /dev/null @@ -1,44 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductCollectionServiceMock } from "../../../../../services/__mocks__/product-collection" - -describe("POST /admin/collections/:id", () => { - describe("successful update", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/collections/${IdMap.getId("col")}`, - { - payload: { - title: "Suits and vests", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns updated product collection", () => { - expect(subject.body.collection.id).toEqual(IdMap.getId("col")) - }) - - it("product collection service update", () => { - expect(ProductCollectionServiceMock.update).toHaveBeenCalledTimes(1) - expect(ProductCollectionServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("col"), - { - title: "Suits and vests", - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/collections/add-products.ts b/packages/medusa/src/api/routes/admin/collections/add-products.ts deleted file mode 100644 index 219efa2666..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/add-products.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { ArrayNotEmpty, IsString } from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" - -import ProductCollectionService from "../../../../services/product-collection" -import { defaultAdminCollectionsRelations } from "./index" - -/** - * @oas [post] /admin/collections/{id}/products/batch - * operationId: "PostProductsToCollection" - * summary: "Add Products to Collection" - * description: "Add products to a product collection." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the product collection. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostProductsToCollectionReq" - * x-codegen: - * method: addProducts - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.addProducts(collectionId, { - * product_ids: [ - * productId1, - * productId2 - * ] - * }) - * .then(({ collection }) => { - * console.log(collection.products) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminAddProductsToCollection } from "medusa-react" - * - * type Props = { - * collectionId: string - * } - * - * const Collection = ({ collectionId }: Props) => { - * const addProducts = useAdminAddProductsToCollection(collectionId) - * // ... - * - * const handleAddProducts = (productIds: string[]) => { - * addProducts.mutate({ - * product_ids: productIds - * }, { - * onSuccess: ({ collection }) => { - * console.log(collection.products) - * } - * }) - * } - * - * // ... - * } - * - * export default Collection - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/collections/{id}/products/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "product_ids": [ - * "prod_01G1G5V2MBA328390B5AXJ610F" - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Collections - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCollectionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - const { validatedBody } = req as { - validatedBody: AdminPostProductsToCollectionReq - } - - const productCollectionService: ProductCollectionService = req.scope.resolve( - "productCollectionService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const updated = await manager.transaction(async (transactionManager) => { - return await productCollectionService - .withTransaction(transactionManager) - .addProducts(id, validatedBody.product_ids) - }) - - const collection = await productCollectionService.retrieve(updated.id, { - relations: defaultAdminCollectionsRelations, - }) - - res.status(200).json({ collection }) -} - -/** - * @schema AdminPostProductsToCollectionReq - * type: object - * description: "The details of the products to add to the collection." - * required: - * - product_ids - * properties: - * product_ids: - * description: "An array of Product IDs to add to the Product Collection." - * type: array - * items: - * description: "The ID of a Product to add to the Product Collection." - * type: string - */ -export class AdminPostProductsToCollectionReq { - @ArrayNotEmpty() - @IsString({ each: true }) - product_ids: string[] -} diff --git a/packages/medusa/src/api/routes/admin/collections/create-collection.ts b/packages/medusa/src/api/routes/admin/collections/create-collection.ts deleted file mode 100644 index ab2d15de29..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/create-collection.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { IsNotEmpty, IsObject, IsOptional, IsString } from "class-validator" -import ProductCollectionService from "../../../../services/product-collection" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { defaultAdminCollectionsRelations } from "." - -/** - * @oas [post] /admin/collections - * operationId: "PostCollections" - * summary: "Create a Collection" - * description: "Create a Product Collection." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostCollectionsReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.create({ - * title: "New Collection" - * }) - * .then(({ collection }) => { - * console.log(collection.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateCollection } from "medusa-react" - * - * const CreateCollection = () => { - * const createCollection = useAdminCreateCollection() - * // ... - * - * const handleCreate = (title: string) => { - * createCollection.mutate({ - * title - * }, { - * onSuccess: ({ collection }) => { - * console.log(collection.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateCollection - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/collections' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "title": "New Collection" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Collections - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCollectionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { validatedBody } = req as { validatedBody: AdminPostCollectionsReq } - - const productCollectionService: ProductCollectionService = req.scope.resolve( - "productCollectionService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const created = await manager.transaction(async (transactionManager) => { - return await productCollectionService - .withTransaction(transactionManager) - .create(validatedBody) - }) - - const collection = await productCollectionService.retrieve(created.id, { - relations: defaultAdminCollectionsRelations, - }) - - res.status(200).json({ collection }) -} - -/** - * @schema AdminPostCollectionsReq - * type: object - * description: The product collection's details. - * required: - * - title - * properties: - * title: - * type: string - * description: The title of the collection. - * handle: - * type: string - * description: An optional handle to be used in slugs. If none is provided, the kebab-case version of the title will be used. - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostCollectionsReq { - @IsString() - @IsNotEmpty() - title: string - - @IsString() - @IsOptional() - handle?: string - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/collections/delete-collection.ts b/packages/medusa/src/api/routes/admin/collections/delete-collection.ts deleted file mode 100644 index 5055ae0140..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/delete-collection.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { Request, Response } from "express" - -import { EntityManager } from "typeorm" -import ProductCollectionService from "../../../../services/product-collection" - -/** - * @oas [delete] /admin/collections/{id} - * operationId: "DeleteCollectionsCollection" - * summary: "Delete a Collection" - * description: "Delete a Product Collection. This does not delete associated products." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Collection. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.delete(collectionId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteCollection } from "medusa-react" - * - * type Props = { - * collectionId: string - * } - * - * const Collection = ({ collectionId }: Props) => { - * const deleteCollection = useAdminDeleteCollection(collectionId) - * // ... - * - * const handleDelete = (title: string) => { - * deleteCollection.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Collection - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/collections/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Collections - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCollectionsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const productCollectionService: ProductCollectionService = req.scope.resolve( - "productCollectionService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await productCollectionService - .withTransaction(transactionManager) - .delete(id) - }) - - res.json({ - id, - object: "product-collection", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/collections/get-collection.ts b/packages/medusa/src/api/routes/admin/collections/get-collection.ts deleted file mode 100644 index f547935f8f..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/get-collection.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Request, Response } from "express" - -import ProductCollectionService from "../../../../services/product-collection" -import { defaultAdminCollectionsRelations } from "." - -/** - * @oas [get] /admin/collections/{id} - * operationId: "GetCollectionsCollection" - * summary: "Get a Collection" - * description: "Retrieve a Product Collection by its ID. The products associated with it are expanded and returned as well." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Product Collection - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.retrieve(collectionId) - * .then(({ collection }) => { - * console.log(collection.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCollection } from "medusa-react" - * - * type Props = { - * collectionId: string - * } - * - * const Collection = ({ collectionId }: Props) => { - * const { collection, isLoading } = useAdminCollection(collectionId) - * - * return ( - *
- * {isLoading && Loading...} - * {collection && {collection.title}} - *
- * ) - * } - * - * export default Collection - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/collections/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Collections - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCollectionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const productCollectionService: ProductCollectionService = req.scope.resolve( - "productCollectionService" - ) - - const collection = await productCollectionService.retrieve(id, { - relations: defaultAdminCollectionsRelations, - }) - res.status(200).json({ collection }) -} diff --git a/packages/medusa/src/api/routes/admin/collections/index.ts b/packages/medusa/src/api/routes/admin/collections/index.ts deleted file mode 100644 index 7e280f57b1..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/index.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { Router } from "express" -import "reflect-metadata" -import { ProductCollection } from "../../../.." -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" -import { AdminGetCollectionsParams } from "./list-collections" -import { AdminPostCollectionsReq } from "./create-collection" -import { AdminPostCollectionsCollectionReq } from "./update-collection" -import { AdminPostProductsToCollectionReq } from "./add-products" -import { AdminDeleteProductsFromCollectionReq } from "./remove-products" - -export default (app) => { - const route = Router() - app.use("/collections", route) - - route.post( - "/", - transformBody(AdminPostCollectionsReq), - middlewares.wrap(require("./create-collection").default) - ) - route.get( - "/", - transformQuery(AdminGetCollectionsParams, { - defaultRelations: defaultAdminCollectionsRelations, - defaultFields: defaultAdminCollectionsFields, - isList: true, - }), - middlewares.wrap(require("./list-collections").default) - ) - - const collectionRouter = Router({ mergeParams: true }) - route.use("/:id", collectionRouter) - collectionRouter.post( - "/", - transformBody(AdminPostCollectionsCollectionReq), - middlewares.wrap(require("./update-collection").default) - ) - collectionRouter.get( - "/", - middlewares.wrap(require("./get-collection").default) - ) - collectionRouter.delete( - "/", - middlewares.wrap(require("./delete-collection").default) - ) - collectionRouter.post( - "/products/batch", - transformBody(AdminPostProductsToCollectionReq), - middlewares.wrap(require("./add-products").default) - ) - collectionRouter.delete( - "/products/batch", - transformBody(AdminDeleteProductsFromCollectionReq), - middlewares.wrap(require("./remove-products").default) - ) - - return app -} - -export const defaultAdminCollectionsFields = [ - "id", - "title", - "handle", - "created_at", - "updated_at", -] -export const defaultAdminCollectionsRelations = ["products.profiles"] - -/** - * @schema AdminCollectionsListRes - * type: object - * required: - * - collections - * - count - * - offset - * - limit - * properties: - * collections: - * type: array - * description: an array of collection details - * items: - * $ref: "#/components/schemas/ProductCollection" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of product collections skipped when retrieving the product collections. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminCollectionsListRes = PaginatedResponse & { - collections: ProductCollection[] -} - -/** - * @schema AdminCollectionsDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Collection - * object: - * type: string - * description: The type of the object that was deleted. - * default: product-collection - * deleted: - * type: boolean - * description: Whether the collection was deleted successfully or not. - * default: true - */ -export type AdminCollectionsDeleteRes = DeleteResponse - -/** - * @schema AdminDeleteProductsFromCollectionRes - * type: object - * description: "Deletion operation details" - * required: - * - id - * - object - * - removed_products - * properties: - * id: - * type: string - * description: "The ID of the collection" - * object: - * type: string - * description: "The type of object the removal was executed on" - * default: product-collection - * removed_products: - * description: "The IDs of the products removed from the collection" - * type: array - * items: - * description: "The ID of the Product removed from the Product Collection." - * type: string - */ -export type AdminDeleteProductsFromCollectionRes = { - id: string - object: string - removed_products: string[] -} - -/** - * @schema AdminCollectionsRes - * type: object - * description: The collection's details. - * x-expanded-relations: - * field: collection - * relations: - * - products - * required: - * - collection - * properties: - * collection: - * description: "Product Collection details." - * $ref: "#/components/schemas/ProductCollection" - */ -export type AdminCollectionsRes = { - collection: ProductCollection -} - -export * from "./add-products" -export * from "./create-collection" -export * from "./delete-collection" -export * from "./get-collection" -export * from "./list-collections" -export * from "./remove-products" -export * from "./update-collection" diff --git a/packages/medusa/src/api/routes/admin/collections/list-collections.ts b/packages/medusa/src/api/routes/admin/collections/list-collections.ts deleted file mode 100644 index b6b461b73d..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/list-collections.ts +++ /dev/null @@ -1,265 +0,0 @@ -import { IsNumber, IsOptional, IsString, ValidateNested } from "class-validator" -import { Request, Response } from "express" - -import { Type } from "class-transformer" -import ProductCollectionService from "../../../../services/product-collection" -import { DateComparisonOperator } from "../../../../types/common" - -/** - * @oas [get] /admin/collections - * operationId: "GetCollections" - * summary: "List Collections" - * description: "Retrieve a list of Product Collection. The product collections can be filtered by fields such as `handle` or `title`. The collections can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) limit=10 {integer} The number of collections to return. - * - (query) offset=0 {integer} The number of collections to skip when retrieving the collections. - * - (query) title {string} Filter collections by their title. - * - (query) handle {string} Filter collections by their handle. - * - (query) q {string} a term to search collections by their title or handle. - * - (query) order {string} A field to sort-order the retrieved collections by. - * - (query) discount_condition_id {string} Filter collections by a discount condition ID associated with them. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: deleted_at - * description: Filter by a deletion date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: list - * queryParams: AdminGetCollectionsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.list() - * .then(({ collections, limit, offset, count }) => { - * console.log(collections.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCollections } from "medusa-react" - * - * const Collections = () => { - * const { collections, isLoading } = useAdminCollections() - * - * return ( - *
- * {isLoading && Loading...} - * {collections && !collections.length && - * No Product Collections - * } - * {collections && collections.length > 0 && ( - *
    - * {collections.map((collection) => ( - *
  • {collection.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Collections - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/collections' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Collections - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCollectionsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const productCollectionService: ProductCollectionService = req.scope.resolve( - "productCollectionService" - ) - - const { filterableFields, listConfig } = req - const { skip, take } = listConfig - - const [collections, count] = await productCollectionService.listAndCount( - filterableFields, - listConfig - ) - - res.status(200).json({ - collections, - count, - offset: skip, - limit: take, - }) -} - -/** - * Parameters used to configure the pagination of the retrieved product collections. - */ -export class AdminGetCollectionsPaginationParams { - /** - * {@inheritDoc FindPaginationParams.limit} - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit = 10 - - /** - * {@inheritDoc FindPaginationParams.offset} - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - offset = 0 -} - -/** - * Parameters used to filter and configure the pagination of the retrieved product collections. - */ -// eslint-disable-next-line max-len -export class AdminGetCollectionsParams extends AdminGetCollectionsPaginationParams { - /** - * Title to filter product collections by. - */ - @IsOptional() - @IsString() - title?: string - - /** - * Handle to filter product collections by. - */ - @IsOptional() - @IsString() - handle?: string - - /** - * Date filters to apply on the product collections' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the product collections' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on the product collections' `deleted_at` date. - */ - @ValidateNested() - @IsOptional() - @Type(() => DateComparisonOperator) - deleted_at?: DateComparisonOperator - - /** - * Term to search product collections by their title and handle. - */ - @IsString() - @IsOptional() - q?: string - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string - - /** - * Filter product collections by their associated discount condition's ID. - */ - @IsString() - @IsOptional() - discount_condition_id?: string -} diff --git a/packages/medusa/src/api/routes/admin/collections/remove-products.ts b/packages/medusa/src/api/routes/admin/collections/remove-products.ts deleted file mode 100644 index f9fbba8311..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/remove-products.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { ArrayNotEmpty, IsString } from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" - -import ProductCollectionService from "../../../../services/product-collection" - -/** - * @oas [delete] /admin/collections/{id}/products/batch - * operationId: "DeleteProductsFromCollection" - * summary: "Remove Products from Collection" - * description: "Remove a list of products from a collection. This would not delete the product, only the association between the product and the collection." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Product Collection. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteProductsFromCollectionReq" - * x-codegen: - * method: removeProducts - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.removeProducts(collectionId, { - * product_ids: [ - * productId1, - * productId2 - * ] - * }) - * .then(({ id, object, removed_products }) => { - * console.log(removed_products) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminRemoveProductsFromCollection } from "medusa-react" - * - * type Props = { - * collectionId: string - * } - * - * const Collection = ({ collectionId }: Props) => { - * const removeProducts = useAdminRemoveProductsFromCollection(collectionId) - * // ... - * - * const handleRemoveProducts = (productIds: string[]) => { - * removeProducts.mutate({ - * product_ids: productIds - * }, { - * onSuccess: ({ id, object, removed_products }) => { - * console.log(removed_products) - * } - * }) - * } - * - * // ... - * } - * - * export default Collection - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/collections/{id}/products/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "product_ids": [ - * "prod_01G1G5V2MBA328390B5AXJ610F" - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Collections - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteProductsFromCollectionRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - const { validatedBody } = req as { - validatedBody: AdminDeleteProductsFromCollectionReq - } - - const productCollectionService: ProductCollectionService = req.scope.resolve( - "productCollectionService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await productCollectionService - .withTransaction(transactionManager) - .removeProducts(id, validatedBody.product_ids) - }) - - res.json({ - id, - object: "product-collection", - removed_products: validatedBody.product_ids, - }) -} - -/** - * @schema AdminDeleteProductsFromCollectionReq - * type: object - * description: "The details of the products to remove from the collection." - * required: - * - product_ids - * properties: - * product_ids: - * description: "An array of Product IDs to remove from the Product Collection." - * type: array - * items: - * description: "The ID of a Product to add to the Product Collection." - * type: string - */ -export class AdminDeleteProductsFromCollectionReq { - @ArrayNotEmpty() - @IsString({ each: true }) - product_ids: string[] -} diff --git a/packages/medusa/src/api/routes/admin/collections/update-collection.ts b/packages/medusa/src/api/routes/admin/collections/update-collection.ts deleted file mode 100644 index 2730345ad8..0000000000 --- a/packages/medusa/src/api/routes/admin/collections/update-collection.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { IsObject, IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import ProductCollectionService from "../../../../services/product-collection" -import { defaultAdminCollectionsRelations } from "." - -/** - * @oas [post] /admin/collections/{id} - * operationId: "PostCollectionsCollection" - * summary: "Update a Collection" - * description: "Update a Product Collection's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Collection. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostCollectionsCollectionReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.collections.update(collectionId, { - * title: "New Collection" - * }) - * .then(({ collection }) => { - * console.log(collection.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateCollection } from "medusa-react" - * - * type Props = { - * collectionId: string - * } - * - * const Collection = ({ collectionId }: Props) => { - * const updateCollection = useAdminUpdateCollection(collectionId) - * // ... - * - * const handleUpdate = (title: string) => { - * updateCollection.mutate({ - * title - * }, { - * onSuccess: ({ collection }) => { - * console.log(collection.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Collection - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/collections/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "title": "New Collection" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Collections - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCollectionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - const { validatedBody } = req as { - validatedBody: AdminPostCollectionsCollectionReq - } - - const productCollectionService: ProductCollectionService = req.scope.resolve( - "productCollectionService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const updated = await manager.transaction(async (transactionManager) => { - return await productCollectionService - .withTransaction(transactionManager) - .update(id, validatedBody) - }) - - const collection = await productCollectionService.retrieve(updated.id, { - relations: defaultAdminCollectionsRelations, - }) - - res.status(200).json({ collection }) -} - -/** - * @schema AdminPostCollectionsCollectionReq - * type: object - * description: The product collection's details to update. - * properties: - * title: - * type: string - * description: The title of the collection. - * handle: - * type: string - * description: An optional handle to be used in slugs. If none is provided, the kebab-case version of the title will be used. - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostCollectionsCollectionReq { - @IsString() - @IsOptional() - title?: string - - @IsString() - @IsOptional() - handle?: string - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/currencies/__tests__/list-currencies.ts b/packages/medusa/src/api/routes/admin/currencies/__tests__/list-currencies.ts deleted file mode 100644 index 637594c38a..0000000000 --- a/packages/medusa/src/api/routes/admin/currencies/__tests__/list-currencies.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { currency, CurrencyServiceMock } from "../../../../../services/__mocks__/currency"; -import TaxInclusivePricingFeatureFlag from "../../../../../loaders/feature-flags/tax-inclusive-pricing"; - -describe("GET /admin/currencies/", () => { - describe("successfully list the currency", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/admin/currencies`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - flags: [TaxInclusivePricingFeatureFlag], - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls the listAndCount method from the currency service", () => { - expect(CurrencyServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(CurrencyServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - { - order: {}, - select: undefined, - relations: [], - skip: 0, - take: 20 - } - ) - }) - - it("returns the expected currencies", () => { - expect(subject.body).toEqual({ - currencies: [currency], - offset: 0, - limit: 20, - count: 1, - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/currencies/__tests__/update-currency.ts b/packages/medusa/src/api/routes/admin/currencies/__tests__/update-currency.ts deleted file mode 100644 index cd8217ca50..0000000000 --- a/packages/medusa/src/api/routes/admin/currencies/__tests__/update-currency.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { currency, CurrencyServiceMock } from "../../../../../services/__mocks__/currency"; -import TaxInclusivePricingFeatureFlag from "../../../../../loaders/feature-flags/tax-inclusive-pricing"; - -describe("POST /admin/currencies/:code", () => { - let subject - const code = IdMap.getId("currency-1") - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/currencies/${code}`, - { - payload: { - includes_tax: true, - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - flags: [TaxInclusivePricingFeatureFlag], - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns updated currency", () => { - expect(subject.body.currency).toEqual({ - ...currency, - includes_tax: true, - }) - }) - - it("calls service update", () => { - expect(CurrencyServiceMock.update).toHaveBeenCalledTimes(1) - expect(CurrencyServiceMock.update).toHaveBeenCalledWith( - code, - { - includes_tax: true, - } - ) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/currencies/index.ts b/packages/medusa/src/api/routes/admin/currencies/index.ts deleted file mode 100644 index dbf37b3c55..0000000000 --- a/packages/medusa/src/api/routes/admin/currencies/index.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Router } from "express" -import { Currency } from "../../../.." -import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" -import { PaginatedResponse } from "../../../../types/common" -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" -import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled" -import { AdminGetCurrenciesParams } from "./list-currencies" -import { AdminPostCurrenciesCurrencyReq } from "./update-currency" - -export default (app) => { - const route = Router() - app.use("/currencies", route) - - route.get( - "/", - transformQuery(AdminGetCurrenciesParams, { - isList: true, - }), - middlewares.wrap(require("./list-currencies").default) - ) - - route.post( - "/:code", - transformBody(AdminPostCurrenciesCurrencyReq), - isFeatureFlagEnabled(TaxInclusivePricingFeatureFlag.key), - middlewares.wrap(require("./update-currency").default) - ) - - return app -} - -/** - * @schema AdminCurrenciesListRes - * type: object - * description: List of currencies with pagination fields. - * required: - * - currencies - * - count - * - offset - * - limit - * properties: - * currencies: - * type: array - * description: An array of currency details. - * items: - * $ref: "#/components/schemas/Currency" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of currencies skipped when retrieving the currencies. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminCurrenciesListRes = PaginatedResponse & { - currencies: Currency[] -} - -/** - * @schema AdminCurrenciesRes - * type: object - * description: A currency's details. - * required: - * - currency - * properties: - * currency: - * description: Currency details. - * $ref: "#/components/schemas/Currency" - */ -export type AdminCurrenciesRes = { - currency: Currency -} - -export * from "./list-currencies" -export * from "./update-currency" diff --git a/packages/medusa/src/api/routes/admin/currencies/list-currencies.ts b/packages/medusa/src/api/routes/admin/currencies/list-currencies.ts deleted file mode 100644 index 0a605a1a24..0000000000 --- a/packages/medusa/src/api/routes/admin/currencies/list-currencies.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { IsBoolean, IsOptional, IsString } from "class-validator" -import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" -import { Currency } from "../../../../models" -import { CurrencyService } from "../../../../services" -import { FindPaginationParams } from "../../../../types/common" -import { ExtendedRequest } from "../../../../types/global" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" - -/** - * @oas [get] /admin/currencies - * operationId: "GetCurrencies" - * summary: "List Currency" - * description: "Retrieve a list of currencies. The currencies can be filtered by fields such as `code`. The currencies can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) code {string} filter by currency code. - * - in: query - * name: includes_tax - * description: filter currencies by whether they include taxes or not. - * schema: - * type: boolean - * x-featureFlag: "tax_inclusive_pricing" - * - (query) order {string} A field to sort order the retrieved currencies by. - * - (query) q {string} Term used to search currencies' name and code. - * - (query) offset=0 {number} The number of currencies to skip when retrieving the currencies. - * - (query) limit=20 {number} The number of currencies to return. - * x-codegen: - * method: list - * queryParams: AdminGetCurrenciesParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.currencies.list() - * .then(({ currencies, count, offset, limit }) => { - * console.log(currencies.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCurrencies } from "medusa-react" - * - * const Currencies = () => { - * const { currencies, isLoading } = useAdminCurrencies() - * - * return ( - *
- * {isLoading && Loading...} - * {currencies && !currencies.length && ( - * No Currencies - * )} - * {currencies && currencies.length > 0 && ( - *
    - * {currencies.map((currency) => ( - *
  • {currency.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Currencies - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/currencies' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Currencies - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCurrenciesListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: ExtendedRequest, res) => { - const currencyService: CurrencyService = req.scope.resolve("currencyService") - - const { skip, take } = req.listConfig - - req.listConfig.select = undefined - if (req.listConfig.order && req.listConfig.order["created_at"]) { - delete req.listConfig.order["created_at"] - } - const [currencies, count] = await currencyService.listAndCount( - req.filterableFields, - req.listConfig - ) - - res.json({ - currencies, - count, - offset: skip, - limit: take, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved currencies. - */ -export class AdminGetCurrenciesParams extends FindPaginationParams { - /** - * Code to filter currencies by. - */ - @IsString() - @IsOptional() - code?: string - - /** - * Search parameter for currencies. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Filter currencies by whether they include tax. - * - * @featureFlag tax_inclusive_pricing - */ - @FeatureFlagDecorators(TaxInclusivePricingFeatureFlag.key, [ - IsBoolean(), - IsOptional(), - ]) - includes_tax?: boolean - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - * By default, the returned currencies will be sorted by their `created_at` field. - */ - @IsString() - @IsOptional() - order?: string -} diff --git a/packages/medusa/src/api/routes/admin/currencies/update-currency.ts b/packages/medusa/src/api/routes/admin/currencies/update-currency.ts deleted file mode 100644 index 6d446841bc..0000000000 --- a/packages/medusa/src/api/routes/admin/currencies/update-currency.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { IsBoolean, IsOptional } from "class-validator" -import { Currency } from "../../../../models" -import { ExtendedRequest } from "../../../../types/global" -import { CurrencyService } from "../../../../services" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" -import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/currencies/{code} - * operationId: "PostCurrenciesCurrency" - * summary: "Update a Currency" - * description: "Update a Currency's details." - * x-authenticated: true - * parameters: - * - (path) code=* {string} The code of the Currency. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostCurrenciesCurrencyReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.currencies.update(code, { - * includes_tax: true - * }) - * .then(({ currency }) => { - * console.log(currency.code); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateCurrency } from "medusa-react" - * - * type Props = { - * currencyCode: string - * } - * - * const Currency = ({ currencyCode }: Props) => { - * const updateCurrency = useAdminUpdateCurrency(currencyCode) - * // ... - * - * const handleUpdate = (includes_tax: boolean) => { - * updateCurrency.mutate({ - * includes_tax, - * }, { - * onSuccess: ({ currency }) => { - * console.log(currency) - * } - * }) - * } - * - * // ... - * } - * - * export default Currency - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/currencies/{code}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "includes_tax": true - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Currencies - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCurrenciesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: ExtendedRequest, res) => { - const code = req.params.code as string - const data = req.validatedBody as AdminPostCurrenciesCurrencyReq - const currencyService: CurrencyService = req.scope.resolve("currencyService") - const manager: EntityManager = req.scope.resolve("manager") - - const currency = await manager.transaction(async (transactionManager) => { - return await currencyService - .withTransaction(transactionManager) - .update(code, data) - }) - - res.json({ currency }) -} - -/** - * @schema AdminPostCurrenciesCurrencyReq - * type: object - * description: "The details to update in the currency" - * properties: - * includes_tax: - * type: boolean - * x-featureFlag: "tax_inclusive_pricing" - * description: "Tax included in prices of currency." - */ -export class AdminPostCurrenciesCurrencyReq { - @FeatureFlagDecorators(TaxInclusivePricingFeatureFlag.key, [ - IsOptional(), - IsBoolean(), - ]) - includes_tax?: boolean -} diff --git a/packages/medusa/src/api/routes/admin/customer-groups/__tests__/create-customer-group.ts b/packages/medusa/src/api/routes/admin/customer-groups/__tests__/create-customer-group.ts deleted file mode 100644 index 2b239d1cee..0000000000 --- a/packages/medusa/src/api/routes/admin/customer-groups/__tests__/create-customer-group.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { CustomerGroupServiceMock } from "../../../../../services/__mocks__/customer-group" - -describe("POST /customer-groups", () => { - describe("successfully calls create customer group", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/admin/customer-groups`, { - payload: { - name: "test group", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls CustomerGroupService create", () => { - expect(CustomerGroupServiceMock.create).toHaveBeenCalledTimes(1) - expect(CustomerGroupServiceMock.create).toHaveBeenCalledWith({ - name: "test group", - }) - }) - }) - - describe("fails if no name is provided for the group ", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/admin/customer-groups`, { - payload: {}, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns descriptive error that name is missing", () => { - expect(subject.body.type).toEqual("invalid_data") - expect(subject.body.message).toEqual("name must be a string") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/customer-groups/__tests__/get-customer-group.ts b/packages/medusa/src/api/routes/admin/customer-groups/__tests__/get-customer-group.ts deleted file mode 100644 index 9fd1ecd201..0000000000 --- a/packages/medusa/src/api/routes/admin/customer-groups/__tests__/get-customer-group.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { CustomerGroupServiceMock } from "../../../../../services/__mocks__/customer-group" - -describe("GET /customer-groups", () => { - let subject - const id = "123" - - beforeAll(async () => { - subject = await request( - "GET", - `/admin/customer-groups/${id}?expand=customers`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls CustomerGroupService get", () => { - expect(CustomerGroupServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(CustomerGroupServiceMock.retrieve).toHaveBeenCalledWith(id, { - relations: ["customers"], - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/customer-groups/add-customers-batch.ts b/packages/medusa/src/api/routes/admin/customer-groups/add-customers-batch.ts deleted file mode 100644 index 80db05c8f6..0000000000 --- a/packages/medusa/src/api/routes/admin/customer-groups/add-customers-batch.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { Request, Response } from "express" - -import { CustomerGroupService } from "../../../../services" -import { CustomerGroupsBatchCustomer } from "../../../../types/customer-groups" -import { EntityManager } from "typeorm" -import { Type } from "class-transformer" -import { ValidateNested } from "class-validator" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/customer-groups/{id}/customers/batch - * operationId: "PostCustomerGroupsGroupCustomersBatch" - * summary: "Add Customers to Group" - * description: "Add a list of customers to a customer group." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the customer group. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostCustomerGroupsGroupCustomersBatchReq" - * x-codegen: - * method: addCustomers - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.addCustomers(customerGroupId, { - * customer_ids: [ - * { - * id: customerId - * } - * ] - * }) - * .then(({ customer_group }) => { - * console.log(customer_group.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminAddCustomersToCustomerGroup, - * } from "medusa-react" - * - * type Props = { - * customerGroupId: string - * } - * - * const CustomerGroup = ({ customerGroupId }: Props) => { - * const addCustomers = useAdminAddCustomersToCustomerGroup( - * customerGroupId - * ) - * // ... - * - * const handleAddCustomers= (customerId: string) => { - * addCustomers.mutate({ - * customer_ids: [ - * { - * id: customerId, - * }, - * ], - * }) - * } - * - * // ... - * } - * - * export default CustomerGroup - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/customer-groups/{id}/customers/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "customer_ids": [ - * { - * "id": "cus_01G2Q4BS9GAHDBMDEN4ZQZCJB2" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customer Groups - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCustomerGroupsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const { id } = req.params - const validated = await validator( - AdminPostCustomerGroupsGroupCustomersBatchReq, - req.body - ) - - const customerGroupService: CustomerGroupService = req.scope.resolve( - "customerGroupService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const customer_group = await manager.transaction( - async (transactionManager) => { - return await customerGroupService - .withTransaction(transactionManager) - .addCustomers( - id, - validated.customer_ids.map(({ id }) => id) - ) - } - ) - - res.status(200).json({ customer_group }) -} - -/** - * @schema AdminPostCustomerGroupsGroupCustomersBatchReq - * type: object - * description: "The customers to add to the customer group." - * required: - * - customer_ids - * properties: - * customer_ids: - * description: "The ids of the customers to add" - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * description: ID of the customer - * type: string - */ -export class AdminPostCustomerGroupsGroupCustomersBatchReq { - @ValidateNested({ each: true }) - @Type(() => CustomerGroupsBatchCustomer) - customer_ids: CustomerGroupsBatchCustomer[] -} diff --git a/packages/medusa/src/api/routes/admin/customer-groups/create-customer-group.ts b/packages/medusa/src/api/routes/admin/customer-groups/create-customer-group.ts deleted file mode 100644 index d63af297f8..0000000000 --- a/packages/medusa/src/api/routes/admin/customer-groups/create-customer-group.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { IsObject, IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" - -import { CustomerGroupService } from "../../../../services" -import { EntityManager } from "typeorm" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/customer-groups - * operationId: "PostCustomerGroups" - * summary: "Create a Customer Group" - * description: "Create a Customer Group." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostCustomerGroupsReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.create({ - * name: "VIP" - * }) - * .then(({ customer_group }) => { - * console.log(customer_group.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateCustomerGroup } from "medusa-react" - * - * const CreateCustomerGroup = () => { - * const createCustomerGroup = useAdminCreateCustomerGroup() - * // ... - * - * const handleCreate = (name: string) => { - * createCustomerGroup.mutate({ - * name, - * }) - * } - * - * // ... - * } - * - * export default CreateCustomerGroup - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/customer-groups' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "VIP" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customer Groups - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCustomerGroupsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const validated = await validator(AdminPostCustomerGroupsReq, req.body) - - const customerGroupService: CustomerGroupService = req.scope.resolve( - "customerGroupService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const customerGroup = await manager.transaction( - async (transactionManager) => { - return await customerGroupService - .withTransaction(transactionManager) - .create(validated) - } - ) - - res.status(200).json({ customer_group: customerGroup }) -} - -/** - * @schema AdminPostCustomerGroupsReq - * type: object - * description: "The details of the customer group to create." - * required: - * - name - * properties: - * name: - * type: string - * description: Name of the customer group - * metadata: - * type: object - * description: Metadata of the customer group. - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostCustomerGroupsReq { - @IsString() - name: string - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/customer-groups/delete-customer-group.ts b/packages/medusa/src/api/routes/admin/customer-groups/delete-customer-group.ts deleted file mode 100644 index 9af8f0d5ed..0000000000 --- a/packages/medusa/src/api/routes/admin/customer-groups/delete-customer-group.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Request, Response } from "express" - -import { CustomerGroupService } from "../../../../services" -import { EntityManager } from "typeorm" - -/** - * @oas [delete] /admin/customer-groups/{id} - * operationId: "DeleteCustomerGroupsCustomerGroup" - * summary: "Delete a Customer Group" - * description: "Delete a customer group. This doesn't delete the customers associated with the customer group." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Customer Group - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.delete(customerGroupId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteCustomerGroup } from "medusa-react" - * - * type Props = { - * customerGroupId: string - * } - * - * const CustomerGroup = ({ customerGroupId }: Props) => { - * const deleteCustomerGroup = useAdminDeleteCustomerGroup( - * customerGroupId - * ) - * // ... - * - * const handleDeleteCustomerGroup = () => { - * deleteCustomerGroup.mutate() - * } - * - * // ... - * } - * - * export default CustomerGroup - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/customer-groups/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customer Groups - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCustomerGroupsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const { id } = req.params - - const customerGroupService: CustomerGroupService = req.scope.resolve( - "customerGroupService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await customerGroupService - .withTransaction(transactionManager) - .delete(id) - }) - - res.json({ - id: id, - object: "customer_group", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/customer-groups/delete-customers-batch.ts b/packages/medusa/src/api/routes/admin/customer-groups/delete-customers-batch.ts deleted file mode 100644 index 2c94a01643..0000000000 --- a/packages/medusa/src/api/routes/admin/customer-groups/delete-customers-batch.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { Request, Response } from "express" - -import { CustomerGroupService } from "../../../../services" -import { CustomerGroupsBatchCustomer } from "../../../../types/customer-groups" -import { EntityManager } from "typeorm" -import { Type } from "class-transformer" -import { ValidateNested } from "class-validator" -import { validator } from "../../../../utils/validator" - -/** - * @oas [delete] /admin/customer-groups/{id}/customers/batch - * operationId: "DeleteCustomerGroupsGroupCustomerBatch" - * summary: "Remove Customers from Group" - * description: "Remove a list of customers from a customer group. This doesn't delete the customer, only the association between the customer and the customer group." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the customer group. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteCustomerGroupsGroupCustomerBatchReq" - * x-codegen: - * method: removeCustomers - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.removeCustomers(customerGroupId, { - * customer_ids: [ - * { - * id: customerId - * } - * ] - * }) - * .then(({ customer_group }) => { - * console.log(customer_group.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminRemoveCustomersFromCustomerGroup, - * } from "medusa-react" - * - * type Props = { - * customerGroupId: string - * } - * - * const CustomerGroup = ({ customerGroupId }: Props) => { - * const removeCustomers = - * useAdminRemoveCustomersFromCustomerGroup( - * customerGroupId - * ) - * // ... - * - * const handleRemoveCustomer = (customerId: string) => { - * removeCustomers.mutate({ - * customer_ids: [ - * { - * id: customerId, - * }, - * ], - * }) - * } - * - * // ... - * } - * - * export default CustomerGroup - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/customer-groups/{id}/customers/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "customer_ids": [ - * { - * "id": "cus_01G2Q4BS9GAHDBMDEN4ZQZCJB2" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customer Groups - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCustomerGroupsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const { id } = req.params - const validated = await validator( - AdminDeleteCustomerGroupsGroupCustomerBatchReq, - req.body - ) - - const customerGroupService: CustomerGroupService = req.scope.resolve( - "customerGroupService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const customer_group = await manager.transaction( - async (transactionManager) => { - return await customerGroupService - .withTransaction(transactionManager) - .removeCustomer( - id, - validated.customer_ids.map(({ id }) => id) - ) - } - ) - - res.status(200).json({ customer_group }) -} - -/** - * @schema AdminDeleteCustomerGroupsGroupCustomerBatchReq - * type: object - * description: "The customers to remove from the customer group." - * required: - * - customer_ids - * properties: - * customer_ids: - * description: "The ids of the customers to remove" - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * description: ID of the customer - * type: string - */ -export class AdminDeleteCustomerGroupsGroupCustomerBatchReq { - @ValidateNested({ each: true }) - @Type(() => CustomerGroupsBatchCustomer) - customer_ids: CustomerGroupsBatchCustomer[] -} diff --git a/packages/medusa/src/api/routes/admin/customer-groups/get-customer-group-customers.ts b/packages/medusa/src/api/routes/admin/customer-groups/get-customer-group-customers.ts deleted file mode 100644 index 8770f31514..0000000000 --- a/packages/medusa/src/api/routes/admin/customer-groups/get-customer-group-customers.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { Request, Response } from "express" - -import CustomerController from "../../../../controllers/customers" -import { IsNumber, IsOptional, IsString } from "class-validator" -import { Type } from "class-transformer" - -/** - * @oas [get] /admin/customer-groups/{id}/customers - * operationId: "GetCustomerGroupsGroupCustomers" - * summary: "List Customers" - * description: "Retrieve a list of customers in a customer group. The customers can be filtered by the `q` field. The customers can also be paginated." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the customer group. - * - (query) limit=50 {integer} The number of customers to return. - * - (query) offset=0 {integer} The number of customers to skip when retrieving the customers. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned customers. - * - (query) q {string} a term to search customers by email, first_name, and last_name. - * x-codegen: - * method: listCustomers - * queryParams: AdminGetGroupsGroupCustomersParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.listCustomers(customerGroupId) - * .then(({ customers }) => { - * console.log(customers.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCustomerGroupCustomers } from "medusa-react" - * - * type Props = { - * customerGroupId: string - * } - * - * const CustomerGroup = ({ customerGroupId }: Props) => { - * const { - * customers, - * isLoading, - * } = useAdminCustomerGroupCustomers( - * customerGroupId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {customers && !customers.length && ( - * No customers - * )} - * {customers && customers.length > 0 && ( - *
    - * {customers.map((customer) => ( - *
  • {customer.first_name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default CustomerGroup - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/customer-groups/{id}/customers' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customer Groups - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCustomersListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - req.query.groups = [id] - - const result = await CustomerController.listAndCount( - req.scope, - req.query, - req.body - ) - - res.json(result) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved customer group's customers. - */ -// eslint-disable-next-line max-len -export class AdminGetGroupsGroupCustomersParams { - /** - * Search term to search customers by their email, first name, and last name. - */ - @IsString() - @IsOptional() - q?: string - - /** - * {@inheritDoc FindPaginationParams.limit} - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit = 50 - - /** - * {@inheritDoc FindPaginationParams.offset} - */ - @IsOptional() - @IsNumber() - @IsOptional() - @Type(() => Number) - offset = 0 - - /** - * {@inheritDoc FindParams.expand} - */ - @IsString() - @IsOptional() - expand?: string -} diff --git a/packages/medusa/src/api/routes/admin/customer-groups/get-customer-group.ts b/packages/medusa/src/api/routes/admin/customer-groups/get-customer-group.ts deleted file mode 100644 index 6a87b6ca28..0000000000 --- a/packages/medusa/src/api/routes/admin/customer-groups/get-customer-group.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { Request, Response } from "express" - -import { CustomerGroupService } from "../../../../services" -import { FindParams } from "../../../../types/common" - -/** - * @oas [get] /admin/customer-groups/{id} - * operationId: "GetCustomerGroupsGroup" - * summary: "Get a Customer Group" - * description: "Retrieve a Customer Group by its ID. You can expand the customer group's relations or select the fields that should be returned." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Customer Group. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned customer group. - * - (query) fields {string} Comma-separated fields that should be included in the returned customer group. - * x-codegen: - * method: retrieve - * queryParams: AdminGetCustomerGroupsGroupParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.retrieve(customerGroupId) - * .then(({ customer_group }) => { - * console.log(customer_group.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCustomerGroup } from "medusa-react" - * - * type Props = { - * customerGroupId: string - * } - * - * const CustomerGroup = ({ customerGroupId }: Props) => { - * const { customer_group, isLoading } = useAdminCustomerGroup( - * customerGroupId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {customer_group && {customer_group.name}} - *
- * ) - * } - * - * export default CustomerGroup - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/customer-groups/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customer Groups - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCustomerGroupsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const customerGroupService: CustomerGroupService = req.scope.resolve( - "customerGroupService" - ) - - const customerGroup = await customerGroupService.retrieve( - id, - req.retrieveConfig - ) - - res.json({ customer_group: customerGroup }) -} - -export class AdminGetCustomerGroupsGroupParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/customer-groups/index.ts b/packages/medusa/src/api/routes/admin/customer-groups/index.ts deleted file mode 100644 index b32eaef819..0000000000 --- a/packages/medusa/src/api/routes/admin/customer-groups/index.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { Router } from "express" -import { CustomerGroup } from "../../../.." -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import middlewares, { transformQuery } from "../../../middlewares" -import { AdminGetCustomerGroupsGroupParams } from "./get-customer-group" -import { AdminGetCustomerGroupsParams } from "./list-customer-groups" - -const route = Router() - -export default (app) => { - app.use("/customer-groups", route) - - route.post("/", middlewares.wrap(require("./create-customer-group").default)) - route.get( - "/", - transformQuery(AdminGetCustomerGroupsParams, { - defaultRelations: defaultAdminCustomerGroupsRelations, - isList: true, - }), - middlewares.wrap(require("./list-customer-groups").default) - ) - - const customerGroupRouter = Router({ mergeParams: true }) - route.use("/:id", customerGroupRouter) - customerGroupRouter.get( - "/", - transformQuery(AdminGetCustomerGroupsGroupParams, { - defaultRelations: defaultAdminCustomerGroupsRelations, - }), - middlewares.wrap(require("./get-customer-group").default) - ) - customerGroupRouter.delete( - "/", - middlewares.wrap(require("./delete-customer-group").default) - ) - customerGroupRouter.post( - "/", - middlewares.wrap(require("./update-customer-group").default) - ) - customerGroupRouter.get( - "/customers", - middlewares.wrap(require("./get-customer-group-customers").default) - ) - customerGroupRouter.post( - "/customers/batch", - middlewares.wrap(require("./add-customers-batch").default) - ) - customerGroupRouter.delete( - "/customers/batch", - middlewares.wrap(require("./delete-customers-batch").default) - ) - - return app -} - -/* ************************************** */ -/* ******** EXPORT API CLIENT TYPES ***** */ -/* ************************************** */ -/** - * @schema AdminCustomerGroupsRes - * type: object - * description: "The customer group's details." - * required: - * - customer_group - * properties: - * customer_group: - * description: Customer group details. - * $ref: "#/components/schemas/CustomerGroup" - */ -export type AdminCustomerGroupsRes = { - customer_group: CustomerGroup -} - -/** - * @schema AdminCustomerGroupsDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted customer group. - * object: - * type: string - * description: The type of the object that was deleted. - * default: customer_group - * deleted: - * type: boolean - * description: Whether the customer group was deleted successfully or not. - * default: true - */ -export type AdminCustomerGroupsDeleteRes = DeleteResponse - -/** - * @schema AdminCustomerGroupsListRes - * type: object - * required: - * - customer_groups - * - count - * - offset - * - limit - * properties: - * customer_groups: - * type: array - * description: An array of customer group details. - * items: - * $ref: "#/components/schemas/CustomerGroup" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of customer groups skipped when retrieving the customer groups. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminCustomerGroupsListRes = PaginatedResponse & { - customer_groups: CustomerGroup[] -} - -export const defaultAdminCustomerGroupsRelations = [] - -export * from "./add-customers-batch" -export * from "./create-customer-group" -export * from "./delete-customers-batch" -export * from "./get-customer-group" -export * from "./list-customer-groups" -export * from "./update-customer-group" diff --git a/packages/medusa/src/api/routes/admin/customer-groups/list-customer-groups.ts b/packages/medusa/src/api/routes/admin/customer-groups/list-customer-groups.ts deleted file mode 100644 index a1663956cf..0000000000 --- a/packages/medusa/src/api/routes/admin/customer-groups/list-customer-groups.ts +++ /dev/null @@ -1,242 +0,0 @@ -import { IsNumber, IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" - -import { Type } from "class-transformer" -import { CustomerGroupService } from "../../../../services" -import { FilterableCustomerGroupProps } from "../../../../types/customer-groups" - -/** - * @oas [get] /admin/customer-groups - * operationId: "GetCustomerGroups" - * summary: "List Customer Groups" - * description: "Retrieve a list of customer groups. The customer groups can be filtered by fields such as `name` or `id. The customer groups can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) q {string} term to search customer groups by name. - * - (query) offset=0 {integer} The number of customer groups to skip when retrieving the customer groups. - * - (query) order {string} A field to sort order the retrieved customer groups by. - * - (query) discount_condition_id {string} Filter by discount condition ID. - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by the customer group ID - * schema: - * oneOf: - * - type: string - * description: customer group ID - * - type: array - * description: an array of customer group IDs - * items: - * type: string - * - type: object - * properties: - * lt: - * type: string - * description: filter by IDs less than this ID - * gt: - * type: string - * description: filter by IDs greater than this ID - * lte: - * type: string - * description: filter by IDs less than or equal to this ID - * gte: - * type: string - * description: filter by IDs greater than or equal to this ID - * - in: query - * name: name - * style: form - * explode: false - * description: Filter by the customer group name - * schema: - * type: array - * description: an array of customer group names - * items: - * type: string - * description: customer group name - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - (query) limit=10 {integer} The number of customer groups to return. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned customer groups. - * - (query) fields {string} Comma-separated fields that should be included in the returned customer groups. - * x-codegen: - * method: list - * queryParams: AdminGetCustomerGroupsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.list() - * .then(({ customer_groups, limit, offset, count }) => { - * console.log(customer_groups.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCustomerGroups } from "medusa-react" - * - * const CustomerGroups = () => { - * const { - * customer_groups, - * isLoading, - * } = useAdminCustomerGroups() - * - * return ( - *
- * {isLoading && Loading...} - * {customer_groups && !customer_groups.length && ( - * No Customer Groups - * )} - * {customer_groups && customer_groups.length > 0 && ( - *
    - * {customer_groups.map( - * (customerGroup) => ( - *
  • - * {customerGroup.name} - *
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default CustomerGroups - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/customer-groups' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customer Groups - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCustomerGroupsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const customerGroupService: CustomerGroupService = req.scope.resolve( - "customerGroupService" - ) - - const [data, count] = await customerGroupService.listAndCount( - req.filterableFields, - req.listConfig - ) - - const { limit, offset } = req.validatedQuery - res.json({ - count, - customer_groups: data, - offset, - limit, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved customer groups. - */ -export class AdminGetCustomerGroupsParams extends FilterableCustomerGroupProps { - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string - - /** - * {@inheritDoc FindPaginationParams.offset} - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - offset?: number = 0 - - /** - * {@inheritDoc FindPaginationParams.limit} - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit?: number = 10 - - /** - * {@inheritDoc FindParams.expand} - */ - @IsString() - @IsOptional() - expand?: string - - /** - * {@inheritDoc FindPaginationParams.fields} - */ - @IsString() - @IsOptional() - fields?: string -} diff --git a/packages/medusa/src/api/routes/admin/customer-groups/update-customer-group.ts b/packages/medusa/src/api/routes/admin/customer-groups/update-customer-group.ts deleted file mode 100644 index 7ddcbe9c20..0000000000 --- a/packages/medusa/src/api/routes/admin/customer-groups/update-customer-group.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { IsObject, IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" - -import { CustomerGroupService } from "../../../../services" -import { EntityManager } from "typeorm" -import { FindParams } from "../../../../types/common" -import { defaultAdminCustomerGroupsRelations } from "." -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/customer-groups/{id} - * operationId: "PostCustomerGroupsGroup" - * summary: "Update a Customer Group" - * description: "Update a Customer Group's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the customer group. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostCustomerGroupsGroupReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customerGroups.update(customerGroupId, { - * name: "VIP" - * }) - * .then(({ customer_group }) => { - * console.log(customer_group.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateCustomerGroup } from "medusa-react" - * - * type Props = { - * customerGroupId: string - * } - * - * const CustomerGroup = ({ customerGroupId }: Props) => { - * const updateCustomerGroup = useAdminUpdateCustomerGroup( - * customerGroupId - * ) - * // .. - * - * const handleUpdate = (name: string) => { - * updateCustomerGroup.mutate({ - * name, - * }) - * } - * - * // ... - * } - * - * export default CustomerGroup - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/customer-groups/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "VIP" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customer Groups - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCustomerGroupsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const { id } = req.params - - const validatedBody = await validator( - AdminPostCustomerGroupsGroupReq, - req.body - ) - const validatedQuery = await validator(FindParams, req.query) - - const customerGroupService: CustomerGroupService = req.scope.resolve( - "customerGroupService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await customerGroupService - .withTransaction(transactionManager) - .update(id, validatedBody) - }) - - let expandFields: string[] = [] - if (validatedQuery.expand) { - expandFields = validatedQuery.expand.split(",") - } - - const findConfig = { - relations: expandFields.length - ? expandFields - : defaultAdminCustomerGroupsRelations, - } - - const customerGroup = await customerGroupService.retrieve(id, findConfig) - - res.json({ customer_group: customerGroup }) -} - -/** - * @schema AdminPostCustomerGroupsGroupReq - * type: object - * description: "The details to update in the customer group." - * properties: - * name: - * description: "Name of the customer group" - * type: string - * metadata: - * description: "Metadata of the customer group." - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostCustomerGroupsGroupReq { - @IsString() - @IsOptional() - name?: string - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/customers/create-customer.ts b/packages/medusa/src/api/routes/admin/customers/create-customer.ts deleted file mode 100644 index 861f729a2f..0000000000 --- a/packages/medusa/src/api/routes/admin/customers/create-customer.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { IsEmail, IsObject, IsOptional, IsString } from "class-validator" - -import { CustomerService } from "../../../../services" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/customers - * operationId: "PostCustomers" - * summary: "Create a Customer" - * description: "Create a customer as an admin." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostCustomersReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customers.create({ - * email: "user@example.com", - * first_name: "Caterina", - * last_name: "Yost", - * password: "supersecret" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateCustomer } from "medusa-react" - * - * type CustomerData = { - * first_name: string - * last_name: string - * email: string - * password: string - * } - * - * const CreateCustomer = () => { - * const createCustomer = useAdminCreateCustomer() - * // ... - * - * const handleCreate = (customerData: CustomerData) => { - * createCustomer.mutate(customerData, { - * onSuccess: ({ customer }) => { - * console.log(customer.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateCustomer - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/customers' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com", - * "first_name": "Caterina", - * "last_name": "Yost", - * "password": "supersecret" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customers - * responses: - * 201: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCustomersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminPostCustomersReq, req.body) - - const customerService: CustomerService = req.scope.resolve("customerService") - const manager: EntityManager = req.scope.resolve("manager") - const customer = await manager.transaction(async (transactionManager) => { - return await customerService - .withTransaction(transactionManager) - .create(validated) - }) - res.status(201).json({ customer }) -} - -/** - * @schema AdminPostCustomersReq - * type: object - * description: "The details of the customer to create." - * required: - * - email - * - first_name - * - last_name - * - password - * properties: - * email: - * type: string - * description: The customer's email. - * format: email - * first_name: - * type: string - * description: The customer's first name. - * last_name: - * type: string - * description: The customer's last name. - * password: - * type: string - * description: The customer's password. - * format: password - * phone: - * type: string - * description: The customer's phone number. - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostCustomersReq { - @IsEmail() - email: string - - @IsString() - first_name: string - - @IsString() - last_name: string - - @IsString() - password: string - - @IsString() - @IsOptional() - phone?: string - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/customers/get-customer.ts b/packages/medusa/src/api/routes/admin/customers/get-customer.ts deleted file mode 100644 index 4f8969bb74..0000000000 --- a/packages/medusa/src/api/routes/admin/customers/get-customer.ts +++ /dev/null @@ -1,105 +0,0 @@ -import CustomerService from "../../../../services/customer" -import { FindParams } from "../../../../types/common" -import { defaultAdminCustomersRelations } from "." -import { validator } from "../../../../utils/validator" - -/** - * @oas [get] /admin/customers/{id} - * operationId: "GetCustomersCustomer" - * summary: "Get a Customer" - * description: "Retrieve the details of a customer." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Customer. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned customer. - * - (query) fields {string} Comma-separated fields that should be included in the returned customer. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customers.retrieve(customerId) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCustomer } from "medusa-react" - * - * type Props = { - * customerId: string - * } - * - * const Customer = ({ customerId }: Props) => { - * const { customer, isLoading } = useAdminCustomer( - * customerId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {customer && {customer.first_name}} - *
- * ) - * } - * - * export default Customer - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/customers/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customers - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCustomersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = await validator(FindParams, req.query) - - const customerService: CustomerService = req.scope.resolve("customerService") - - let expandFields: string[] = [] - if (validated.expand) { - expandFields = validated.expand.split(",") - } - - const findConfig = { - relations: expandFields.length - ? expandFields - : defaultAdminCustomersRelations, - } - - const customer = await customerService.retrieve(id, findConfig) - - res.json({ customer }) -} diff --git a/packages/medusa/src/api/routes/admin/customers/index.ts b/packages/medusa/src/api/routes/admin/customers/index.ts deleted file mode 100644 index f32fa5b9e7..0000000000 --- a/packages/medusa/src/api/routes/admin/customers/index.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { Router } from "express" -import { Customer } from "../../../.." -import { PaginatedResponse } from "../../../../types/common" -import middlewares from "../../../middlewares" - -const route = Router() - -export default (app) => { - app.use("/customers", route) - - route.get( - "/", - middlewares.normalizeQuery(), - middlewares.wrap(require("./list-customers").default) - ) - route.get("/:id", middlewares.wrap(require("./get-customer").default)) - - route.post("/", middlewares.wrap(require("./create-customer").default)) - route.post("/:id", middlewares.wrap(require("./update-customer").default)) - return app -} - -/** - * @schema AdminCustomersRes - * type: object - * description: "The customer's details." - * x-expanded-relations: - * field: customer - * relations: - * - orders - * - shipping_addresses - * required: - * - customer - * properties: - * customer: - * description: "Customer details." - * $ref: "#/components/schemas/Customer" - */ -export type AdminCustomersRes = { - customer: Customer -} - -/** - * @schema AdminCustomersListRes - * description: The list of customers with pagination fields. - * type: object - * required: - * - customers - * - count - * - offset - * - limit - * properties: - * customers: - * type: array - * description: "An array of customer details." - * items: - * $ref: "#/components/schemas/Customer" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of customers skipped when retrieving the customers. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminCustomersListRes = PaginatedResponse & { - customers: Customer[] -} - -export const defaultAdminCustomersRelations = ["orders", "shipping_addresses"] - -export * from "./create-customer" -export * from "./get-customer" -export * from "./list-customers" -export * from "./update-customer" diff --git a/packages/medusa/src/api/routes/admin/customers/list-customers.ts b/packages/medusa/src/api/routes/admin/customers/list-customers.ts deleted file mode 100644 index 399bfcf79e..0000000000 --- a/packages/medusa/src/api/routes/admin/customers/list-customers.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { IsNumber, IsOptional, IsString } from "class-validator" - -import { Type } from "class-transformer" -import { Request, Response } from "express" -import customerController from "../../../../controllers/customers" -import { AdminListCustomerSelector } from "../../../../types/customers" - -/** - * @oas [get] /admin/customers - * operationId: "GetCustomers" - * summary: "List Customers" - * description: "Retrieve a list of Customers. The customers can be filtered by fields such as `q` or `groups`. The customers can also be paginated." - * x-authenticated: true - * parameters: - * - (query) limit=50 {integer} The number of customers to return. - * - (query) offset=0 {integer} The number of customers to skip when retrieving the customers. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned customers. - * - (query) fields {string} Comma-separated fields that should be included in the returned customers. - * - (query) q {string} term to search customers' email, first_name, and last_name fields. - * - (query) has_account {boolean} Filter customers by whether they have an account. - * - (query) order {string} A field to sort-order the retrieved customers by. - * - in: query - * name: groups - * style: form - * explode: false - * description: Filter by customer group IDs. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: list - * queryParams: AdminGetCustomersParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customers.list() - * .then(({ customers, limit, offset, count }) => { - * console.log(customers.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCustomers } from "medusa-react" - * - * const Customers = () => { - * const { customers, isLoading } = useAdminCustomers() - * - * return ( - *
- * {isLoading && Loading...} - * {customers && !customers.length && ( - * No customers - * )} - * {customers && customers.length > 0 && ( - *
    - * {customers.map((customer) => ( - *
  • {customer.first_name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Customers - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/customers' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customers - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCustomersListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const result = await customerController.listAndCount( - req.scope, - req.query, - req.body - ) - - res.json(result) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved customers. - */ -export class AdminGetCustomersParams extends AdminListCustomerSelector { - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 50 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit = 50 - - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsOptional() - @IsNumber() - @IsOptional() - @Type(() => Number) - offset = 0 - - /** - * {@inheritDoc FindParams.expand} - */ - @IsString() - @IsOptional() - expand?: string - - /** - * {@inheritDoc FindParams.fields} - */ - @IsString() - @IsOptional() - fields?: string -} diff --git a/packages/medusa/src/api/routes/admin/customers/update-customer.ts b/packages/medusa/src/api/routes/admin/customers/update-customer.ts deleted file mode 100644 index 4fb089fc2e..0000000000 --- a/packages/medusa/src/api/routes/admin/customers/update-customer.ts +++ /dev/null @@ -1,227 +0,0 @@ -import { - IsArray, - IsEmail, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" - -import CustomerService from "../../../../services/customer" -import { EntityManager } from "typeorm" -import { FindParams } from "../../../../types/common" -import { MedusaError } from "medusa-core-utils" -import { Type } from "class-transformer" -import { defaultAdminCustomersRelations } from "." -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/customers/{id} - * operationId: "PostCustomersCustomer" - * summary: "Update a Customer" - * description: "Update a Customer's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Customer. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned customer. - * - (query) fields {string} Comma-separated fields that should be retrieved in the returned customer. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostCustomersCustomerReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.customers.update(customerId, { - * first_name: "Dolly" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateCustomer } from "medusa-react" - * - * type CustomerData = { - * first_name: string - * last_name: string - * email: string - * password: string - * } - * - * type Props = { - * customerId: string - * } - * - * const Customer = ({ customerId }: Props) => { - * const updateCustomer = useAdminUpdateCustomer(customerId) - * // ... - * - * const handleUpdate = (customerData: CustomerData) => { - * updateCustomer.mutate(customerData) - * } - * - * // ... - * } - * - * export default Customer - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/customers/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "first_name": "Dolly" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customers - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCustomersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validatedBody = await validator(AdminPostCustomersCustomerReq, req.body) - const validatedQuery = await validator(FindParams, req.query) - - const customerService: CustomerService = req.scope.resolve("customerService") - - let customer = await customerService.retrieve(id) - - if (validatedBody.email && customer.has_account) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Email cannot be changed when the user has registered their account" - ) - } - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await customerService - .withTransaction(transactionManager) - .update(id, validatedBody) - }) - - let expandFields: string[] = [] - if (validatedQuery.expand) { - expandFields = validatedQuery.expand.split(",") - } - - const findConfig = { - relations: expandFields.length - ? expandFields - : defaultAdminCustomersRelations, - } - - customer = await customerService.retrieve(id, findConfig) - - res.status(200).json({ customer }) -} - -class Group { - @IsString() - id: string -} - -/** - * @schema AdminPostCustomersCustomerReq - * type: object - * description: "The details of the customer to update." - * properties: - * email: - * type: string - * description: The Customer's email. You can't update the email of a registered customer. - * format: email - * first_name: - * type: string - * description: The Customer's first name. - * last_name: - * type: string - * description: The Customer's last name. - * phone: - * type: string - * description: The Customer's phone number. - * password: - * type: string - * description: The Customer's password. - * format: password - * groups: - * type: array - * description: A list of customer groups to which the customer belongs. - * items: - * type: object - * required: - * - id - * properties: - * id: - * description: The ID of a customer group - * type: string - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostCustomersCustomerReq { - @IsEmail() - @IsOptional() - email?: string - - @IsString() - @IsOptional() - first_name?: string - - @IsString() - @IsOptional() - last_name?: string - - @IsString() - @IsOptional() - password?: string - - @IsString() - @IsOptional() - phone?: string - - @IsObject() - @IsOptional() - metadata?: Record - - @IsArray() - @IsOptional() - @Type(() => Group) - @ValidateNested({ each: true }) - groups?: Group[] -} diff --git a/packages/medusa/src/api/routes/admin/discounts/__tests__/add-region.js b/packages/medusa/src/api/routes/admin/discounts/__tests__/add-region.js deleted file mode 100644 index 6fd72d8932..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/__tests__/add-region.js +++ /dev/null @@ -1,62 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { DiscountServiceMock } from "../../../../../services/__mocks__/discount" - -describe("POST /admin/discounts/:discount_id/regions/:region_id", () => { - describe("successful addition", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/discounts/${IdMap.getId("total10")}/regions/${IdMap.getId( - "region-france" - )}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve", () => { - expect(DiscountServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("total10"), - { - select: [ - "id", - "code", - "is_dynamic", - "is_disabled", - "rule_id", - "parent_discount_id", - "usage_limit", - "usage_count", - "starts_at", - "ends_at", - "created_at", - "updated_at", - "deleted_at", - "metadata", - "valid_duration", - ], - relations: ["parent_discount", "regions", "rule.conditions"], - } - ) - - expect(DiscountServiceMock.addRegion).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.addRegion).toHaveBeenCalledWith( - IdMap.getId("total10"), - IdMap.getId("region-france") - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/discounts/__tests__/create-discount.js b/packages/medusa/src/api/routes/admin/discounts/__tests__/create-discount.js deleted file mode 100644 index 2ac77cc2ed..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/__tests__/create-discount.js +++ /dev/null @@ -1,318 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { DiscountServiceMock } from "../../../../../services/__mocks__/discount" - -const validRegionId = IdMap.getId("region-france") - -jest.setTimeout(30000) -describe("POST /admin/discounts", () => { - const adminSession = { - jwt: { - userId: IdMap.getId("admin_user"), - }, - } - - describe("successful creation", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/discounts", { - payload: { - code: "TEST", - rule: { - description: "Test", - type: "fixed", - value: 10, - allocation: "total", - }, - regions: [validRegionId], - starts_at: "02/02/2021 13:45", - ends_at: "03/14/2021 04:30", - }, - adminSession, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service create", () => { - expect(DiscountServiceMock.create).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.create).toHaveBeenCalledWith({ - code: "TEST", - rule: { - description: "Test", - type: "fixed", - value: 10, - allocation: "total", - }, - regions: [validRegionId], - starts_at: new Date("02/02/2021 13:45"), - ends_at: new Date("03/14/2021 04:30"), - is_disabled: false, - is_dynamic: false, - }) - }) - }) - - describe("unsuccessful creation with dynamic discount using an invalid iso8601 duration", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - - subject = await request("POST", "/admin/discounts", { - payload: { - code: "TEST", - rule: { - description: "Test", - type: "fixed", - value: 10, - allocation: "total", - }, - regions: [validRegionId], - starts_at: "02/02/2021 13:45", - is_dynamic: true, - valid_duration: "PaMT2D", - }, - adminSession, - }) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns error", () => { - expect(subject.body.message).toEqual( - `"valid_duration" must be a valid ISO 8601 duration` - ) - }) - }) - - describe("successful creation with dynamic discount", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("POST", "/admin/discounts", { - payload: { - code: "TEST", - rule: { - description: "Test", - type: "fixed", - value: 10, - allocation: "total", - }, - regions: [validRegionId], - starts_at: "02/02/2021 13:45", - is_dynamic: true, - valid_duration: "P1Y2M03DT04H05M", - }, - adminSession, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service create", () => { - expect(DiscountServiceMock.create).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.create).toHaveBeenCalledWith({ - code: "TEST", - rule: { - description: "Test", - type: "fixed", - value: 10, - allocation: "total", - }, - regions: [validRegionId], - starts_at: new Date("02/02/2021 13:45"), - is_disabled: false, - is_dynamic: true, - valid_duration: "P1Y2M03DT04H05M", - }) - }) - }) - - describe("fails on invalid data", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/discounts", { - payload: { - code: "10%OFF", - rule: { - description: "Test", - value: 10, - allocation: "total", - }, - regions: [validRegionId], - }, - adminSession, - }) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns error", () => { - expect(subject.body.message).toEqual( - `Invalid rule type, must be one of "fixed", "percentage" or "free_shipping"` - ) - }) - }) - - describe("fails on xor constraint for conditions", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/discounts", { - payload: { - code: "TEST", - rule: { - description: "Test", - type: "fixed", - value: 10, - allocation: "total", - conditions: [ - { - products: ["product1"], - operator: "in", - product_types: ["producttype1"], - }, - ], - }, - regions: [validRegionId], - starts_at: "02/02/2021 13:45", - is_dynamic: true, - valid_duration: "P1Y2M03DT04H05M", - }, - adminSession, - }) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns error", () => { - expect(subject.body.message).toEqual( - `Only one of products, product_types is allowed, Only one of product_types, products is allowed` - ) - }) - }) - - describe("fails on invalid date intervals", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/discounts", { - payload: { - code: "TEST", - rule: { - description: "Test", - type: "fixed", - value: 10, - allocation: "total", - }, - regions: [validRegionId], - ends_at: "02/02/2021", - starts_at: "03/14/2021", - }, - adminSession, - }) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns error", () => { - expect(subject.body.message).toEqual( - `"ends_at" must be greater than "starts_at"` - ) - }) - }) - - describe("successfully creates a dynamic discount without setting valid duration", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("POST", "/admin/discounts", { - payload: { - code: "TEST", - is_dynamic: true, - rule: { - description: "Test", - type: "fixed", - value: 10, - allocation: "total", - }, - regions: [validRegionId], - starts_at: "03/14/2021 14:30", - }, - adminSession, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns error", () => { - expect(DiscountServiceMock.create).toHaveBeenCalledWith({ - code: "TEST", - is_dynamic: true, - is_disabled: false, - rule: { - description: "Test", - type: "fixed", - value: 10, - allocation: "total", - }, - regions: [validRegionId], - starts_at: new Date("03/14/2021 14:30"), - }) - }) - }) - - describe("unsuccessful creation with invalid regions", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - - subject = await request("POST", "/admin/discounts", { - payload: { - code: "TEST", - rule: { - description: "Test", - type: "fixed", - value: 10, - allocation: "total", - }, - }, - adminSession, - }) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns error", () => { - expect(subject.body.message).toEqual( - `each value in regions must be a string, regions must be an array` - ) - }) - - it("does not call service create", () => { - expect(DiscountServiceMock.create).toHaveBeenCalledTimes(0) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/discounts/__tests__/delete-discount.js b/packages/medusa/src/api/routes/admin/discounts/__tests__/delete-discount.js deleted file mode 100644 index f2bacfafe1..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/__tests__/delete-discount.js +++ /dev/null @@ -1,42 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { DiscountServiceMock } from "../../../../../services/__mocks__/discount" - -describe("DELETE /admin/discounts/discount_id", () => { - describe("successful deletion", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/discounts/${IdMap.getId("total10")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service delete", () => { - expect(DiscountServiceMock.delete).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.delete).toHaveBeenCalledWith( - IdMap.getId("total10") - ) - }) - - it("returns correct delete object", () => { - expect(subject.body).toEqual({ - id: IdMap.getId("total10"), - object: "discount", - deleted: true, - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/discounts/__tests__/get-discount.js b/packages/medusa/src/api/routes/admin/discounts/__tests__/get-discount.js deleted file mode 100644 index 978e843415..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/__tests__/get-discount.js +++ /dev/null @@ -1,58 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { DiscountServiceMock } from "../../../../../services/__mocks__/discount" - -const defaultFields = [ - "id", - "code", - "is_dynamic", - "is_disabled", - "rule_id", - "parent_discount_id", - "usage_limit", - "usage_count", - "starts_at", - "ends_at", - "created_at", - "updated_at", - "deleted_at", - "metadata", - "valid_duration", -] - -const defaultRelations = ["parent_discount", "regions", "rule.conditions"] - -describe("GET /admin/discounts/:discount_id", () => { - describe("successful retrieval", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/admin/discounts/${IdMap.getId("total10")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve", () => { - expect(DiscountServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("total10"), - { - select: defaultFields, - relations: defaultRelations, - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/discounts/__tests__/list-discounts.js b/packages/medusa/src/api/routes/admin/discounts/__tests__/list-discounts.js deleted file mode 100644 index 292e87eb76..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/__tests__/list-discounts.js +++ /dev/null @@ -1,142 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from ".." -import { request } from "../../../../../helpers/test-request" -import { DiscountServiceMock } from "../../../../../services/__mocks__/discount" - -describe("GET /admin/discounts", () => { - describe("successful retrieval of discounts", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("GET", `/admin/discounts`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve with config", () => { - expect(DiscountServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - { - select: defaultAdminDiscountsFields, - relations: defaultAdminDiscountsRelations, - skip: 0, - take: 20, - order: { created_at: "DESC" }, - } - ) - }) - }) - - describe("successful retrieval of discounts with query config", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request( - "GET", - `/admin/discounts?q=OLI&limit=40&offset=20&is_dynamic=false&is_disabled=false`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve with config", () => { - expect(DiscountServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.listAndCount).toHaveBeenCalledWith( - { q: "OLI", is_dynamic: false, is_disabled: false }, - { - select: defaultAdminDiscountsFields, - relations: defaultAdminDiscountsRelations, - skip: 20, - take: 40, - order: { created_at: "DESC" }, - } - ) - }) - }) - - describe("successful retrieval of dynamic discounts", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("GET", `/admin/discounts?is_dynamic=true`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve with corresponding config", () => { - expect(DiscountServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.listAndCount).toHaveBeenCalledWith( - { is_dynamic: true }, - { - select: defaultAdminDiscountsFields, - relations: defaultAdminDiscountsRelations, - skip: 0, - take: 20, - order: { created_at: "DESC" }, - } - ) - }) - }) - - describe("successful retrieval of disabled discounts", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("GET", `/admin/discounts?is_disabled=true`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve with corresponding config", () => { - expect(DiscountServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.listAndCount).toHaveBeenCalledWith( - { is_disabled: true }, - { - select: defaultAdminDiscountsFields, - relations: defaultAdminDiscountsRelations, - skip: 0, - take: 20, - order: { created_at: "DESC" }, - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/discounts/__tests__/remove-region.js b/packages/medusa/src/api/routes/admin/discounts/__tests__/remove-region.js deleted file mode 100644 index 613397cbb3..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/__tests__/remove-region.js +++ /dev/null @@ -1,66 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { DiscountServiceMock } from "../../../../../services/__mocks__/discount" - -const defaultFields = [ - "id", - "code", - "is_dynamic", - "is_disabled", - "rule_id", - "parent_discount_id", - "usage_limit", - "usage_count", - "starts_at", - "ends_at", - "created_at", - "updated_at", - "deleted_at", - "metadata", - "valid_duration", -] - -const defaultRelations = ["parent_discount", "regions", "rule.conditions"] - -describe("DELETE /admin/discounts/:discount_id/regions/region_id", () => { - describe("successful removal", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/discounts/${IdMap.getId("total10")}/regions/${IdMap.getId( - "region-france" - )}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve", () => { - expect(DiscountServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("total10"), - { - select: defaultFields, - relations: defaultRelations, - } - ) - - expect(DiscountServiceMock.removeRegion).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.removeRegion).toHaveBeenCalledWith( - IdMap.getId("total10"), - IdMap.getId("region-france") - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/discounts/__tests__/update-discount.js b/packages/medusa/src/api/routes/admin/discounts/__tests__/update-discount.js deleted file mode 100644 index 9a04ecd9ae..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/__tests__/update-discount.js +++ /dev/null @@ -1,128 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { DiscountServiceMock } from "../../../../../services/__mocks__/discount" - -describe("POST /admin/discounts", () => { - describe("successful update", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request( - "POST", - `/admin/discounts/${IdMap.getId("total10")}`, - { - payload: { - code: "10TOTALOFF", - rule: { - id: "1234", - value: 10, - allocation: "total", - }, - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service method", () => { - expect(DiscountServiceMock.update).toHaveBeenCalledTimes(1) - expect(DiscountServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("total10"), - { - code: "10TOTALOFF", - rule: { - id: "1234", - value: 10, - allocation: "total", - }, - } - ) - }) - }) - - describe("unsuccessful update with dynamic discount using an invalid iso8601 duration", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request( - "POST", - `/admin/discounts/${IdMap.getId("total10")}`, - { - payload: { - code: "10TOTALOFF", - rule: { - id: "1234", - value: 10, - }, - starts_at: "02/02/2021 13:45", - valid_duration: "PaMT2D", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns error", () => { - expect(subject.body.message).toEqual( - `"valid_duration" must be a valid ISO 8601 duration` - ) - }) - }) - - describe("fails on invalid date intervals", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request( - "POST", - `/admin/discounts/${IdMap.getId("total10")}`, - { - payload: { - code: "10TOTALOFF", - rule: { - id: "1234", - value: 10, - allocation: "total", - }, - ends_at: "02/02/2021", - starts_at: "03/14/2021", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns error", () => { - expect(subject.body.message).toEqual( - `"ends_at" must be greater than "starts_at"` - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/discounts/add-region.ts b/packages/medusa/src/api/routes/admin/discounts/add-region.ts deleted file mode 100644 index bbfcdf6812..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/add-region.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "." - -import { Discount } from "../../../.." -import DiscountService from "../../../../services/discount" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/discounts/{id}/regions/{region_id} - * operationId: "PostDiscountsDiscountRegionsRegion" - * summary: "Add Region to Discount" - * description: "Add a Region to the list of Regions a Discount can be used in." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Discount. - * - (path) region_id=* {string} The ID of the Region. - * x-codegen: - * method: addRegion - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.addRegion(discountId, regionId) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDiscountAddRegion } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const addRegion = useAdminDiscountAddRegion(discountId) - * // ... - * - * const handleAdd = (regionId: string) => { - * addRegion.mutate(regionId, { - * onSuccess: ({ discount }) => { - * console.log(discount.regions) - * } - * }) - * } - * - * // ... - * } - * - * export default Discount - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/discounts/{id}/regions/{region_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { discount_id, region_id } = req.params - - const discountService: DiscountService = req.scope.resolve("discountService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await discountService - .withTransaction(transactionManager) - .addRegion(discount_id, region_id) - }) - - const discount: Discount = await discountService.retrieve(discount_id, { - select: defaultAdminDiscountsFields, - relations: defaultAdminDiscountsRelations, - }) - - res.status(200).json({ discount }) -} diff --git a/packages/medusa/src/api/routes/admin/discounts/add-resources-to-condition-batch.ts b/packages/medusa/src/api/routes/admin/discounts/add-resources-to-condition-batch.ts deleted file mode 100644 index aa6e2dbc71..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/add-resources-to-condition-batch.ts +++ /dev/null @@ -1,182 +0,0 @@ -import DiscountConditionService from "../../../../services/discount-condition" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { DiscountService } from "../../../../services" -import { - DiscountConditionInput, - DiscountConditionMapTypeToProperty, -} from "../../../../types/discount" -import { IsArray } from "class-validator" -import { FindParams } from "../../../../types/common" - -/** - * @oas [post] /admin/discounts/{discount_id}/conditions/{condition_id}/batch - * operationId: "PostDiscountsDiscountConditionsConditionBatch" - * summary: "Add Batch Resources" - * description: "Add a batch of resources to a discount condition. The type of resource depends on the type of discount condition. For example, if the discount condition's type is `products`, - * the resources being added should be products." - * x-authenticated: true - * parameters: - * - (path) discount_id=* {string} The ID of the discount the condition belongs to. - * - (path) condition_id=* {string} The ID of the discount condition on which to add the item. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned discount. - * - (query) fields {string} Comma-separated fields that should be included in the returned discount. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostDiscountsDiscountConditionsConditionBatchReq" - * x-codegen: - * method: addConditionResourceBatch - * queryParams: AdminPostDiscountsDiscountConditionsConditionBatchParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.addConditionResourceBatch(discountId, conditionId, { - * resources: [{ id: itemId }] - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminAddDiscountConditionResourceBatch - * } from "medusa-react" - * - * type Props = { - * discountId: string - * conditionId: string - * } - * - * const DiscountCondition = ({ - * discountId, - * conditionId - * }: Props) => { - * const addConditionResources = useAdminAddDiscountConditionResourceBatch( - * discountId, - * conditionId - * ) - * // ... - * - * const handleAdd = (itemId: string) => { - * addConditionResources.mutate({ - * resources: [ - * { - * id: itemId - * } - * ] - * }, { - * onSuccess: ({ discount }) => { - * console.log(discount.id) - * } - * }) - * } - * - * // ... - * } - * - * export default DiscountCondition - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/discounts/{id}/conditions/{condition_id}/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "resources": [{ "id": "item_id" }] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { discount_id, condition_id } = req.params - const validatedBody = - req.validatedBody as AdminPostDiscountsDiscountConditionsConditionBatchReq - - const conditionService: DiscountConditionService = req.scope.resolve( - "discountConditionService" - ) - const manager: EntityManager = req.scope.resolve("manager") - - const condition = await conditionService.retrieve(condition_id, { - select: ["id", "type", "discount_rule_id"], - }) - - const updateObj: DiscountConditionInput = { - id: condition_id, - rule_id: condition.discount_rule_id, - [DiscountConditionMapTypeToProperty[condition.type]]: - validatedBody.resources, - } - - await manager.transaction(async (transactionManager) => { - await conditionService - .withTransaction(transactionManager) - .upsertCondition(updateObj, false) - }) - - const discountService: DiscountService = req.scope.resolve("discountService") - const discount = await discountService.retrieve( - discount_id, - req.retrieveConfig - ) - - res.status(200).json({ discount }) -} - -/** - * @schema AdminPostDiscountsDiscountConditionsConditionBatchReq - * type: object - * description: "The details of the resources to add." - * required: - * - resources - * properties: - * resources: - * description: The resources to be added to the discount condition - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * description: The ID of the item - * type: string - */ -export class AdminPostDiscountsDiscountConditionsConditionBatchReq { - @IsArray() - resources: { id: string }[] -} - -// eslint-disable-next-line max-len -export class AdminPostDiscountsDiscountConditionsConditionBatchParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/discounts/create-condition.ts b/packages/medusa/src/api/routes/admin/discounts/create-condition.ts deleted file mode 100644 index 08c419983c..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/create-condition.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { Request, Response } from "express" -import { DiscountConditionOperator } from "../../../../models" -import { IsString } from "class-validator" - -import { AdminUpsertConditionsReq } from "../../../../types/discount" -import DiscountConditionService from "../../../../services/discount-condition" -import { DiscountService } from "../../../../services" -import { EntityManager } from "typeorm" -import { FindParams } from "../../../../types/common" - -/** - * @oas [post] /admin/discounts/{discount_id}/conditions - * operationId: "PostDiscountsDiscountConditions" - * summary: "Create a Condition" - * description: "Create a Discount Condition. Only one of `products`, `product_types`, `product_collections`, `product_tags`, and `customer_groups` should be provided, based on the type of discount condition. - * For example, if the discount condition's type is `products`, the `products` field should be provided in the request body." - * x-authenticated: true - * parameters: - * - (path) discount_id=* {string} The ID of the discount. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned discount. - * - (query) fields {string} Comma-separated fields that should be included in the returned discount. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostDiscountsDiscountConditions" - * x-codegen: - * method: createCondition - * queryParams: AdminPostDiscountsDiscountConditionsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * import { DiscountConditionOperator } from "@medusajs/medusa" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.createCondition(discountId, { - * operator: DiscountConditionOperator.IN, - * products: [productId] - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { DiscountConditionOperator } from "@medusajs/medusa" - * import { useAdminDiscountCreateCondition } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const createCondition = useAdminDiscountCreateCondition(discountId) - * // ... - * - * const handleCreateCondition = ( - * operator: DiscountConditionOperator, - * products: string[] - * ) => { - * createCondition.mutate({ - * operator, - * products - * }, { - * onSuccess: ({ discount }) => { - * console.log(discount.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Discount - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/discounts/{id}/conditions' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "operator": "in" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { discount_id } = req.params - const conditionService: DiscountConditionService = req.scope.resolve( - "discountConditionService" - ) - const discountService: DiscountService = req.scope.resolve("discountService") - - let discount = await discountService.retrieve(discount_id) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await conditionService - .withTransaction(transactionManager) - .upsertCondition({ - ...(req.validatedBody as AdminPostDiscountsDiscountConditions), - rule_id: discount.rule_id, - }) - }) - - discount = await discountService.retrieve(discount.id, req.retrieveConfig) - - res.status(200).json({ discount }) -} - -/** - * @schema AdminPostDiscountsDiscountConditions - * type: object - * required: - * - operator - * properties: - * operator: - * description: >- - * Operator of the condition. `in` indicates that discountable resources are within the specified resources. `not_in` indicates that - * discountable resources are everything but the specified resources. - * type: string - * enum: [in, not_in] - * products: - * type: array - * description: list of product IDs if the condition's type is `products`. - * items: - * type: string - * product_types: - * type: array - * description: list of product type IDs if the condition's type is `product_types`. - * items: - * type: string - * product_collections: - * type: array - * description: list of product collection IDs if the condition's type is `product_collections`. - * items: - * type: string - * product_tags: - * type: array - * description: list of product tag IDs if the condition's type is `product_tags`. - * items: - * type: string - * customer_groups: - * type: array - * description: list of customer group IDs if the condition's type is `customer_groups`. - * items: - * type: string - */ -// eslint-disable-next-line max-len -export class AdminPostDiscountsDiscountConditions extends AdminUpsertConditionsReq { - @IsString() - operator: DiscountConditionOperator -} - -export class AdminPostDiscountsDiscountConditionsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/discounts/create-discount.ts b/packages/medusa/src/api/routes/admin/discounts/create-discount.ts deleted file mode 100644 index f91073fefc..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/create-discount.ts +++ /dev/null @@ -1,382 +0,0 @@ -import { Type } from "class-transformer" -import { - IsArray, - IsBoolean, - IsDate, - IsEnum, - IsNotEmpty, - IsNumber, - IsObject, - IsOptional, - IsPositive, - IsString, - ValidateNested, -} from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { - AllocationType, - DiscountConditionOperator, - DiscountRuleType, -} from "../../../../models" -import DiscountService from "../../../../services/discount" -import { FindParams } from "../../../../types/common" -import { AdminUpsertConditionsReq } from "../../../../types/discount" -import { IsGreaterThan } from "../../../../utils/validators/greater-than" -import { IsISO8601Duration } from "../../../../utils/validators/iso8601-duration" - -/** - * @oas [post] /admin/discounts - * operationId: "PostDiscounts" - * summary: "Create a Discount" - * x-authenticated: true - * description: "Create a Discount with a given set of rules that defines how the Discount is applied." - * parameters: - * - (query) expand {string} Comma-separated relations that should be expanded in the returned discount. - * - (query) fields {string} Comma-separated fields that should be retrieved in the returned discount. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostDiscountsReq" - * x-codegen: - * method: create - * queryParams: AdminPostDiscountsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * import { AllocationType, DiscountRuleType } from "@medusajs/medusa" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.create({ - * code: "TEST", - * rule: { - * type: DiscountRuleType.FIXED, - * value: 10, - * allocation: AllocationType.ITEM - * }, - * regions: ["reg_XXXXXXXX"], - * is_dynamic: false, - * is_disabled: false - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminCreateDiscount, - * } from "medusa-react" - * import { - * AllocationType, - * DiscountRuleType, - * } from "@medusajs/medusa" - * - * const CreateDiscount = () => { - * const createDiscount = useAdminCreateDiscount() - * // ... - * - * const handleCreate = ( - * currencyCode: string, - * regionId: string - * ) => { - * // ... - * createDiscount.mutate({ - * code: currencyCode, - * rule: { - * type: DiscountRuleType.FIXED, - * value: 10, - * allocation: AllocationType.ITEM, - * }, - * regions: [ - * regionId, - * ], - * is_dynamic: false, - * is_disabled: false, - * }) - * } - * - * // ... - * } - * - * export default CreateDiscount - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/discounts' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "code": "TEST", - * "rule": { - * "type": "fixed", - * "value": 10, - * "allocation": "item" - * }, - * "regions": ["reg_XXXXXXXX"] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const discountService: DiscountService = req.scope.resolve("discountService") - - const manager: EntityManager = req.scope.resolve("manager") - const created = await manager.transaction(async (transactionManager) => { - return await discountService - .withTransaction(transactionManager) - .create(req.validatedBody as AdminPostDiscountsReq) - }) - - const discount = await discountService.retrieve( - created.id, - req.retrieveConfig - ) - - res.status(200).json({ discount }) -} - -/** - * Details of the discount rule to create. - */ -export class AdminPostDiscountsDiscountRule { - /** - * The discount rule's description. - */ - @IsString() - @IsOptional() - description?: string - - /** - * The discount rule's type. - */ - @IsEnum(DiscountRuleType, { - message: `Invalid rule type, must be one of "fixed", "percentage" or "free_shipping"`, - }) - type: DiscountRuleType - - /** - * The discount rule's value. - */ - @IsNumber() - value: number - - /** - * The discount rule's allocation. - */ - @IsEnum(AllocationType, { - message: `Invalid allocation type, must be one of "total" or "item"`, - }) - allocation: AllocationType - - /** - * The discount rule's conditions. - */ - @IsOptional() - @IsArray() - @ValidateNested({ each: true }) - @Type(() => AdminCreateCondition) - conditions?: AdminCreateCondition[] -} - -/** - * @schema AdminPostDiscountsReq - * type: object - * description: "The details of the discount to create." - * required: - * - code - * - rule - * - regions - * properties: - * code: - * type: string - * description: A unique code that will be used to redeem the discount - * is_dynamic: - * type: boolean - * description: Whether the discount should have multiple instances of itself, each with a different code. This can be useful for automatically generated discount codes that all have to follow a common set of rules. - * default: false - * rule: - * description: The discount rule that defines how discounts are calculated - * type: object - * required: - * - type - * - value - * - allocation - * properties: - * description: - * type: string - * description: "A short description of the discount" - * type: - * type: string - * description: >- - * The type of the discount, can be `fixed` for discounts that reduce the price by a fixed amount, `percentage` for percentage reductions or `free_shipping` for shipping vouchers. - * enum: [fixed, percentage, free_shipping] - * value: - * type: number - * description: "The value that the discount represents. This will depend on the type of the discount." - * allocation: - * type: string - * description: >- - * The scope that the discount should apply to. `total` indicates that the discount should be applied on the cart total, and `item` indicates that the discount should be applied to each discountable item in the cart. - * enum: [total, item] - * conditions: - * type: array - * description: "A set of conditions that can be used to limit when the discount can be used. Only one of `products`, `product_types`, `product_collections`, `product_tags`, and `customer_groups` should be provided based on the discount condition's type." - * items: - * type: object - * required: - * - operator - * properties: - * operator: - * type: string - * description: >- - * Operator of the condition. `in` indicates that discountable resources are within the specified resources. `not_in` indicates that - * discountable resources are everything but the specified resources. - * enum: [in, not_in] - * products: - * type: array - * description: list of product IDs if the condition's type is `products`. - * items: - * type: string - * product_types: - * type: array - * description: list of product type IDs if the condition's type is `product_types`. - * items: - * type: string - * product_collections: - * type: array - * description: list of product collection IDs if the condition's type is `product_collections`. - * items: - * type: string - * product_tags: - * type: array - * description: list of product tag IDs if the condition's type is `product_tags`. - * items: - * type: string - * customer_groups: - * type: array - * description: list of customer group IDs if the condition's type is `customer_groups`. - * items: - * type: string - * is_disabled: - * type: boolean - * description: >- - * Whether the discount code is disabled on creation. If set to `true`, it will not be available for customers. - * default: false - * starts_at: - * type: string - * format: date-time - * description: The date and time at which the discount should be available. - * ends_at: - * type: string - * format: date-time - * description: The date and time at which the discount should no longer be available. - * valid_duration: - * type: string - * description: The duration the discount runs between - * example: P3Y6M4DT12H30M5S - * regions: - * description: A list of region IDs representing the Regions in which the Discount can be used. - * type: array - * items: - * type: string - * usage_limit: - * type: number - * description: Maximum number of times the discount can be used - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostDiscountsReq { - @IsString() - @IsNotEmpty() - code: string - - @IsNotEmpty() - @ValidateNested() - @Type(() => AdminPostDiscountsDiscountRule) - rule: AdminPostDiscountsDiscountRule - - @IsBoolean() - @IsOptional() - is_dynamic = false - - @IsBoolean() - @IsOptional() - is_disabled = false - - @IsDate() - @IsOptional() - @Type(() => Date) - starts_at?: Date - - @IsDate() - @IsOptional() - @IsGreaterThan("starts_at") - @Type(() => Date) - ends_at?: Date - - @IsISO8601Duration() - @IsOptional() - valid_duration?: string - - @IsNumber() - @IsOptional() - @IsPositive() - usage_limit?: number - - @IsArray() - @IsString({ each: true }) - regions: string[] - - @IsObject() - @IsOptional() - metadata?: Record -} - -/** - * Details of the discount condition to create. - */ -export class AdminCreateCondition extends AdminUpsertConditionsReq { - /** - * The operator of the discount condition. - */ - @IsString() - operator: DiscountConditionOperator -} - -/** - * {@inheritDoc FindParams} - */ -export class AdminPostDiscountsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/discounts/create-dynamic-code.ts b/packages/medusa/src/api/routes/admin/discounts/create-dynamic-code.ts deleted file mode 100644 index 7d65352002..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/create-dynamic-code.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { Request, Response } from "express" -import { - IsNotEmpty, - IsNumber, - IsObject, - IsOptional, - IsString, -} from "class-validator" -import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "." - -import DiscountService from "../../../../services/discount" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/discounts/{id}/dynamic-codes - * operationId: "PostDiscountsDiscountDynamicCodes" - * summary: "Create a Dynamic Code" - * description: "Create a dynamic unique code that can map to a parent Discount. This is useful if you want to automatically generate codes with the same rules and conditions." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Discount to create the dynamic code for." - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostDiscountsDiscountDynamicCodesReq" - * x-codegen: - * method: createDynamicCode - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.createDynamicCode(discountId, { - * code: "TEST", - * usage_limit: 1 - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateDynamicDiscountCode } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const createDynamicDiscount = useAdminCreateDynamicDiscountCode(discountId) - * // ... - * - * const handleCreate = ( - * code: string, - * usageLimit: number - * ) => { - * createDynamicDiscount.mutate({ - * code, - * usage_limit: usageLimit - * }, { - * onSuccess: ({ discount }) => { - * console.log(discount.is_dynamic) - * } - * }) - * } - * - * // ... - * } - * - * export default Discount - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/discounts/{id}/dynamic-codes' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "code": "TEST" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { discount_id } = req.params - - const discountService: DiscountService = req.scope.resolve("discountService") - const manager: EntityManager = req.scope.resolve("manager") - const created = await manager.transaction(async (transactionManager) => { - return await discountService - .withTransaction(transactionManager) - .createDynamicCode( - discount_id, - req.validatedBody as AdminPostDiscountsDiscountDynamicCodesReq - ) - }) - - const discount = await discountService.retrieve(created.id, { - select: defaultAdminDiscountsFields, - relations: defaultAdminDiscountsRelations, - }) - - res.status(200).json({ discount }) -} - -/** - * @schema AdminPostDiscountsDiscountDynamicCodesReq - * type: object - * description: "The details of the dynamic discount to create." - * required: - * - code - * properties: - * code: - * type: string - * description: A unique code that will be used to redeem the Discount - * usage_limit: - * type: number - * description: Maximum number of times the discount code can be used - * default: 1 - * metadata: - * type: object - * description: An optional set of key-value pairs to hold additional information. - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostDiscountsDiscountDynamicCodesReq { - @IsString() - @IsNotEmpty() - code: string - - @IsNumber() - @IsOptional() - usage_limit = 1 - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/discounts/delete-condition.ts b/packages/medusa/src/api/routes/admin/discounts/delete-condition.ts deleted file mode 100644 index 587e87cbab..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/delete-condition.ts +++ /dev/null @@ -1,149 +0,0 @@ -import DiscountConditionService from "../../../../services/discount-condition" -import { DiscountService } from "../../../../services" -import { EntityManager } from "typeorm" -import { MedusaError } from "medusa-core-utils" -import { FindParams } from "../../../../types/common" - -/** - * @oas [delete] /admin/discounts/{discount_id}/conditions/{condition_id} - * operationId: "DeleteDiscountsDiscountConditionsCondition" - * summary: "Delete a Condition" - * description: "Delete a Discount Condition. This does not delete resources associated to the discount condition." - * x-authenticated: true - * parameters: - * - (path) discount_id=* {string} The ID of the Discount - * - (path) condition_id=* {string} The ID of the Discount Condition - * - (query) expand {string} Comma-separated relations that should be expanded in the returned discount. - * - (query) fields {string} Comma-separated fields that should be included in the returned discount. - * x-codegen: - * method: deleteCondition - * queryParams: AdminDeleteDiscountsDiscountConditionsConditionParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.deleteCondition(discountId, conditionId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminDiscountRemoveCondition - * } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const deleteCondition = useAdminDiscountRemoveCondition( - * discountId - * ) - * // ... - * - * const handleDelete = ( - * conditionId: string - * ) => { - * deleteCondition.mutate(conditionId, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(deleted) - * } - * }) - * } - * - * // ... - * } - * - * export default Discount - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/discounts/{id}/conditions/{condition_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountConditionsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { discount_id, condition_id } = req.params - - const conditionService: DiscountConditionService = req.scope.resolve( - "discountConditionService" - ) - const discountService: DiscountService = req.scope.resolve("discountService") - - const condition = await conditionService - .retrieve(condition_id) - .catch(() => void 0) - - if (!condition) { - const discount = await discountService.retrieve( - discount_id, - req.retrieveConfig - ) - // resolves idempotently in case of non-existing condition - return res.json({ - id: condition_id, - object: "discount-condition", - deleted: true, - discount, - }) - } - - let discount = await discountService.retrieve(discount_id, { - select: ["id", "rule_id"], - }) - - if (condition.discount_rule_id !== discount.rule_id) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Condition with id ${condition_id} does not belong to Discount with id ${discount_id}` - ) - } - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await conditionService - .withTransaction(transactionManager) - .delete(condition_id) - }) - - discount = await discountService.retrieve(discount_id, req.retrieveConfig) - - res.json({ - id: condition_id, - object: "discount-condition", - deleted: true, - discount, - }) -} - -export class AdminDeleteDiscountsDiscountConditionsConditionParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/discounts/delete-discount.ts b/packages/medusa/src/api/routes/admin/discounts/delete-discount.ts deleted file mode 100644 index 404e178f75..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/delete-discount.ts +++ /dev/null @@ -1,90 +0,0 @@ -import DiscountService from "../../../../services/discount" -import { EntityManager } from "typeorm" - -/** - * @oas [delete] /admin/discounts/{id} - * operationId: "DeleteDiscountsDiscount" - * summary: "Delete a Discount" - * description: "Delete a Discount. Deleting the discount will make it unavailable for customers to use." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Discount - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.delete(discountId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteDiscount } from "medusa-react" - * - * const Discount = () => { - * const deleteDiscount = useAdminDeleteDiscount(discount_id) - * // ... - * - * const handleDelete = () => { - * deleteDiscount.mutate() - * } - * - * // ... - * } - * - * export default Discount - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/discounts/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { discount_id } = req.params - - const discountService: DiscountService = req.scope.resolve("discountService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await discountService - .withTransaction(transactionManager) - .delete(discount_id) - }) - - res.json({ - id: discount_id, - object: "discount", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/discounts/delete-dynamic-code.ts b/packages/medusa/src/api/routes/admin/discounts/delete-dynamic-code.ts deleted file mode 100644 index 26a4a25e89..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/delete-dynamic-code.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "." - -import DiscountService from "../../../../services/discount" -import { EntityManager } from "typeorm" - -/** - * @oas [delete] /admin/discounts/{id}/dynamic-codes/{code} - * operationId: "DeleteDiscountsDiscountDynamicCodesCode" - * summary: "Delete a Dynamic Code" - * description: "Delete a dynamic code from a Discount." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Discount - * - (path) code=* {string} The dynamic code to delete - * x-codegen: - * method: deleteDynamicCode - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.deleteDynamicCode(discountId, code) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteDynamicDiscountCode } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const deleteDynamicDiscount = useAdminDeleteDynamicDiscountCode(discountId) - * // ... - * - * const handleDelete = (code: string) => { - * deleteDynamicDiscount.mutate(code, { - * onSuccess: ({ discount }) => { - * console.log(discount.is_dynamic) - * } - * }) - * } - * - * // ... - * } - * - * export default Discount - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/discounts/{id}/dynamic-codes/{code}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { discount_id, code } = req.params - - const discountService: DiscountService = req.scope.resolve("discountService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await discountService - .withTransaction(transactionManager) - .deleteDynamicCode(discount_id, code) - }) - - const discount = await discountService.retrieve(discount_id, { - select: defaultAdminDiscountsFields, - relations: defaultAdminDiscountsRelations, - }) - - res.status(200).json({ discount }) -} diff --git a/packages/medusa/src/api/routes/admin/discounts/delete-resources-from-condition-batch.ts b/packages/medusa/src/api/routes/admin/discounts/delete-resources-from-condition-batch.ts deleted file mode 100644 index 4b91203a94..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/delete-resources-from-condition-batch.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { DiscountConditionService, DiscountService } from "../../../../services" -import { - DiscountConditionInput, - DiscountConditionMapTypeToProperty, -} from "../../../../types/discount" -import { IsArray } from "class-validator" -import { FindParams } from "../../../../types/common" - -/** - * @oas [delete] /admin/discounts/{discount_id}/conditions/{condition_id}/batch - * operationId: "DeleteDiscountsDiscountConditionsConditionBatch" - * summary: "Remove Batch Resources" - * description: "Remove a batch of resources from a discount condition. This will only remove the association between the resource and the discount condition, not the resource itself." - * x-authenticated: true - * parameters: - * - (path) discount_id=* {string} The ID of the discount. - * - (path) condition_id=* {string} The ID of the condition to remove the resources from. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned discount. - * - (query) fields {string} Comma-separated fields that should be included in the returned discount. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteDiscountsDiscountConditionsConditionBatchReq" - * x-codegen: - * method: deleteConditionResourceBatch - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.deleteConditionResourceBatch(discountId, conditionId, { - * resources: [{ id: itemId }] - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminDeleteDiscountConditionResourceBatch - * } from "medusa-react" - * - * type Props = { - * discountId: string - * conditionId: string - * } - * - * const DiscountCondition = ({ - * discountId, - * conditionId - * }: Props) => { - * const deleteConditionResource = useAdminDeleteDiscountConditionResourceBatch( - * discountId, - * conditionId, - * ) - * // ... - * - * const handleDelete = (itemId: string) => { - * deleteConditionResource.mutate({ - * resources: [ - * { - * id: itemId - * } - * ] - * }, { - * onSuccess: ({ discount }) => { - * console.log(discount.id) - * } - * }) - * } - * - * // ... - * } - * - * export default DiscountCondition - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/discounts/{id}/conditions/{condition_id}/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "resources": [{ "id": "item_id" }] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { discount_id, condition_id } = req.params - - const conditionService: DiscountConditionService = req.scope.resolve( - "discountConditionService" - ) - const manager: EntityManager = req.scope.resolve("manager") - - const condition = await conditionService.retrieve(condition_id, { - select: ["id", "type", "discount_rule_id"], - }) - - const validatedBody = - req.validatedBody as AdminDeleteDiscountsDiscountConditionsConditionBatchReq - const data = { - id: condition_id, - rule_id: condition.discount_rule_id, - [DiscountConditionMapTypeToProperty[condition.type]]: - validatedBody.resources, - } as Omit & { id: string } - - await manager.transaction(async (transactionManager) => { - await conditionService - .withTransaction(transactionManager) - .removeResources(data) - }) - - const discountService: DiscountService = req.scope.resolve("discountService") - const discount = await discountService.retrieve( - discount_id, - req.retrieveConfig - ) - - res.status(200).json({ discount }) -} - -/** - * {@inheritDoc FindParams} - */ -// eslint-disable-next-line max-len -export class AdminDeleteDiscountsDiscountConditionsConditionBatchParams extends FindParams {} - -/** - * @schema AdminDeleteDiscountsDiscountConditionsConditionBatchReq - * type: object - * description: "The resources to remove." - * required: - * - resources - * properties: - * resources: - * description: The resources to be removed from the discount condition - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * description: The id of the item - * type: string - */ -export class AdminDeleteDiscountsDiscountConditionsConditionBatchReq { - @IsArray() - resources: { id: string }[] -} diff --git a/packages/medusa/src/api/routes/admin/discounts/get-condition.ts b/packages/medusa/src/api/routes/admin/discounts/get-condition.ts deleted file mode 100644 index e977afac6b..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/get-condition.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { Request, Response } from "express" -import DiscountConditionService from "../../../../services/discount-condition" -import { FindParams } from "../../../../types/common" - -/** - * @oas [get] /admin/discounts/{discount_id}/conditions/{condition_id} - * operationId: "GetDiscountsDiscountConditionsCondition" - * summary: "Get a Condition" - * description: "Retrieve a Discount Condition's details." - * x-authenticated: true - * parameters: - * - (path) discount_id=* {string} The ID of the Discount. - * - (path) condition_id=* {string} The ID of the Discount Condition. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned discount condition. - * - (query) fields {string} Comma-separated fields that should be included in the returned discount condition. - * x-codegen: - * method: getCondition - * queryParams: AdminGetDiscountsDiscountConditionsConditionParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.getCondition(discountId, conditionId) - * .then(({ discount_condition }) => { - * console.log(discount_condition.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminGetDiscountCondition } from "medusa-react" - * - * type Props = { - * discountId: string - * discountConditionId: string - * } - * - * const DiscountCondition = ({ - * discountId, - * discountConditionId - * }: Props) => { - * const { - * discount_condition, - * isLoading - * } = useAdminGetDiscountCondition( - * discountId, - * discountConditionId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {discount_condition && ( - * {discount_condition.type} - * )} - *
- * ) - * } - * - * export default DiscountCondition - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/discounts/{id}/conditions/{condition_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountConditionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const { condition_id } = req.params - - const conditionService: DiscountConditionService = req.scope.resolve( - "discountConditionService" - ) - - const discountCondition = await conditionService.retrieve( - condition_id, - req.retrieveConfig - ) - - res.status(200).json({ discount_condition: discountCondition }) -} - -export class AdminGetDiscountsDiscountConditionsConditionParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/discounts/get-discount-by-code.ts b/packages/medusa/src/api/routes/admin/discounts/get-discount-by-code.ts deleted file mode 100644 index 6e723e099f..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/get-discount-by-code.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { Request, Response } from "express" -import DiscountService from "../../../../services/discount" -import { FindParams } from "../../../../types/common" - -/** - * @oas [get] /admin/discounts/code/{code} - * operationId: "GetDiscountsDiscountCode" - * summary: "Get Discount by Code" - * description: "Retrieve a Discount's details by its discount code" - * x-authenticated: true - * parameters: - * - (path) code=* {string} The code of the Discount - * - (query) expand {string} Comma-separated relations that should be expanded in the returned discount. - * - (query) fields {string} Comma-separated fields that should be included in the returned discount. - * x-codegen: - * method: retrieveByCode - * queryParams: AdminGetDiscountsDiscountCodeParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.retrieveByCode(code) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminGetDiscountByCode } from "medusa-react" - * - * type Props = { - * discountCode: string - * } - * - * const Discount = ({ discountCode }: Props) => { - * const { discount, isLoading } = useAdminGetDiscountByCode( - * discountCode - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {discount && {discount.code}} - *
- * ) - * } - * - * export default Discount - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/discounts/code/{code}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { code } = req.params - - const discountService: DiscountService = req.scope.resolve("discountService") - const discount = await discountService.retrieveByCode( - code, - req.retrieveConfig - ) - - res.status(200).json({ discount }) -} - -export class AdminGetDiscountsDiscountCodeParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/discounts/get-discount.ts b/packages/medusa/src/api/routes/admin/discounts/get-discount.ts deleted file mode 100644 index 3980cfb650..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/get-discount.ts +++ /dev/null @@ -1,93 +0,0 @@ -import DiscountService from "../../../../services/discount" -import { Request, Response } from "express" -import { FindParams } from "../../../../types/common" - -/** - * @oas [get] /admin/discounts/{id} - * operationId: "GetDiscountsDiscount" - * summary: "Get a Discount" - * description: "Retrieve a Discount." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Discount - * - (query) expand {string} Comma-separated relations that should be expanded in the returned discount. - * - (query) fields {string} Comma-separated fields that should be included in the returned discount. - * x-codegen: - * method: retrieve - * queryParams: AdminGetDiscountParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.retrieve(discountId) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDiscount } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const { discount, isLoading } = useAdminDiscount( - * discountId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {discount && {discount.code}} - *
- * ) - * } - * - * export default Discount - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/discounts/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { discount_id } = req.params - - const discountService: DiscountService = req.scope.resolve("discountService") - const data = await discountService.retrieve(discount_id, req.retrieveConfig) - - res.status(200).json({ discount: data }) -} - -export class AdminGetDiscountParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/discounts/index.ts b/packages/medusa/src/api/routes/admin/discounts/index.ts deleted file mode 100644 index 26a3f40f8b..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/index.ts +++ /dev/null @@ -1,366 +0,0 @@ -import { Router } from "express" -import "reflect-metadata" -import { Discount } from "../../../.." -import { DiscountCondition } from "../../../../models" -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import middlewares, { - doesConditionBelongToDiscount, - transformBody, - transformQuery, -} from "../../../middlewares" -import { - AdminPostDiscountsDiscountConditionsConditionBatchParams, - AdminPostDiscountsDiscountConditionsConditionBatchReq, -} from "./add-resources-to-condition-batch" -import { - AdminPostDiscountsDiscountConditionsCondition, - AdminPostDiscountsDiscountConditionsConditionParams, -} from "./update-condition" -import { - AdminPostDiscountsDiscountConditions, - AdminPostDiscountsDiscountConditionsParams, -} from "./create-condition" -import { AdminPostDiscountsDiscountDynamicCodesReq } from "./create-dynamic-code" -import { - AdminPostDiscountsDiscountParams, - AdminPostDiscountsDiscountReq, -} from "./update-discount" -import { - AdminPostDiscountsParams, - AdminPostDiscountsReq, -} from "./create-discount" -import { AdminGetDiscountsParams } from "./list-discounts" -import { AdminGetDiscountsDiscountConditionsConditionParams } from "./get-condition" -import { AdminDeleteDiscountsDiscountConditionsConditionParams } from "./delete-condition" -import { AdminGetDiscountsDiscountCodeParams } from "./get-discount-by-code" -import { AdminGetDiscountParams } from "./get-discount" -import { - AdminDeleteDiscountsDiscountConditionsConditionBatchParams, - AdminDeleteDiscountsDiscountConditionsConditionBatchReq, -} from "./delete-resources-from-condition-batch" - -const route = Router() - -export default (app) => { - app.use("/discounts", route) - - route.get( - "/", - transformQuery(AdminGetDiscountsParams, { - defaultFields: defaultAdminDiscountsFields, - defaultRelations: defaultAdminDiscountsRelations, - isList: true, - }), - middlewares.wrap(require("./list-discounts").default) - ) - route.post( - "/", - transformQuery(AdminPostDiscountsParams, { - defaultFields: defaultAdminDiscountsFields, - defaultRelations: defaultAdminDiscountsRelations, - isList: false, - }), - transformBody(AdminPostDiscountsReq), - middlewares.wrap(require("./create-discount").default) - ) - - route.get( - "/:discount_id", - transformQuery(AdminGetDiscountParams, { - defaultFields: defaultAdminDiscountsFields, - defaultRelations: defaultAdminDiscountsRelations, - isList: false, - }), - middlewares.wrap(require("./get-discount").default) - ) - route.get( - "/code/:code", - transformQuery(AdminGetDiscountsDiscountCodeParams, { - defaultFields: defaultAdminDiscountsFields, - defaultRelations: defaultAdminDiscountsRelations, - isList: false, - }), - middlewares.wrap(require("./get-discount-by-code").default) - ) - route.post( - "/:discount_id", - transformQuery(AdminPostDiscountsDiscountParams, { - defaultFields: defaultAdminDiscountsFields, - defaultRelations: defaultAdminDiscountsRelations, - isList: false, - }), - transformBody(AdminPostDiscountsDiscountReq), - middlewares.wrap(require("./update-discount").default) - ) - route.delete( - "/:discount_id", - middlewares.wrap(require("./delete-discount").default) - ) - - // Dynamic codes - route.post( - "/:discount_id/dynamic-codes", - transformBody(AdminPostDiscountsDiscountDynamicCodesReq), - middlewares.wrap(require("./create-dynamic-code").default) - ) - route.delete( - "/:discount_id/dynamic-codes/:code", - middlewares.wrap(require("./delete-dynamic-code").default) - ) - - // Discount region management - route.post( - "/:discount_id/regions/:region_id", - middlewares.wrap(require("./add-region").default) - ) - route.delete( - "/:discount_id/regions/:region_id", - middlewares.wrap(require("./remove-region").default) - ) - - // Discount condition management - route.post( - "/:discount_id/conditions", - transformQuery(AdminPostDiscountsDiscountConditionsParams, { - defaultFields: defaultAdminDiscountsFields, - defaultRelations: defaultAdminDiscountsRelations, - isList: false, - }), - transformBody(AdminPostDiscountsDiscountConditions), - middlewares.wrap(require("./create-condition").default) - ) - - route.delete( - "/:discount_id/conditions/:condition_id", - transformQuery(AdminDeleteDiscountsDiscountConditionsConditionParams, { - defaultFields: defaultAdminDiscountsFields, - defaultRelations: defaultAdminDiscountsRelations, - isList: false, - }), - middlewares.wrap(require("./delete-condition").default) - ) - - const conditionRouter = Router({ mergeParams: true }) - route.use( - "/:discount_id/conditions/:condition_id", - doesConditionBelongToDiscount, - conditionRouter - ) - - conditionRouter.get( - "/", - transformQuery(AdminGetDiscountsDiscountConditionsConditionParams, { - defaultFields: defaultAdminDiscountConditionFields, - defaultRelations: defaultAdminDiscountConditionRelations, - isList: false, - }), - middlewares.wrap(require("./get-condition").default) - ) - conditionRouter.post( - "/", - transformQuery(AdminPostDiscountsDiscountConditionsConditionParams, { - defaultFields: defaultAdminDiscountsFields, - defaultRelations: defaultAdminDiscountsRelations, - isList: false, - }), - transformBody(AdminPostDiscountsDiscountConditionsCondition), - middlewares.wrap(require("./update-condition").default) - ) - conditionRouter.post( - "/batch", - transformQuery(AdminPostDiscountsDiscountConditionsConditionBatchParams, { - defaultFields: defaultAdminDiscountsFields, - defaultRelations: defaultAdminDiscountsRelations, - isList: false, - }), - transformBody(AdminPostDiscountsDiscountConditionsConditionBatchReq), - middlewares.wrap(require("./add-resources-to-condition-batch").default) - ) - conditionRouter.delete( - "/batch", - transformQuery(AdminDeleteDiscountsDiscountConditionsConditionBatchParams, { - defaultFields: defaultAdminDiscountsFields, - defaultRelations: defaultAdminDiscountsRelations, - isList: false, - }), - transformBody(AdminDeleteDiscountsDiscountConditionsConditionBatchReq), - middlewares.wrap(require("./delete-resources-from-condition-batch").default) - ) - - return app -} - -export const defaultAdminDiscountsFields: (keyof Discount)[] = [ - "id", - "code", - "is_dynamic", - "is_disabled", - "rule_id", - "parent_discount_id", - "usage_limit", - "usage_count", - "starts_at", - "ends_at", - "created_at", - "updated_at", - "deleted_at", - "metadata", - "valid_duration", -] - -export const defaultAdminDiscountsRelations = [ - "parent_discount", - "regions", - "rule.conditions", -] - -export const defaultAdminDiscountConditionFields: (keyof DiscountCondition)[] = - ["id", "type", "operator", "discount_rule_id", "created_at", "updated_at"] - -export const defaultAdminDiscountConditionRelations = ["discount_rule"] - -/** - * @schema AdminDiscountsRes - * type: object - * description: "The discount's details." - * x-expanded-relations: - * field: discount - * relations: - * - parent_discount - * - regions - * - rule - * - rule.conditions - * eager: - * - regions.fulfillment_providers - * - regions.payment_providers - * required: - * - discount - * properties: - * discount: - * description: "Discount details." - * $ref: "#/components/schemas/Discount" - */ -export type AdminDiscountsRes = { - discount: Discount -} - -/** - * @schema AdminDiscountConditionsRes - * type: object - * x-expanded-relations: - * field: discount_condition - * relations: - * - discount_rule - * required: - * - discount_condition - * properties: - * discount_condition: - * description: "Discount condition details." - * $ref: "#/components/schemas/DiscountCondition" - */ -export type AdminDiscountConditionsRes = { - discount_condition: DiscountCondition -} - -/** - * @schema AdminDiscountsDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Discount - * object: - * type: string - * description: The type of the object that was deleted. - * default: discount - * deleted: - * type: boolean - * description: Whether the discount was deleted successfully. - * default: true - */ -export type AdminDiscountsDeleteRes = DeleteResponse - -/** - * @schema AdminDiscountConditionsDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * - discount - * properties: - * id: - * type: string - * description: The ID of the deleted Discount Condition - * object: - * type: string - * description: The type of the object that was deleted. - * default: discount-condition - * deleted: - * type: boolean - * description: Whether the discount condition was deleted successfully. - * default: true - * discount: - * description: The Discount to which the condition used to belong to. - * $ref: "#/components/schemas/Discount" - */ -export type AdminDiscountConditionsDeleteRes = DeleteResponse & { - discount: Discount -} - -/** - * @schema AdminDiscountsListRes - * type: object - * description: The list of discounts with pagination fields. - * x-expanded-relations: - * field: discounts - * relations: - * - parent_discount - * - regions - * - rule - * - rule.conditions - * required: - * - discounts - * - count - * - offset - * - limit - * properties: - * discounts: - * type: array - * description: "The list of discounts." - * items: - * $ref: "#/components/schemas/Discount" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of discounts skipped when retrieving the discounts. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminDiscountsListRes = PaginatedResponse & { - discounts: Discount[] -} - -export * from "./add-region" -export * from "./create-condition" -export * from "./create-discount" -export * from "./create-dynamic-code" -export * from "./delete-condition" -export * from "./delete-discount" -export * from "./delete-dynamic-code" -export * from "./get-condition" -export * from "./get-discount" -export * from "./get-discount-by-code" -export * from "./list-discounts" -export * from "./remove-region" -export * from "./update-condition" -export * from "./update-discount" -export * from "./add-resources-to-condition-batch" -export * from "./delete-resources-from-condition-batch" diff --git a/packages/medusa/src/api/routes/admin/discounts/list-discounts.ts b/packages/medusa/src/api/routes/admin/discounts/list-discounts.ts deleted file mode 100644 index 1a786920dd..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/list-discounts.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { - IsBoolean, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { Transform, Type } from "class-transformer" - -import { AdminGetDiscountsDiscountRuleParams } from "../../../../types/discount" -import { - DateComparisonOperator, - extendedFindParamsMixin, -} from "../../../../types/common" -import { Request, Response } from "express" -import { DiscountService } from "../../../../services" -import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean" - -/** - * @oas [get] /admin/discounts - * operationId: "GetDiscounts" - * summary: "List Discounts" - * x-authenticated: true - * description: "Retrieve a list of Discounts. The discounts can be filtered by fields such as `rule` or `is_dynamic`. The discounts can also be paginated." - * parameters: - * - (query) q {string} term to search discounts' code field. - * - in: query - * name: rule - * description: Filter discounts by rule fields. - * schema: - * type: object - * properties: - * type: - * type: string - * enum: [fixed, percentage, free_shipping] - * description: "Filter discounts by type." - * allocation: - * type: string - * enum: [total, item] - * description: "Filter discounts by allocation type." - * - (query) is_dynamic {boolean} Filter discounts by whether they're dynamic or not. - * - (query) is_disabled {boolean} Filter discounts by whether they're disabled or not. - * - (query) limit=20 {number} The number of discounts to return - * - (query) offset=0 {number} The number of discounts to skip when retrieving the discounts. - * - (query) expand {string} Comma-separated relations that should be expanded in each returned discount. - * - (query) order {string} A discount field to sort-order the retrieved discounts by. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: list - * queryParams: AdminGetDiscountsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.list() - * .then(({ discounts, limit, offset, count }) => { - * console.log(discounts.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDiscounts } from "medusa-react" - * - * const Discounts = () => { - * const { discounts, isLoading } = useAdminDiscounts() - * - * return ( - *
- * {isLoading && Loading...} - * {discounts && !discounts.length && ( - * No customers - * )} - * {discounts && discounts.length > 0 && ( - *
    - * {discounts.map((discount) => ( - *
  • {discount.code}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Discounts - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/discounts' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const discountService: DiscountService = req.scope.resolve("discountService") - - const { filterableFields, listConfig } = req - const { skip, take } = listConfig - - const [discounts, count] = await discountService.listAndCount( - filterableFields, - listConfig - ) - - res.status(200).json({ - discounts, - count, - offset: skip, - limit: take, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved discounts. - */ -export class AdminGetDiscountsParams extends extendedFindParamsMixin({ - limit: 20, - offset: 0, -}) { - /** - * Filter discounts by their associated rule. - */ - @ValidateNested() - @IsOptional() - @Type(() => AdminGetDiscountsDiscountRuleParams) - rule?: AdminGetDiscountsDiscountRuleParams - - /** - * Search terms to search discounts' code fields. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Filter discounts by whether they're dynamic. - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value)) - is_dynamic?: boolean - - /** - * Filter discounts by whether they're disabled. - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value)) - is_disabled?: boolean - - /** - * Date filters to apply on the discounts' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the discounts' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string -} diff --git a/packages/medusa/src/api/routes/admin/discounts/remove-region.ts b/packages/medusa/src/api/routes/admin/discounts/remove-region.ts deleted file mode 100644 index 99034570fe..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/remove-region.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "." - -import DiscountService from "../../../../services/discount" -import { EntityManager } from "typeorm" - -/** - * @oas [delete] /admin/discounts/{id}/regions/{region_id} - * operationId: "DeleteDiscountsDiscountRegionsRegion" - * summary: "Remove Region" - * x-authenticated: true - * description: "Remove a Region from the list of Regions that a Discount can be used in. This does not delete a region, only the association between it and the discount." - * parameters: - * - (path) id=* {string} The ID of the Discount. - * - (path) region_id=* {string} The ID of the Region. - * x-codegen: - * method: removeRegion - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.removeRegion(discountId, regionId) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDiscountRemoveRegion } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const deleteRegion = useAdminDiscountRemoveRegion(discountId) - * // ... - * - * const handleDelete = (regionId: string) => { - * deleteRegion.mutate(regionId, { - * onSuccess: ({ discount }) => { - * console.log(discount.regions) - * } - * }) - * } - * - * // ... - * } - * - * export default Discount - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/discounts/{id}/regions/{region_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { discount_id, region_id } = req.params - - const discountService: DiscountService = req.scope.resolve("discountService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await discountService - .withTransaction(transactionManager) - .removeRegion(discount_id, region_id) - }) - - const discount = await discountService.retrieve(discount_id, { - select: defaultAdminDiscountsFields, - relations: defaultAdminDiscountsRelations, - }) - - res.status(200).json({ discount }) -} diff --git a/packages/medusa/src/api/routes/admin/discounts/update-condition.ts b/packages/medusa/src/api/routes/admin/discounts/update-condition.ts deleted file mode 100644 index 8526874a7f..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/update-condition.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { Request, Response } from "express" -import { AdminUpsertConditionsReq } from "../../../../types/discount" -import DiscountConditionService from "../../../../services/discount-condition" -import { DiscountService } from "../../../../services" -import { EntityManager } from "typeorm" -import { FindParams } from "../../../../types/common" - -/** - * @oas [post] /admin/discounts/{discount_id}/conditions/{condition_id} - * operationId: "PostDiscountsDiscountConditionsCondition" - * summary: "Update a Condition" - * description: "Update a Discount Condition. Only one of `products`, `product_types`, `product_collections`, `product_tags`, and `customer_groups` should be provided, based on the type of discount condition. - * For example, if the discount condition's type is `products`, the `products` field should be provided in the request body." - * x-authenticated: true - * parameters: - * - (path) discount_id=* {string} The ID of the Discount. - * - (path) condition_id=* {string} The ID of the Discount Condition. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned discount. - * - (query) fields {string} Comma-separated fields that should be included in the returned discount. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostDiscountsDiscountConditionsCondition" - * x-codegen: - * method: updateCondition - * queryParams: AdminPostDiscountsDiscountConditionsConditionParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.updateCondition(discountId, conditionId, { - * products: [ - * productId - * ] - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDiscountUpdateCondition } from "medusa-react" - * - * type Props = { - * discountId: string - * conditionId: string - * } - * - * const DiscountCondition = ({ - * discountId, - * conditionId - * }: Props) => { - * const update = useAdminDiscountUpdateCondition( - * discountId, - * conditionId - * ) - * // ... - * - * const handleUpdate = ( - * products: string[] - * ) => { - * update.mutate({ - * products - * }, { - * onSuccess: ({ discount }) => { - * console.log(discount.id) - * } - * }) - * } - * - * // ... - * } - * - * export default DiscountCondition - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/discounts/{id}/conditions/{condition}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "products": [ - * "prod_01G1G5V2MBA328390B5AXJ610F" - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const { discount_id, condition_id } = req.params - - const conditionService: DiscountConditionService = req.scope.resolve( - "discountConditionService" - ) - - const condition = await conditionService.retrieve(condition_id) - - const discountService: DiscountService = req.scope.resolve("discountService") - - let discount = await discountService.retrieve(discount_id) - - const updateObj = { - ...(req.validatedBody as AdminPostDiscountsDiscountConditionsCondition), - rule_id: discount.rule_id, - id: condition.id, - } - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await conditionService - .withTransaction(transactionManager) - .upsertCondition(updateObj) - }) - - discount = await discountService.retrieve(discount.id, req.retrieveConfig) - - res.status(200).json({ discount }) -} - -/** - * @schema AdminPostDiscountsDiscountConditionsCondition - * type: object - * properties: - * products: - * type: array - * description: list of product IDs if the condition's type is `products`. - * items: - * type: string - * product_types: - * type: array - * description: list of product type IDs if the condition's type is `product_types`. - * items: - * type: string - * product_collections: - * type: array - * description: list of product collection IDs if the condition's type is `product_collections`. - * items: - * type: string - * product_tags: - * type: array - * description: list of product tag IDs if the condition's type is `product_tags` - * items: - * type: string - * customer_groups: - * type: array - * description: list of customer group IDs if the condition's type is `customer_groups`. - * items: - * type: string - */ -// eslint-disable-next-line max-len -export class AdminPostDiscountsDiscountConditionsCondition extends AdminUpsertConditionsReq {} - -// eslint-disable-next-line max-len -export class AdminPostDiscountsDiscountConditionsConditionParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/discounts/update-discount.ts b/packages/medusa/src/api/routes/admin/discounts/update-discount.ts deleted file mode 100644 index 52d216036c..0000000000 --- a/packages/medusa/src/api/routes/admin/discounts/update-discount.ts +++ /dev/null @@ -1,343 +0,0 @@ -import { - IsArray, - IsBoolean, - IsDate, - IsEnum, - IsNotEmpty, - IsNumber, - IsObject, - IsOptional, - IsPositive, - IsString, - ValidateNested, -} from "class-validator" -import { Request, Response } from "express" -import { AllocationType, DiscountConditionOperator } from "../../../../models" - -import { Type } from "class-transformer" -import { EntityManager } from "typeorm" -import DiscountService from "../../../../services/discount" -import { FindParams } from "../../../../types/common" -import { AdminUpsertConditionsReq } from "../../../../types/discount" -import { IsGreaterThan } from "../../../../utils/validators/greater-than" -import { IsISO8601Duration } from "../../../../utils/validators/iso8601-duration" - -/** - * @oas [post] /admin/discounts/{id} - * operationId: "PostDiscountsDiscount" - * summary: "Update a Discount" - * description: "Update a Discount with a given set of rules that define how the Discount is applied." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Discount. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned discount. - * - (query) fields {string} Comma-separated fields that should be retrieved in the returned discount. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostDiscountsDiscountReq" - * x-codegen: - * method: update - * queryParams: AdminPostDiscountsDiscountParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.discounts.update(discountId, { - * code: "TEST" - * }) - * .then(({ discount }) => { - * console.log(discount.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateDiscount } from "medusa-react" - * - * type Props = { - * discountId: string - * } - * - * const Discount = ({ discountId }: Props) => { - * const updateDiscount = useAdminUpdateDiscount(discountId) - * // ... - * - * const handleUpdate = (isDisabled: boolean) => { - * updateDiscount.mutate({ - * is_disabled: isDisabled, - * }) - * } - * - * // ... - * } - * - * export default Discount - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/discounts/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "code": "TEST" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Discounts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDiscountsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { discount_id } = req.params - - const discountService: DiscountService = req.scope.resolve("discountService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await discountService - .withTransaction(transactionManager) - .update(discount_id, req.validatedBody as AdminPostDiscountsDiscountReq) - }) - - const discount = await discountService.retrieve( - discount_id, - req.retrieveConfig - ) - - res.status(200).json({ discount }) -} - -/** - * The attributes of the discount rule to update. - */ -export class AdminUpdateDiscountRule { - /** - * The discount rule's ID. - */ - @IsString() - @IsNotEmpty() - id: string - - /** - * The discount rule's description. - */ - @IsString() - @IsOptional() - description?: string - - /** - * The discount rule's value. - */ - @IsNumber() - @IsOptional() - value?: number - - /** - * The discount rule's allocation. - */ - @IsOptional() - @IsEnum(AllocationType, { - message: `Invalid allocation type, must be one of "total" or "item"`, - }) - allocation?: AllocationType - - /** - * The discount rule's discount conditions. - */ - @IsOptional() - @IsArray() - @ValidateNested({ each: true }) - @Type(() => AdminUpsertCondition) - conditions?: AdminUpsertCondition[] -} - -/** - * @schema AdminPostDiscountsDiscountReq - * type: object - * description: "The details of the discount to update." - * properties: - * code: - * type: string - * description: A unique code that will be used to redeem the discount - * rule: - * description: The discount rule that defines how discounts are calculated - * type: object - * required: - * - id - * properties: - * id: - * type: string - * description: "The ID of the Rule" - * description: - * type: string - * description: "A short description of the discount" - * value: - * type: number - * description: "The value that the discount represents. This will depend on the type of the discount." - * allocation: - * type: string - * description: >- - * The scope that the discount should apply to. `total` indicates that the discount should be applied on the cart total, and `item` indicates that the discount should be applied to each discountable item in the cart. - * enum: [total, item] - * conditions: - * type: array - * description: "A set of conditions that can be used to limit when the discount can be used. Only one of `products`, `product_types`, `product_collections`, `product_tags`, and `customer_groups` should be provided based on the discount condition's type." - * items: - * type: object - * required: - * - operator - * properties: - * id: - * type: string - * description: "The ID of the condition" - * operator: - * type: string - * description: >- - * Operator of the condition. `in` indicates that discountable resources are within the specified resources. `not_in` indicates that - * discountable resources are everything but the specified resources. - * enum: [in, not_in] - * products: - * type: array - * description: list of product IDs if the condition's type is `products`. - * items: - * type: string - * product_types: - * type: array - * description: list of product type IDs if the condition's type is `product_types`. - * items: - * type: string - * product_collections: - * type: array - * description: list of product collection IDs if the condition's type is `product_collections`. - * items: - * type: string - * product_tags: - * type: array - * description: list of product tag IDs if the condition's type is `product_tags`. - * items: - * type: string - * customer_groups: - * type: array - * description: list of customer group IDs if the condition's type is `customer_groups`. - * items: - * type: string - * is_disabled: - * type: boolean - * description: >- - * Whether the discount code is disabled on creation. If set to `true`, it will not be available for customers. - * starts_at: - * type: string - * format: date-time - * description: The date and time at which the discount should be available. - * ends_at: - * type: string - * format: date-time - * description: The date and time at which the discount should no longer be available. - * valid_duration: - * type: string - * description: The duration the discount runs between - * example: P3Y6M4DT12H30M5S - * usage_limit: - * type: number - * description: Maximum number of times the discount can be used - * regions: - * description: A list of region IDs representing the Regions in which the Discount can be used. - * type: array - * items: - * type: string - * metadata: - * description: An object containing metadata of the discount - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostDiscountsDiscountReq { - @IsString() - @IsOptional() - code?: string - - @IsOptional() - @ValidateNested() - @Type(() => AdminUpdateDiscountRule) - rule?: AdminUpdateDiscountRule - - @IsBoolean() - @IsOptional() - is_disabled?: boolean - - @IsDate() - @IsOptional() - @Type(() => Date) - starts_at?: Date - - @IsDate() - @IsOptional() - @IsGreaterThan("starts_at") - @Type(() => Date) - ends_at?: Date | null - - @IsISO8601Duration() - @IsOptional() - valid_duration?: string | null - - @IsNumber() - @IsOptional() - @IsPositive() - usage_limit?: number | null - - @IsArray() - @IsOptional() - @IsString({ each: true }) - regions?: string[] - - @IsObject() - @IsOptional() - metadata?: Record -} - -/** - * The attributes to create or update in the discount condition. - */ -export class AdminUpsertCondition extends AdminUpsertConditionsReq { - /** - * The discount condition's ID. - */ - @IsString() - @IsOptional() - id?: string - - /** - * The discount condition's operator. - */ - @IsString() - @IsOptional() - operator: DiscountConditionOperator -} - -export class AdminPostDiscountsDiscountParams extends FindParams {} 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 deleted file mode 100644 index 166eca6473..0000000000 --- a/packages/medusa/src/api/routes/admin/draft-orders/create-draft-order.ts +++ /dev/null @@ -1,388 +0,0 @@ -import { - IsArray, - IsBoolean, - IsEmail, - IsEnum, - IsNotEmpty, - IsNumber, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { - defaultAdminDraftOrdersCartFields, - defaultAdminDraftOrdersCartRelations, - defaultAdminDraftOrdersFields, - defaultAdminDraftOrdersRelations, -} from "." - -import { Type } from "class-transformer" -import { EntityManager } from "typeorm" -import { DraftOrder } from "../../../.." -import { CartService, DraftOrderService } from "../../../../services" -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 - * operationId: "PostDraftOrders" - * summary: "Create a Draft Order" - * description: "Create a Draft Order. A draft order is not transformed into an order until payment is captured." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostDraftOrdersReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.create({ - * email: "user@example.com", - * region_id, - * items: [ - * { - * quantity: 1 - * } - * ], - * shipping_methods: [ - * { - * option_id - * } - * ], - * }) - * .then(({ draft_order }) => { - * console.log(draft_order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateDraftOrder } from "medusa-react" - * - * type DraftOrderData = { - * email: string - * region_id: string - * items: { - * quantity: number, - * variant_id: string - * }[] - * shipping_methods: { - * option_id: string - * price: number - * }[] - * } - * - * const CreateDraftOrder = () => { - * const createDraftOrder = useAdminCreateDraftOrder() - * // ... - * - * const handleCreate = (data: DraftOrderData) => { - * createDraftOrder.mutate(data, { - * onSuccess: ({ draft_order }) => { - * console.log(draft_order.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateDraftOrder - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/draft-orders' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com", - * "region_id": "{region_id}" - * "items": [ - * { - * "quantity": 1 - * } - * ], - * "shipping_methods": [ - * { - * "option_id": "{option_id}" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Draft Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDraftOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const validated = await validator(AdminPostDraftOrdersReq, req.body) - - const { shipping_address, billing_address, ...rest } = validated - - const draftOrderDataToCreate: DraftOrderCreateProps = { ...rest } - - if (typeof shipping_address === "string") { - draftOrderDataToCreate.shipping_address_id = shipping_address - } else { - draftOrderDataToCreate.shipping_address = shipping_address - } - - if (typeof billing_address === "string") { - draftOrderDataToCreate.billing_address_id = billing_address - } else { - draftOrderDataToCreate.billing_address = billing_address - } - - const draftOrderService: DraftOrderService = - req.scope.resolve("draftOrderService") - - const manager: EntityManager = req.scope.resolve("manager") - let draftOrder: DraftOrder = await manager.transaction( - async (transactionManager) => { - return await draftOrderService - .withTransaction(transactionManager) - .create(draftOrderDataToCreate) - } - ) - - draftOrder = await draftOrderService.retrieve(draftOrder.id, { - relations: defaultAdminDraftOrdersRelations, - select: defaultAdminDraftOrdersFields, - }) - - const cartService: CartService = req.scope.resolve("cartService") - - draftOrder.cart = await cartService - .withTransaction(manager) - .retrieveWithTotals(draftOrder.cart_id, { - relations: defaultAdminDraftOrdersCartRelations, - select: defaultAdminDraftOrdersCartFields, - }) - - res.status(200).json({ draft_order: cleanResponseData(draftOrder, []) }) -} - -enum Status { - open = "open", - completed = "completed", -} - -/** - * @schema AdminPostDraftOrdersReq - * type: object - * description: "The details of the draft order to create." - * required: - * - email - * - region_id - * - shipping_methods - * properties: - * status: - * description: >- - * The status of the draft order. The draft order's default status is `open`. It's changed to `completed` when its payment is marked as paid. - * type: string - * enum: [open, completed] - * email: - * description: "The email of the customer of the draft order" - * type: string - * format: email - * billing_address: - * description: "The Address to be used for billing purposes." - * anyOf: - * - $ref: "#/components/schemas/AddressPayload" - * - type: string - * shipping_address: - * description: "The Address to be used for shipping purposes." - * anyOf: - * - $ref: "#/components/schemas/AddressPayload" - * - type: string - * items: - * description: The draft order's line items. - * type: array - * items: - * type: object - * required: - * - quantity - * properties: - * variant_id: - * description: The ID of the Product Variant associated with the line item. If the line item is custom, the `variant_id` should be omitted. - * type: string - * unit_price: - * description: The custom price of the line item. If a `variant_id` is supplied, the price provided here will override the variant's price. - * type: integer - * title: - * description: The title of the line item if `variant_id` is not provided. - * type: string - * quantity: - * description: The quantity of the line item. - * type: integer - * metadata: - * description: The optional key-value map with additional details about the line item. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * region_id: - * description: The ID of the region for the draft order - * type: string - * discounts: - * description: The discounts to add to the draft order - * type: array - * items: - * type: object - * required: - * - code - * properties: - * code: - * description: The code of the discount to apply - * type: string - * customer_id: - * description: The ID of the customer this draft order is associated with. - * type: string - * no_notification_order: - * description: An optional flag passed to the resulting order that indicates whether the customer should receive notifications about order updates. - * type: boolean - * shipping_methods: - * description: The shipping methods for the draft order - * type: array - * items: - * type: object - * required: - * - option_id - * properties: - * option_id: - * description: The ID of the shipping option in use - * type: string - * data: - * description: The optional additional data needed for the shipping method - * type: object - * price: - * description: The price of the shipping method. - * type: integer - * metadata: - * description: The optional key-value map with additional details about the Draft Order. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostDraftOrdersReq { - @IsEnum(Status) - @IsOptional() - status?: string - - @IsEmail() - email: string - - @IsOptional() - @IsType([AddressPayload, String]) - billing_address?: AddressPayload | string - - @IsOptional() - @IsType([AddressPayload, String]) - shipping_address?: AddressPayload | string - - @IsArray() - @Type(() => Item) - @IsNotEmpty() - @ValidateNested({ each: true }) - @IsOptional() - items?: Item[] - - @IsString() - region_id: string - - @IsArray() - @IsOptional() - @Type(() => Discount) - @ValidateNested({ each: true }) - discounts?: Discount[] - - @IsString() - @IsOptional() - customer_id?: string - - @IsBoolean() - @IsOptional() - no_notification_order?: boolean - - @IsArray() - @Type(() => ShippingMethod) - @IsNotEmpty() - @ValidateNested({ each: true }) - shipping_methods: ShippingMethod[] - - @IsObject() - @IsOptional() - metadata?: Record = {} -} - -class ShippingMethod { - @IsString() - option_id: string - - @IsObject() - @IsOptional() - data?: Record = {} - - @IsNumber() - @IsOptional() - price?: number -} - -class Discount { - @IsString() - code: string -} - -class Item { - @IsString() - @IsOptional() - title?: string - - @IsNumber() - @IsOptional() - unit_price?: number - - @IsString() - @IsOptional() - variant_id?: string - - @IsNumber() - quantity: number - - @IsObject() - @IsOptional() - metadata?: Record = {} -} 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 deleted file mode 100644 index 5766102e9b..0000000000 --- a/packages/medusa/src/api/routes/admin/draft-orders/create-line-item.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { - IsBoolean, - IsInt, - IsObject, - IsOptional, - IsString, -} from "class-validator" -import { - defaultAdminDraftOrdersCartFields, - defaultAdminDraftOrdersCartRelations, - defaultAdminDraftOrdersFields, -} from "." -import { - CartService, - DraftOrderService, - LineItemService, -} from "../../../../services" - -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { cleanResponseData } from "../../../../utils/clean-response-data" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/draft-orders/{id}/line-items - * operationId: "PostDraftOrdersDraftOrderLineItems" - * summary: "Create a Line Item" - * description: "Create a Line Item in the Draft Order." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Draft Order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostDraftOrdersDraftOrderLineItemsReq" - * x-codegen: - * method: addLineItem - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.addLineItem(draftOrderId, { - * quantity: 1 - * }) - * .then(({ draft_order }) => { - * console.log(draft_order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDraftOrderAddLineItem } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const addLineItem = useAdminDraftOrderAddLineItem( - * draftOrderId - * ) - * // ... - * - * const handleAdd = (quantity: number) => { - * addLineItem.mutate({ - * quantity, - * }, { - * onSuccess: ({ draft_order }) => { - * console.log(draft_order.cart) - * } - * }) - * } - * - * // ... - * } - * - * export default DraftOrder - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/draft-orders/{id}/line-items' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "quantity": 1 - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Draft Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDraftOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const { id } = req.params - - const validated = await validator( - AdminPostDraftOrdersDraftOrderLineItemsReq, - req.body - ) - - const draftOrderService: DraftOrderService = - req.scope.resolve("draftOrderService") - const cartService: CartService = req.scope.resolve("cartService") - const lineItemService: LineItemService = req.scope.resolve("lineItemService") - const entityManager: EntityManager = req.scope.resolve("manager") - - await entityManager.transaction(async (manager) => { - const draftOrder = await draftOrderService - .withTransaction(manager) - .retrieve(id, { - select: defaultAdminDraftOrdersFields, - relations: ["cart"], - }) - - if (draftOrder.status === "completed") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "You are only allowed to update open draft orders" - ) - } - - if (validated.variant_id) { - const line = await lineItemService - .withTransaction(manager) - .generate( - validated.variant_id, - draftOrder.cart.region_id, - validated.quantity, - { - metadata: validated.metadata, - unit_price: validated.unit_price, - } - ) - - await cartService - .withTransaction(manager) - .addOrUpdateLineItems(draftOrder.cart_id, line, { - validateSalesChannels: false, - }) - } else { - // custom line items can be added to a draft order - await lineItemService.withTransaction(manager).create({ - cart_id: draftOrder.cart_id, - has_shipping: true, - title: validated.title, - allow_discounts: false, - unit_price: validated.unit_price || 0, - quantity: validated.quantity, - metadata: validated.metadata, - }) - } - - draftOrder.cart = await cartService - .withTransaction(manager) - .retrieveWithTotals(draftOrder.cart_id, { - relations: defaultAdminDraftOrdersCartRelations, - select: defaultAdminDraftOrdersCartFields, - }) - - res.status(200).json({ - draft_order: cleanResponseData(draftOrder, []), - }) - }) -} - -/** - * @schema AdminPostDraftOrdersDraftOrderLineItemsReq - * type: object - * description: "The details of the line item to create." - * required: - * - quantity - * properties: - * variant_id: - * description: The ID of the Product Variant associated with the line item. If the line item is custom, the `variant_id` should be omitted. - * type: string - * unit_price: - * description: The custom price of the line item. If a `variant_id` is supplied, the price provided here will override the variant's price. - * type: integer - * title: - * description: The title of the line item if `variant_id` is not provided. - * type: string - * default: "Custom item" - * quantity: - * description: The quantity of the line item. - * type: integer - * metadata: - * description: The optional key-value map with additional details about the Line Item. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostDraftOrdersDraftOrderLineItemsReq { - @IsString() - @IsOptional() - title?: string = "Custom item" - - @IsInt() - @IsOptional() - unit_price?: number - - @IsString() - @IsOptional() - variant_id?: string - - @IsInt() - quantity: number - - @IsObject() - @IsOptional() - metadata?: Record = {} -} diff --git a/packages/medusa/src/api/routes/admin/draft-orders/delete-draft-order.ts b/packages/medusa/src/api/routes/admin/draft-orders/delete-draft-order.ts deleted file mode 100644 index d71c8eaf96..0000000000 --- a/packages/medusa/src/api/routes/admin/draft-orders/delete-draft-order.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { DraftOrderService } from "../../../../services" -import { EntityManager } from "typeorm" - -/** - * @oas [delete] /admin/draft-orders/{id} - * operationId: DeleteDraftOrdersDraftOrder - * summary: Delete a Draft Order - * description: "Delete a Draft Order." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Draft Order. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.delete(draftOrderId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteDraftOrder } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const deleteDraftOrder = useAdminDeleteDraftOrder( - * draftOrderId - * ) - * // ... - * - * const handleDelete = () => { - * deleteDraftOrder.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default DraftOrder - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/draft-orders/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Draft Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDraftOrdersDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const draftOrderService: DraftOrderService = - req.scope.resolve("draftOrderService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await draftOrderService - .withTransaction(transactionManager) - .delete(id) - }) - - res.json({ - id, - object: "draft-order", - deleted: true, - }) -} 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 deleted file mode 100644 index ed58af0e1c..0000000000 --- a/packages/medusa/src/api/routes/admin/draft-orders/delete-line-item.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { CartService, DraftOrderService } from "../../../../services" -import { - defaultAdminDraftOrdersCartFields, - defaultAdminDraftOrdersCartRelations, - defaultAdminDraftOrdersFields, -} from "." - -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} - * operationId: DeleteDraftOrdersDraftOrderLineItemsItem - * summary: Delete a Line Item - * description: "Delete a Line Item from a Draft Order." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Draft Order. - * - (path) line_id=* {string} The ID of the line item. - * x-codegen: - * method: removeLineItem - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.removeLineItem(draftOrderId, itemId) - * .then(({ draft_order }) => { - * console.log(draft_order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDraftOrderRemoveLineItem } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const deleteLineItem = useAdminDraftOrderRemoveLineItem( - * draftOrderId - * ) - * // ... - * - * const handleDelete = (itemId: string) => { - * deleteLineItem.mutate(itemId, { - * onSuccess: ({ draft_order }) => { - * console.log(draft_order.cart) - * } - * }) - * } - * - * // ... - * } - * - * export default DraftOrder - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/draft-orders/{id}/line-items/{line_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Draft Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDraftOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const { id, line_id } = req.params - - const draftOrderService: DraftOrderService = - req.scope.resolve("draftOrderService") - const cartService: CartService = req.scope.resolve("cartService") - const entityManager: EntityManager = req.scope.resolve("manager") - - await entityManager.transaction(async (manager) => { - const draftOrder: DraftOrder = await draftOrderService - .withTransaction(manager) - .retrieve(id, { select: defaultAdminDraftOrdersFields }) - - if (draftOrder.status === "completed") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "You are only allowed to update open draft orders" - ) - } - - await cartService - .withTransaction(manager) - .removeLineItem(draftOrder.cart_id, line_id) - - draftOrder.cart = await cartService - .withTransaction(manager) - .retrieveWithTotals(draftOrder.cart_id, { - relations: defaultAdminDraftOrdersCartRelations, - select: defaultAdminDraftOrdersCartFields, - }) - - 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 deleted file mode 100644 index 30b91b1535..0000000000 --- a/packages/medusa/src/api/routes/admin/draft-orders/get-draft-order.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { CartService, DraftOrderService } from "../../../../services" -import { - defaultAdminDraftOrdersCartFields, - defaultAdminDraftOrdersCartRelations, - defaultAdminDraftOrdersFields, - defaultAdminDraftOrdersRelations, -} from "." - -import { DraftOrder } from "../../../.." -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [get] /admin/draft-orders/{id} - * operationId: "GetDraftOrdersDraftOrder" - * summary: "Get a Draft Order" - * description: "Retrieve a Draft Order's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Draft Order. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.retrieve(draftOrderId) - * .then(({ draft_order }) => { - * console.log(draft_order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDraftOrder } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const { - * draft_order, - * isLoading, - * } = useAdminDraftOrder(draftOrderId) - * - * return ( - *
- * {isLoading && Loading...} - * {draft_order && {draft_order.display_id}} - * - *
- * ) - * } - * - * export default DraftOrder - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/draft-orders/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Draft Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDraftOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const { id } = req.params - - const draftOrderService: DraftOrderService = - req.scope.resolve("draftOrderService") - const cartService: CartService = req.scope.resolve("cartService") - - const draftOrder: DraftOrder = await draftOrderService.retrieve(id, { - select: defaultAdminDraftOrdersFields, - relations: defaultAdminDraftOrdersRelations, - }) - - draftOrder.cart = await cartService.retrieveWithTotals(draftOrder.cart_id, { - relations: defaultAdminDraftOrdersCartRelations, - select: defaultAdminDraftOrdersCartFields, - }) - - res.json({ - draft_order: cleanResponseData(draftOrder, []), - }) -} diff --git a/packages/medusa/src/api/routes/admin/draft-orders/index.ts b/packages/medusa/src/api/routes/admin/draft-orders/index.ts deleted file mode 100644 index 7defd39a91..0000000000 --- a/packages/medusa/src/api/routes/admin/draft-orders/index.ts +++ /dev/null @@ -1,259 +0,0 @@ -import { Router } from "express" -import { Cart, DraftOrder, Order } from "../../../.." -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import middlewares, { transformQuery } from "../../../middlewares" -import { AdminGetDraftOrdersParams } from "./list-draft-orders" - -const route = Router() - -export default (app) => { - app.use("/draft-orders", route) - - route.get( - "/", - transformQuery(AdminGetDraftOrdersParams, { - defaultFields: defaultAdminDraftOrdersFields, - defaultRelations: defaultAdminDraftOrdersRelations, - isList: true, - }), - middlewares.wrap(require("./list-draft-orders").default) - ) - - route.get("/:id", middlewares.wrap(require("./get-draft-order").default)) - - route.post("/", middlewares.wrap(require("./create-draft-order").default)) - - route.post("/:id", middlewares.wrap(require("./update-draft-order").default)) - - route.delete( - "/:id", - middlewares.wrap(require("./delete-draft-order").default) - ) - - route.delete( - "/:id/line-items/:line_id", - middlewares.wrap(require("./delete-line-item").default) - ) - - route.post( - "/:id/line-items", - middlewares.wrap(require("./create-line-item").default) - ) - - route.post( - "/:id/line-items/:line_id", - middlewares.wrap(require("./update-line-item").default) - ) - - route.post("/", middlewares.wrap(require("./create-draft-order").default)) - - route.post( - "/:id/pay", - middlewares.wrap(require("./register-payment").default) - ) - - return app -} - -export const defaultAdminDraftOrdersRelations = [ - "order", - "cart", - "cart.items", - "cart.items.adjustments", -] - -export const defaultAdminDraftOrdersCartRelations = [ - "region", - "items", - "items.adjustments", - "payment", - "shipping_address", - "shipping_address.country", - "billing_address", - "billing_address.country", - "region.payment_providers", - "shipping_methods", - "payment_sessions", - "shipping_methods.shipping_option", - "discounts", - "customer", - "discounts.rule", -] - -export const defaultAdminDraftOrdersCartFields: (keyof Cart)[] = [ - "subtotal", - "tax_total", - "shipping_total", - "discount_total", - "gift_card_total", - "total", -] - -export const defaultAdminDraftOrdersFields: (keyof DraftOrder)[] = [ - "id", - "status", - "display_id", - "cart_id", - "order_id", - "canceled_at", - "created_at", - "updated_at", - "metadata", - "no_notification_order", -] - -/** - * @schema AdminPostDraftOrdersDraftOrderRegisterPaymentRes - * type: object - * description: "The order's details." - * required: - * - order - * properties: - * order: - * description: Order's details. - * $ref: "#/components/schemas/Order" - */ -export type AdminPostDraftOrdersDraftOrderRegisterPaymentRes = { - order: Order -} -/** - * @schema AdminDraftOrdersRes - * type: object - * description: "The list of draft orders." - * x-expanded-relations: - * field: draft_order - * relations: - * - order - * - cart - * - cart.items - * - cart.items.adjustments - * - cart.billing_address - * - cart.customer - * - cart.discounts - * - cart.discounts.rule - * - cart.items - * - cart.items.adjustments - * - cart.payment - * - cart.payment_sessions - * - cart.region - * - cart.region.payment_providers - * - cart.shipping_address - * - cart.shipping_methods - * - cart.shipping_methods.shipping_option - * eager: - * - cart.region.fulfillment_providers - * - cart.region.payment_providers - * - cart.shipping_methods.shipping_option - * implicit: - * - cart.discounts - * - cart.discounts.rule - * - cart.gift_cards - * - cart.items - * - cart.items.adjustments - * - cart.items.tax_lines - * - cart.items.variant - * - cart.items.variant.product - * - cart.items.variant.product.profiles - * - cart.region - * - cart.region.tax_rates - * - cart.shipping_address - * - cart.shipping_methods - * - cart.shipping_methods.tax_lines - * totals: - * - cart.discount_total - * - cart.gift_card_tax_total - * - cart.gift_card_total - * - cart.item_tax_total - * - cart.refundable_amount - * - cart.refunded_total - * - cart.shipping_tax_total - * - cart.shipping_total - * - cart.subtotal - * - cart.tax_total - * - cart.total - * - cart.items.discount_total - * - cart.items.gift_card_total - * - cart.items.original_tax_total - * - cart.items.original_total - * - cart.items.refundable - * - cart.items.subtotal - * - cart.items.tax_total - * - cart.items.total - * required: - * - draft_order - * properties: - * draft_order: - * description: Draft order's details. - * $ref: "#/components/schemas/DraftOrder" - */ -export type AdminDraftOrdersRes = { - draft_order: DraftOrder -} - -/** - * @schema AdminDraftOrdersDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Draft Order. - * object: - * type: string - * description: The type of the object that was deleted. - * default: draft-order - * deleted: - * type: boolean - * description: Whether the draft order was deleted successfully. - * default: true - */ -export type AdminDraftOrdersDeleteRes = DeleteResponse - -/** - * @schema AdminDraftOrdersListRes - * description: "The list of draft orders with pagination fields." - * type: object - * x-expanded-relations: - * field: draft_orders - * relations: - * - order - * - cart - * - cart.items - * - cart.items.adjustments - * required: - * - draft_orders - * - count - * - offset - * - limit - * properties: - * draft_orders: - * type: array - * description: An array of draft order's details. - * items: - * $ref: "#/components/schemas/DraftOrder" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of draft orders skipped when retrieving the draft orders. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminDraftOrdersListRes = PaginatedResponse & { - draft_orders: DraftOrder[] -} - -export * from "./create-draft-order" -export * from "./create-line-item" -export * from "./delete-draft-order" -export * from "./delete-line-item" -export * from "./get-draft-order" -export * from "./list-draft-orders" -export * from "./register-payment" -export * from "./update-draft-order" -export * from "./update-line-item" diff --git a/packages/medusa/src/api/routes/admin/draft-orders/list-draft-orders.ts b/packages/medusa/src/api/routes/admin/draft-orders/list-draft-orders.ts deleted file mode 100644 index c92c4b38ab..0000000000 --- a/packages/medusa/src/api/routes/admin/draft-orders/list-draft-orders.ts +++ /dev/null @@ -1,228 +0,0 @@ -import { Type } from "class-transformer" -import { - IsArray, - IsEnum, - IsNumber, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { DraftOrderStatus } from "../../../../models" -import { DraftOrderService } from "../../../../services" -import { - DateComparisonOperator, - extendedFindParamsMixin, -} from "../../../../types/common" -import { DraftOrderStatusValue } from "../../../../types/draft-orders" - -/** - * @oas [get] /admin/draft-orders - * operationId: "GetDraftOrders" - * summary: "List Draft Orders" - * description: "Retrieve an list of Draft Orders. The draft orders can be filtered by fields such as `q`. The draft orders can also paginated." - * x-authenticated: true - * parameters: - * - (query) offset=0 {number} The number of draft orders to skip when retrieving the draft orders. - * - (query) limit=50 {number} Limit the number of draft orders returned. - * - (query) q {string} a term to search draft orders' display IDs and emails in the draft order's cart - * - (query) order {string} Field to sort retrieved draft orders by. - * - (query) expand {string} A comma-separated list of fields to expand. - * - (query) fields {string} A comma-separated list of fields to include in the response. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: status - * style: form - * explode: false - * description: Filter by status - * schema: - * type: array - * items: - * type: string - * enum: [open, completed] - * x-codegen: - * method: list - * queryParams: AdminGetDraftOrdersParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.list() - * .then(({ draft_orders, limit, offset, count }) => { - * console.log(draft_orders.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDraftOrders } from "medusa-react" - * - * const DraftOrders = () => { - * const { draft_orders, isLoading } = useAdminDraftOrders() - * - * return ( - *
- * {isLoading && Loading...} - * {draft_orders && !draft_orders.length && ( - * No Draft Orders - * )} - * {draft_orders && draft_orders.length > 0 && ( - *
    - * {draft_orders.map((order) => ( - *
  • {order.display_id}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default DraftOrders - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/draft-orders' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Draft Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDraftOrdersListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const draftOrderService: DraftOrderService = - req.scope.resolve("draftOrderService") - - const { skip, take } = req.listConfig - - const [draftOrders, count] = await draftOrderService.listAndCount( - req.filterableFields, - req.listConfig - ) - - res.json({ - draft_orders: draftOrders, - count, - offset: skip, - limit: take, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved draft orders. - */ -export class AdminGetDraftOrdersParams extends extendedFindParamsMixin({ - limit: 50, -}) { - /** - * Search term to search draft orders by their display IDs and emails. - */ - @IsString() - @IsOptional() - q?: string - - /** - * {@inheritDoc FindParams.expand} - */ - @IsOptional() - @IsString() - expand?: string - - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 50 - */ - @IsOptional() - @IsNumber() - fields?: string - - /** - * Statuses to filter draft orders by. - */ - @IsArray() - @IsEnum(DraftOrderStatus, { each: true }) - @IsOptional() - status?: DraftOrderStatusValue[] - - /** - * Date filters to apply on the draft orders' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the draft orders' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator -} 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 deleted file mode 100644 index 9724226521..0000000000 --- a/packages/medusa/src/api/routes/admin/draft-orders/register-payment.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { - CartService, - DraftOrderService, - OrderService, - PaymentProviderService, - ProductVariantInventoryService, -} from "../../../../services" -import { - defaultAdminOrdersFields as defaultOrderFields, - defaultAdminOrdersRelations as defaultOrderRelations, -} from "../../../../types/orders" - -import { EntityManager } from "typeorm" -import { MedusaError } from "medusa-core-utils" -import { Order } from "../../../../models" -import { cleanResponseData } from "../../../../utils/clean-response-data" -import { promiseAll } from "@medusajs/utils" - -/** - * @oas [post] /admin/draft-orders/{id}/pay - * summary: "Mark Paid" - * operationId: "PostDraftOrdersDraftOrderRegisterPayment" - * description: "Capture the draft order's payment. This will also set the draft order's status to `completed` and create an Order from the draft order. The payment is captured through Medusa's system payment, - * which is manual payment that isn't integrated with any third-party payment provider. It is assumed that the payment capturing is handled manually by the admin." - * x-authenticated: true - * parameters: - * - (path) id=* {String} The Draft Order ID. - * x-codegen: - * method: markPaid - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.markPaid(draftOrderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDraftOrderRegisterPayment } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const registerPayment = useAdminDraftOrderRegisterPayment( - * draftOrderId - * ) - * // ... - * - * const handlePayment = () => { - * registerPayment.mutate(void 0, { - * onSuccess: ({ order }) => { - * console.log(order.id) - * } - * }) - * } - * - * // ... - * } - * - * export default DraftOrder - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/draft-orders/{id}/pay' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Draft Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostDraftOrdersDraftOrderRegisterPaymentRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const { id } = req.params - - const draftOrderService: DraftOrderService = - req.scope.resolve("draftOrderService") - const paymentProviderService: PaymentProviderService = req.scope.resolve( - "paymentProviderService" - ) - const orderService: OrderService = req.scope.resolve("orderService") - const inventoryService: OrderService = req.scope.resolve("inventoryService") - const cartService: CartService = req.scope.resolve("cartService") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - const entityManager: EntityManager = req.scope.resolve("manager") - - const order = await entityManager.transaction(async (manager) => { - const draftOrderServiceTx = draftOrderService.withTransaction(manager) - const orderServiceTx = orderService.withTransaction(manager) - const cartServiceTx = cartService.withTransaction(manager) - - const draftOrder = await draftOrderServiceTx.retrieve(id) - - const cart = await cartServiceTx.retrieveWithTotals(draftOrder.cart_id) - - await paymentProviderService - .withTransaction(manager) - .createSession("system", cart) - - await cartServiceTx.setPaymentSession(cart.id, "system") - - await cartServiceTx.createTaxLines(cart.id) - - await cartServiceTx.authorizePayment(cart.id) - - let order = await orderServiceTx.createFromCart(cart.id) - - await draftOrderServiceTx.registerCartCompletion(draftOrder.id, order.id) - - await orderServiceTx.capturePayment(order.id) - - order = await orderService - .withTransaction(manager) - .retrieveWithTotals(order.id, { - relations: defaultOrderRelations, - select: defaultOrderFields, - }) - - return order - }) - - res.status(200).json({ order: cleanResponseData(order, []) }) -} - -export const reserveQuantityForDraftOrder = async ( - order: Order, - context: { - productVariantInventoryService: ProductVariantInventoryService - locationId?: string - } -) => { - const { productVariantInventoryService, locationId } = context - await promiseAll( - order.items.map(async (item) => { - if (item.variant_id) { - const inventoryConfirmed = - await productVariantInventoryService.confirmInventory( - item.variant_id, - item.quantity, - { salesChannelId: order.sales_channel_id } - ) - - if (!inventoryConfirmed) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Variant with id: ${item.variant_id} does not have the required inventory`, - MedusaError.Codes.INSUFFICIENT_INVENTORY - ) - } - - await productVariantInventoryService.reserveQuantity( - item.variant_id, - item.quantity, - { - lineItemId: item.id, - salesChannelId: order.sales_channel_id, - } - ) - } - }) - ) -} 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 deleted file mode 100644 index 54c87f3a09..0000000000 --- a/packages/medusa/src/api/routes/admin/draft-orders/update-draft-order.ts +++ /dev/null @@ -1,260 +0,0 @@ -import { Type } from "class-transformer" -import { - IsArray, - IsBoolean, - IsEmail, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { - defaultAdminDraftOrdersCartFields, - defaultAdminDraftOrdersCartRelations, -} from "." -import { DraftOrderStatus } from "../../../../models" -import { CartService, DraftOrderService } from "../../../../services" -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} - * operationId: PostDraftOrdersDraftOrder - * summary: Update a Draft Order - * description: "Update a Draft Order's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Draft Order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostDraftOrdersDraftOrderReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.update(draftOrderId, { - * email: "user@example.com" - * }) - * .then(({ draft_order }) => { - * console.log(draft_order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateDraftOrder } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const updateDraftOrder = useAdminUpdateDraftOrder( - * draftOrderId - * ) - * // ... - * - * const handleUpdate = (email: string) => { - * updateDraftOrder.mutate({ - * email, - * }, { - * onSuccess: ({ draft_order }) => { - * console.log(draft_order.id) - * } - * }) - * } - * - * // ... - * } - * - * export default DraftOrder - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/draft-orders/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Draft Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDraftOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const { id } = req.params - - const validated = await validator(AdminPostDraftOrdersDraftOrderReq, req.body) - - const draftOrderService: DraftOrderService = - req.scope.resolve("draftOrderService") - - const cartService: CartService = req.scope.resolve("cartService") - - const draftOrder = await draftOrderService.retrieve(id) - - if (draftOrder.status === DraftOrderStatus.COMPLETED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "You are only allowed to update open draft orders" - ) - } - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - if (validated.no_notification_order !== undefined) { - await draftOrderService - .withTransaction(transactionManager) - .update(draftOrder.id, { - no_notification_order: validated.no_notification_order, - }) - delete validated.no_notification_order - } - - const { shipping_address, billing_address, ...rest } = validated - - const cartDataToUpdate: CartUpdateProps = { ...rest } - - if (typeof shipping_address === "string") { - cartDataToUpdate.shipping_address_id = shipping_address - } else { - cartDataToUpdate.shipping_address = shipping_address - } - - if (typeof billing_address === "string") { - cartDataToUpdate.billing_address_id = billing_address - } else { - cartDataToUpdate.billing_address = billing_address - } - - await cartService.update(draftOrder.cart_id, cartDataToUpdate) - }) - - draftOrder.cart = await cartService.retrieveWithTotals(draftOrder.cart_id, { - relations: defaultAdminDraftOrdersCartRelations, - select: defaultAdminDraftOrdersCartFields, - }) - - res.status(200).json({ draft_order: cleanResponseData(draftOrder, []) }) -} - -/** - * @schema AdminPostDraftOrdersDraftOrderReq - * type: object - * description: "The details of the draft order to update." - * properties: - * region_id: - * type: string - * description: The ID of the Region to create the Draft Order in. - * country_code: - * type: string - * description: "The 2 character ISO code for the Country." - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements - * description: See a list of codes. - * email: - * type: string - * description: "An email to be used in the Draft Order." - * format: email - * billing_address: - * description: "The Address to be used for billing purposes." - * anyOf: - * - $ref: "#/components/schemas/AddressPayload" - * - type: string - * shipping_address: - * description: "The Address to be used for shipping purposes." - * anyOf: - * - $ref: "#/components/schemas/AddressPayload" - * - type: string - * discounts: - * description: "An array of Discount codes to add to the Draft Order." - * type: array - * items: - * type: object - * required: - * - code - * properties: - * code: - * description: "The code that a Discount is identifed by." - * type: string - * no_notification_order: - * description: "An optional flag passed to the resulting order that indicates whether the customer should receive notifications about order updates." - * type: boolean - * customer_id: - * description: "The ID of the customer this draft order is associated with." - * type: string - */ -export class AdminPostDraftOrdersDraftOrderReq { - @IsString() - @IsOptional() - region_id?: string - - @IsString() - @IsOptional() - country_code?: string - - @IsEmail() - @IsOptional() - email?: string - - @IsOptional() - @IsType([AddressPayload, String]) - billing_address?: AddressPayload | string - - @IsOptional() - @IsType([AddressPayload, String]) - shipping_address?: AddressPayload | string - - @IsArray() - @IsOptional() - @Type(() => Discount) - @ValidateNested({ each: true }) - discounts?: Discount[] - - @IsString() - @IsOptional() - customer_id?: string - - @IsBoolean() - @IsOptional() - no_notification_order?: boolean -} - -class Discount { - @IsString() - code: string -} 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 deleted file mode 100644 index 977bd17997..0000000000 --- a/packages/medusa/src/api/routes/admin/draft-orders/update-line-item.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { CartService, DraftOrderService } from "../../../../services" -import { IsInt, IsObject, IsOptional, IsString } from "class-validator" -import { - defaultAdminDraftOrdersCartFields, - defaultAdminDraftOrdersCartRelations, - defaultAdminDraftOrdersFields, -} from "." - -import { DraftOrder } from "../../../.." -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} - * operationId: "PostDraftOrdersDraftOrderLineItemsItem" - * summary: "Update a Line Item" - * description: "Update a Line Item in a Draft Order." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Draft Order. - * - (path) line_id=* {string} The ID of the Line Item. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostDraftOrdersDraftOrderLineItemsItemReq" - * x-codegen: - * method: updateLineItem - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.draftOrders.updateLineItem(draftOrderId, lineId, { - * quantity: 1 - * }) - * .then(({ draft_order }) => { - * console.log(draft_order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDraftOrderUpdateLineItem } from "medusa-react" - * - * type Props = { - * draftOrderId: string - * } - * - * const DraftOrder = ({ draftOrderId }: Props) => { - * const updateLineItem = useAdminDraftOrderUpdateLineItem( - * draftOrderId - * ) - * // ... - * - * const handleUpdate = ( - * itemId: string, - * quantity: number - * ) => { - * updateLineItem.mutate({ - * item_id: itemId, - * quantity, - * }) - * } - * - * // ... - * } - * - * export default DraftOrder - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/draft-orders/{id}/line-items/{line_id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "quantity": 1 - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Draft Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDraftOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const { id, line_id } = req.params - - const validated = await validator( - AdminPostDraftOrdersDraftOrderLineItemsItemReq, - req.body - ) - - const draftOrderService: DraftOrderService = - req.scope.resolve("draftOrderService") - const cartService: CartService = req.scope.resolve("cartService") - const entityManager: EntityManager = req.scope.resolve("manager") - - await entityManager.transaction(async (manager) => { - const draftOrder: DraftOrder = await draftOrderService - .withTransaction(manager) - .retrieve(id, { - select: defaultAdminDraftOrdersFields, - relations: ["cart", "cart.items"], - }) - - if (draftOrder.status === "completed") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "You are only allowed to update open draft orders" - ) - } - - if (validated.quantity === 0) { - await cartService - .withTransaction(manager) - .removeLineItem(draftOrder.cart.id, line_id) - } else { - const existing = draftOrder.cart.items.find((i) => i.id === line_id) - - if (!existing) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Could not find the line item" - ) - } - - const lineItemUpdate: LineItemUpdate = { - ...validated, - region_id: draftOrder.cart.region_id, - } - - if (existing.variant_id) { - lineItemUpdate.variant_id = existing.variant_id - } - - await cartService - .withTransaction(manager) - .updateLineItem(draftOrder.cart_id, line_id, lineItemUpdate) - } - - draftOrder.cart = await cartService - .withTransaction(manager) - .retrieveWithTotals(draftOrder.cart_id, { - relations: defaultAdminDraftOrdersCartRelations, - select: defaultAdminDraftOrdersCartFields, - }) - - res.status(200).json({ - draft_order: cleanResponseData(draftOrder, []), - }) - }) -} - -/** - * @schema AdminPostDraftOrdersDraftOrderLineItemsItemReq - * type: object - * description: "The details to update of the line item." - * properties: - * unit_price: - * description: The custom price of the line item. If a `variant_id` is supplied, the price provided here will override the variant's price. - * type: integer - * title: - * description: The title of the line item if `variant_id` is not provided. - * type: string - * quantity: - * description: The quantity of the line item. - * type: integer - * metadata: - * description: The optional key-value map with additional details about the Line Item. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostDraftOrdersDraftOrderLineItemsItemReq { - @IsString() - @IsOptional() - title?: string - - @IsInt() - @IsOptional() - unit_price?: number - - @IsInt() - @IsOptional() - quantity?: number - - @IsObject() - @IsOptional() - metadata?: Record = {} -} diff --git a/packages/medusa/src/api/routes/admin/gift-cards/create-gift-card.ts b/packages/medusa/src/api/routes/admin/gift-cards/create-gift-card.ts deleted file mode 100644 index a796e1ea89..0000000000 --- a/packages/medusa/src/api/routes/admin/gift-cards/create-gift-card.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { IsBoolean, IsDate, IsInt, IsOptional, IsString } from "class-validator" -import { defaultAdminGiftCardFields, defaultAdminGiftCardRelations } from "." - -import { GiftCardService } from "../../../../services" -import { Type } from "class-transformer" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/gift-cards - * operationId: "PostGiftCards" - * summary: "Create a Gift Card" - * description: "Create a Gift Card that can redeemed by its unique code. The Gift Card is only valid within 1 region." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostGiftCardsReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.giftCards.create({ - * region_id - * }) - * .then(({ gift_card }) => { - * console.log(gift_card.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateGiftCard } from "medusa-react" - * - * const CreateCustomGiftCards = () => { - * const createGiftCard = useAdminCreateGiftCard() - * // ... - * - * const handleCreate = ( - * regionId: string, - * value: number - * ) => { - * createGiftCard.mutate({ - * region_id: regionId, - * value, - * }, { - * onSuccess: ({ gift_card }) => { - * console.log(gift_card.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateCustomGiftCards - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/gift-cards' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "region_id": "{region_id}" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Gift Cards - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminGiftCardsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validatedBody: AdminPostGiftCardsReq & { balance?: number } = - req.validatedBody - validatedBody.balance = validatedBody.value - - const giftCardService: GiftCardService = req.scope.resolve("giftCardService") - const manager: EntityManager = req.scope.resolve("manager") - const newly = await manager.transaction(async (transactionManager) => { - return await giftCardService - .withTransaction(transactionManager) - .create(validatedBody) - }) - - const giftCard = await giftCardService.retrieve(newly.id, { - select: defaultAdminGiftCardFields, - relations: defaultAdminGiftCardRelations, - }) - - res.status(200).json({ gift_card: giftCard }) -} - -/** - * @schema AdminPostGiftCardsReq - * type: object - * description: "The details of the gift card to create." - * required: - * - region_id - * properties: - * value: - * type: integer - * description: The value (excluding VAT) that the Gift Card should represent. - * is_disabled: - * type: boolean - * description: >- - * Whether the Gift Card is disabled on creation. If set to `true`, the gift card will not be available for customers. - * ends_at: - * type: string - * format: date-time - * description: The date and time at which the Gift Card should no longer be available. - * region_id: - * description: The ID of the Region in which the Gift Card can be used. - * type: string - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostGiftCardsReq { - @IsOptional() - @IsInt() - value?: number - - @IsOptional() - @IsDate() - @Type(() => Date) - ends_at?: Date - - @IsOptional() - @IsBoolean() - is_disabled?: boolean - - @IsString() - region_id: string - - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/gift-cards/delete-gift-card.ts b/packages/medusa/src/api/routes/admin/gift-cards/delete-gift-card.ts deleted file mode 100644 index 0ccbd896a2..0000000000 --- a/packages/medusa/src/api/routes/admin/gift-cards/delete-gift-card.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { EntityManager } from "typeorm" - -/** - * @oas [delete] /admin/gift-cards/{id} - * operationId: "DeleteGiftCardsGiftCard" - * summary: "Delete a Gift Card" - * description: "Delete a Gift Card. Once deleted, it can't be used by customers." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Gift Card to delete. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.giftCards.delete(giftCardId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteGiftCard } from "medusa-react" - * - * type Props = { - * customGiftCardId: string - * } - * - * const CustomGiftCard = ({ customGiftCardId }: Props) => { - * const deleteGiftCard = useAdminDeleteGiftCard( - * customGiftCardId - * ) - * // ... - * - * const handleDelete = () => { - * deleteGiftCard.mutate(void 0, { - * onSuccess: ({ id, object, deleted}) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default CustomGiftCard - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/gift-cards/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Gift Cards - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminGiftCardsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const giftCardService = req.scope.resolve("giftCardService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await giftCardService.withTransaction(transactionManager).delete(id) - }) - - res.json({ - id, - object: "gift-card", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/gift-cards/get-gift-card.ts b/packages/medusa/src/api/routes/admin/gift-cards/get-gift-card.ts deleted file mode 100644 index 336eff95b3..0000000000 --- a/packages/medusa/src/api/routes/admin/gift-cards/get-gift-card.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { defaultAdminGiftCardFields, defaultAdminGiftCardRelations } from "./" - -/** - * @oas [get] /admin/gift-cards/{id} - * operationId: "GetGiftCardsGiftCard" - * summary: "Get a Gift Card" - * description: "Retrieve a Gift Card's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Gift Card. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.giftCards.retrieve(giftCardId) - * .then(({ gift_card }) => { - * console.log(gift_card.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminGiftCard } from "medusa-react" - * - * type Props = { - * giftCardId: string - * } - * - * const CustomGiftCard = ({ giftCardId }: Props) => { - * const { gift_card, isLoading } = useAdminGiftCard(giftCardId) - * - * return ( - *
- * {isLoading && Loading...} - * {gift_card && {gift_card.code}} - *
- * ) - * } - * - * export default CustomGiftCard - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/gift-cards/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Gift Cards - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminGiftCardsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const giftCardService = req.scope.resolve("giftCardService") - const giftCard = await giftCardService.retrieve(id, { - select: defaultAdminGiftCardFields, - relations: defaultAdminGiftCardRelations, - }) - - res.status(200).json({ gift_card: giftCard }) -} diff --git a/packages/medusa/src/api/routes/admin/gift-cards/index.ts b/packages/medusa/src/api/routes/admin/gift-cards/index.ts deleted file mode 100644 index ef9da8a05d..0000000000 --- a/packages/medusa/src/api/routes/admin/gift-cards/index.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { Router } from "express" -import "reflect-metadata" -import { GiftCard } from "../../../.." -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" -import { AdminGetGiftCardsParams } from "./list-gift-cards" -import { AdminPostGiftCardsReq } from "./create-gift-card" - -const route = Router() - -export default (app) => { - app.use("/gift-cards", route) - - route.get( - "/", - transformQuery(AdminGetGiftCardsParams, { - defaultFields: defaultAdminGiftCardFields, - defaultRelations: defaultAdminGiftCardRelations, - isList: true, - }), - middlewares.wrap(require("./list-gift-cards").default) - ) - - route.post( - "/", - transformBody(AdminPostGiftCardsReq), - middlewares.wrap(require("./create-gift-card").default) - ) - - route.get("/:id", middlewares.wrap(require("./get-gift-card").default)) - - route.post("/:id", middlewares.wrap(require("./update-gift-card").default)) - - route.delete("/:id", middlewares.wrap(require("./delete-gift-card").default)) - - return app -} - -export const defaultAdminGiftCardFields: (keyof GiftCard)[] = [ - "id", - "code", - "value", - "balance", - "region_id", - "is_disabled", - "ends_at", - "tax_rate", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -export const defaultAdminGiftCardRelations = ["region", "order"] - -/** - * @schema AdminGiftCardsRes - * type: object - * description: "The gift card's details." - * x-expanded-relations: - * field: gift_card - * relations: - * - order - * - region - * eager: - * - region.fulfillment_providers - * - region.payment_providers - * required: - * - gift_card - * properties: - * gift_card: - * description: "A gift card's details." - * $ref: "#/components/schemas/GiftCard" - */ -export type AdminGiftCardsRes = { - gift_card: GiftCard -} - -/** - * @schema AdminGiftCardsDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Gift Card - * object: - * type: string - * description: The type of the object that was deleted. - * default: gift-card - * deleted: - * type: boolean - * description: Whether the gift card was deleted successfully. - * default: true - */ -export type AdminGiftCardsDeleteRes = DeleteResponse - -/** - * @schema AdminGiftCardsListRes - * type: object - * description: "The list of gift cards with pagination fields." - * x-expanded-relations: - * field: gift_cards - * relations: - * - order - * - region - * eager: - * - region.fulfillment_providers - * - region.payment_providers - * required: - * - gift_cards - * - count - * - offset - * - limit - * properties: - * gift_cards: - * type: array - * description: "The list of gift cards." - * items: - * $ref: "#/components/schemas/GiftCard" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of gift cards skipped when retrieving the gift cards. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminGiftCardsListRes = PaginatedResponse & { - gift_cards: GiftCard[] -} - -export * from "./create-gift-card" -export * from "./list-gift-cards" -export * from "./update-gift-card" diff --git a/packages/medusa/src/api/routes/admin/gift-cards/list-gift-cards.ts b/packages/medusa/src/api/routes/admin/gift-cards/list-gift-cards.ts deleted file mode 100644 index 1ef305856b..0000000000 --- a/packages/medusa/src/api/routes/admin/gift-cards/list-gift-cards.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { IsInt, IsOptional, IsString } from "class-validator" - -import { Type } from "class-transformer" -import { pickBy } from "lodash" -import { isDefined } from "medusa-core-utils" -import { GiftCardService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [get] /admin/gift-cards - * operationId: "GetGiftCards" - * summary: "List Gift Cards" - * description: "Retrieve a list of Gift Cards. The gift cards can be filtered by fields such as `q`. The gift cards can also paginated." - * x-authenticated: true - * parameters: - * - (query) offset=0 {number} The number of gift cards to skip when retrieving the gift cards. - * - (query) limit=50 {number} Limit the number of gift cards returned. - * - (query) q {string} a term to search gift cards' code or display ID - * - (query) order {string} A gift card field to sort-order the retrieved gift cards by. - * x-codegen: - * method: list - * queryParams: AdminGetGiftCardsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.giftCards.list() - * .then(({ gift_cards, limit, offset, count }) => { - * console.log(gift_cards.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { GiftCard } from "@medusajs/medusa" - * import { useAdminGiftCards } from "medusa-react" - * - * const CustomGiftCards = () => { - * const { gift_cards, isLoading } = useAdminGiftCards() - * - * return ( - *
- * {isLoading && Loading...} - * {gift_cards && !gift_cards.length && ( - * No custom gift cards... - * )} - * {gift_cards && gift_cards.length > 0 && ( - *
    - * {gift_cards.map((giftCard: GiftCard) => ( - *
  • {giftCard.code}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default CustomGiftCards - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/gift-cards' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Gift Cards - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminGiftCardsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminGetGiftCardsParams, req.query) - - const giftCardService: GiftCardService = req.scope.resolve("giftCardService") - - const [giftCards, count] = await giftCardService.listAndCount( - pickBy(req.filterableFields, (val) => isDefined(val)), - req.listConfig - ) - - res.status(200).json({ - gift_cards: giftCards, - count, - offset: validated.offset, - limit: validated.limit, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved gift cards. - */ -export class AdminGetGiftCardsParams { - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 50 - */ - @IsOptional() - @IsInt() - @Type(() => Number) - limit = 50 - - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsOptional() - @IsInt() - @Type(() => Number) - offset = 0 - - /** - * Search term to search gift cards by their code and display ID. - */ - @IsOptional() - @IsString() - q?: string - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsOptional() - @IsString() - order?: string -} diff --git a/packages/medusa/src/api/routes/admin/gift-cards/update-gift-card.ts b/packages/medusa/src/api/routes/admin/gift-cards/update-gift-card.ts deleted file mode 100644 index 5a0fc6ee6a..0000000000 --- a/packages/medusa/src/api/routes/admin/gift-cards/update-gift-card.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { IsBoolean, IsDate, IsInt, IsOptional, IsString } from "class-validator" -import { defaultAdminGiftCardFields, defaultAdminGiftCardRelations } from "." - -import { Type } from "class-transformer" -import { EntityManager } from "typeorm" -import { GiftCardService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/gift-cards/{id} - * operationId: "PostGiftCardsGiftCard" - * summary: "Update a Gift Card" - * description: "Update a Gift Card's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Gift Card. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostGiftCardsGiftCardReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.giftCards.update(giftCardId, { - * region_id - * }) - * .then(({ gift_card }) => { - * console.log(gift_card.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateGiftCard } from "medusa-react" - * - * type Props = { - * customGiftCardId: string - * } - * - * const CustomGiftCard = ({ customGiftCardId }: Props) => { - * const updateGiftCard = useAdminUpdateGiftCard( - * customGiftCardId - * ) - * // ... - * - * const handleUpdate = (regionId: string) => { - * updateGiftCard.mutate({ - * region_id: regionId, - * }, { - * onSuccess: ({ gift_card }) => { - * console.log(gift_card.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CustomGiftCard - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/gift-cards/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "region_id": "{region_id}" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Gift Cards - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminGiftCardsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = await validator(AdminPostGiftCardsGiftCardReq, req.body) - - const giftCardService: GiftCardService = req.scope.resolve("giftCardService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await giftCardService - .withTransaction(transactionManager) - .update(id, validated) - }) - - const giftCard = await giftCardService.retrieve(id, { - select: defaultAdminGiftCardFields, - relations: defaultAdminGiftCardRelations, - }) - - res.status(200).json({ gift_card: giftCard }) -} - -/** - * @schema AdminPostGiftCardsGiftCardReq - * type: object - * description: "The details to update of the gift card." - * properties: - * balance: - * type: integer - * description: The value (excluding VAT) that the Gift Card should represent. - * is_disabled: - * type: boolean - * description: >- - * Whether the Gift Card is disabled on creation. If set to `true`, the gift card will not be available for customers. - * ends_at: - * type: string - * format: date-time - * description: The date and time at which the Gift Card should no longer be available. - * region_id: - * description: The ID of the Region in which the Gift Card can be used. - * type: string - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostGiftCardsGiftCardReq { - @IsOptional() - @IsInt() - balance?: number - - @IsOptional() - @IsBoolean() - is_disabled?: boolean - - @IsOptional() - @IsDate() - @Type(() => Date) - ends_at?: Date | null - - @IsOptional() - @IsString() - region_id?: string - - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/index.js b/packages/medusa/src/api/routes/admin/index.js deleted file mode 100644 index dc4ed7dfc5..0000000000 --- a/packages/medusa/src/api/routes/admin/index.js +++ /dev/null @@ -1,122 +0,0 @@ -import cors from "cors" -import { Router } from "express" -import { parseCorsOrigins } from "medusa-core-utils" -import middlewares from "../../middlewares" -import analyticsConfigs from "./analytics-configs" -import appRoutes from "./apps" -import authRoutes from "./auth" -import batchRoutes from "./batch" -import collectionRoutes from "./collections" -import currencyRoutes from "./currencies" -import customerGroupRoutes from "./customer-groups" -import customerRoutes from "./customers" -import discountRoutes from "./discounts" -import draftOrderRoutes from "./draft-orders" -import giftCardRoutes from "./gift-cards" -import inventoryItemRoutes from "./inventory-items" -import inviteRoutes, { unauthenticatedInviteRoutes } from "./invites" -import noteRoutes from "./notes" -import notificationRoutes from "./notifications" -import orderEditRoutes from "./order-edits" -import orderRoutes from "./orders" -import paymentCollectionRoutes from "./payment-collections" -import paymentRoutes from "./payments" -import priceListRoutes from "./price-lists" -import productCategoryRoutes from "./product-categories" -import productTagRoutes from "./product-tags" -import productTypesRoutes from "./product-types" -import productRoutes from "./products" -import publishableApiKeyRoutes from "./publishable-api-keys" -import regionRoutes from "./regions" -import reservationRoutes from "./reservations" -import returnReasonRoutes from "./return-reasons" -import returnRoutes from "./returns" -import salesChannelRoutes from "./sales-channels" -import shippingOptionRoutes from "./shipping-options" -import shippingProfileRoutes from "./shipping-profiles" -import stockLocationRoutes from "./stock-locations" -import storeRoutes from "./store" -import swapRoutes from "./swaps" -import taxRateRoutes from "./tax-rates" -import uploadRoutes from "./uploads" -import userRoutes, { unauthenticatedUserRoutes } from "./users" -import variantRoutes from "./variants" -import workflowRoutes from "./workflows-executions" - -const route = Router() - -export default (app, container, config) => { - app.use("/admin", route) - - const adminCors = config.admin_cors || "" - route.use( - cors({ - origin: parseCorsOrigins(adminCors), - credentials: true, - }) - ) - - const featureFlagRouter = container.resolve("featureFlagRouter") - - // Unauthenticated routes - authRoutes(route) - - // reset password - unauthenticatedUserRoutes(route) - - // accept invite - unauthenticatedInviteRoutes(route) - - const middlewareService = container.resolve("middlewareService") - // Calls all middleware that has been registered to run before authentication. - middlewareService.usePreAuthentication(app) - - // Authenticated routes - route.use(middlewares.authenticate()) - - // Calls all middleware that has been registered to run after authentication. - middlewareService.usePostAuthentication(app) - - analyticsConfigs(route) - appRoutes(route) - batchRoutes(route) - collectionRoutes(route) - customerGroupRoutes(route) - customerRoutes(route) - currencyRoutes(route) - discountRoutes(route) - draftOrderRoutes(route) - giftCardRoutes(route) - inventoryItemRoutes(route) - inviteRoutes(route) - noteRoutes(route) - notificationRoutes(route) - orderRoutes(route, featureFlagRouter) - orderEditRoutes(route) - priceListRoutes(route, featureFlagRouter) - productRoutes(route, featureFlagRouter) - productTagRoutes(route) - productTypesRoutes(route) - publishableApiKeyRoutes(route) - regionRoutes(route, featureFlagRouter) - reservationRoutes(route) - returnReasonRoutes(route) - returnRoutes(route) - reservationRoutes(route) - salesChannelRoutes(route) - shippingOptionRoutes(route, featureFlagRouter) - shippingProfileRoutes(route) - stockLocationRoutes(route) - storeRoutes(route) - swapRoutes(route) - taxRateRoutes(route) - uploadRoutes(route) - userRoutes(route) - variantRoutes(route) - paymentCollectionRoutes(route) - paymentRoutes(route) - productCategoryRoutes(route) - workflowRoutes(route) - - return app -} diff --git a/packages/medusa/src/api/routes/admin/inventory-items/create-inventory-item.ts b/packages/medusa/src/api/routes/admin/inventory-items/create-inventory-item.ts deleted file mode 100644 index 7b67fe9473..0000000000 --- a/packages/medusa/src/api/routes/admin/inventory-items/create-inventory-item.ts +++ /dev/null @@ -1,340 +0,0 @@ -import { - FlagRouter, - ManyToManyInventoryFeatureFlag, - MedusaError, -} from "@medusajs/utils" -import { IsNumber, IsObject, IsOptional, IsString } from "class-validator" -import { - CreateInventoryItemActions, - createInventoryItems, -} from "@medusajs/core-flows" -import { pipe } from "@medusajs/workflows-sdk" -import { ProductVariantInventoryService } from "../../../../services" - -import { FindParams } from "../../../../types/common" - -/** - * @oas [post] /admin/inventory-items - * operationId: "PostInventoryItems" - * summary: "Create an Inventory Item" - * description: "Create an Inventory Item for a product variant." - * x-authenticated: true - * parameters: - * - (query) expand {string} Comma-separated relations that should be expanded in the returned inventory item. - * - (query) fields {string} Comma-separated fields that should be included in the returned inventory item. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostInventoryItemsReq" - * x-codegen: - * method: create - * queryParams: AdminPostInventoryItemsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.create({ - * variant_id: "variant_123", - * }) - * .then(({ inventory_item }) => { - * console.log(inventory_item.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateInventoryItem } from "medusa-react" - * - * const CreateInventoryItem = () => { - * const createInventoryItem = useAdminCreateInventoryItem() - * // ... - * - * const handleCreate = (variantId: string) => { - * createInventoryItem.mutate({ - * variant_id: variantId, - * }, { - * onSuccess: ({ inventory_item }) => { - * console.log(inventory_item.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateInventoryItem - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/inventory-items' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "variant_id": "variant_123", - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Inventory Items - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminInventoryItemsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const { variant_id, ...inventoryItemInput } = req.validatedBody - - const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - const createInventoryItemWorkflow = createInventoryItems(req.scope) - - if (!featureFlagRouter.isFeatureEnabled(ManyToManyInventoryFeatureFlag.key)) { - if (!variant_id) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "variant_id is required" - ) - } - - createInventoryItemWorkflow.appendAction( - "attachInventoryItems", - CreateInventoryItemActions.createInventoryItems, - { - invoke: pipe( - { - invoke: { - from: CreateInventoryItemActions.createInventoryItems, - alias: "createdItems", - }, - }, - generateAttachInventoryToVariantHandler( - variant_id, - productVariantInventoryService - ) - ), - compensate: pipe( - { - invoke: { - from: "attachInventoryItems", - alias: "attachedItems", - }, - }, - generateDetachInventoryItemFromVariantHandler( - productVariantInventoryService - ) - ), - } - ) - } - - const { result } = await createInventoryItemWorkflow.run({ - input: { - inventoryItems: [inventoryItemInput], - }, - }) - - res.status(200).json({ inventory_item: result[0].inventoryItem }) -} - -function generateDetachInventoryItemFromVariantHandler( - productVariantInventoryService: ProductVariantInventoryService -) { - return async ({ data }) => { - if (!data.attachedItems || !data.attachedItems.length) { - return - } - - const [variantId, inventoryItemId] = data.attachedItems - if (!variantId || !inventoryItemId) { - return - } - - return await productVariantInventoryService.detachInventoryItem( - inventoryItemId, - variantId - ) - } -} - -function generateAttachInventoryToVariantHandler( - variantId: string, - productVariantInventoryService: ProductVariantInventoryService -) { - return async ({ data }) => { - const inventoryItems = await productVariantInventoryService.listByVariant( - variantId - ) - - // TODO: this is a temporary fix to prevent duplicate inventory - // items since we don't support this functionality yet - if (inventoryItems.length) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Inventory Item already exists for this variant" - ) - } - const inventoryItemId = data.createdItems[0].inventoryItem.id - await productVariantInventoryService.attachInventoryItem( - variantId, - inventoryItemId - ) - return [variantId, inventoryItemId] - } -} - -/** - * @schema AdminPostInventoryItemsReq - * type: object - * description: "The details of the inventory item to create." - * required: - * - variant_id - * properties: - * variant_id: - * description: The ID of the variant to create the inventory item for. - * type: string - * sku: - * description: The unique SKU of the associated Product Variant. - * type: string - * ean: - * description: The EAN number of the item. - * type: string - * upc: - * description: The UPC number of the item. - * type: string - * barcode: - * description: A generic GTIN field for the Product Variant. - * type: string - * hs_code: - * description: The Harmonized System code of the Inventory Item. May be used by Fulfillment Providers to pass customs information to shipping carriers. - * type: string - * inventory_quantity: - * description: The amount of stock kept of the associated Product Variant. - * type: integer - * default: 0 - * allow_backorder: - * description: Whether the associated Product Variant can be purchased when out of stock. - * type: boolean - * manage_inventory: - * description: Whether Medusa should keep track of the inventory for the associated Product Variant. - * type: boolean - * default: true - * weight: - * description: The weight of the Inventory Item. May be used in shipping rate calculations. - * type: number - * length: - * description: The length of the Inventory Item. May be used in shipping rate calculations. - * type: number - * height: - * description: The height of the Inventory Item. May be used in shipping rate calculations. - * type: number - * width: - * description: The width of the Inventory Item. May be used in shipping rate calculations. - * type: number - * origin_country: - * description: The country in which the Inventory Item was produced. May be used by Fulfillment Providers to pass customs information to shipping carriers. - * type: string - * mid_code: - * description: The Manufacturers Identification code that identifies the manufacturer of the Inventory Item. May be used by Fulfillment Providers to pass customs information to shipping carriers. - * type: string - * material: - * description: The material and composition that the Inventory Item is made of, May be used by Fulfillment Providers to pass customs information to shipping carriers. - * type: string - * title: - * description: The inventory item's title. - * type: string - * description: - * description: The inventory item's description. - * type: string - * thumbnail: - * description: The inventory item's thumbnail. - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostInventoryItemsReq { - @IsOptional() - @IsString() - variant_id: string - - @IsString() - @IsOptional() - sku?: string - - @IsString() - @IsOptional() - hs_code?: string - - @IsNumber() - @IsOptional() - weight?: number - - @IsNumber() - @IsOptional() - length?: number - - @IsNumber() - @IsOptional() - height?: number - - @IsNumber() - @IsOptional() - width?: number - - @IsString() - @IsOptional() - origin_country?: string - - @IsString() - @IsOptional() - mid_code?: string - - @IsString() - @IsOptional() - material?: string - - @IsString() - @IsOptional() - title?: string - - @IsString() - @IsOptional() - description?: string - - @IsString() - @IsOptional() - thumbnail?: string - - @IsObject() - @IsOptional() - metadata?: Record -} - -export class AdminPostInventoryItemsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/inventory-items/create-location-level.ts b/packages/medusa/src/api/routes/admin/inventory-items/create-location-level.ts deleted file mode 100644 index 7f48b54abb..0000000000 --- a/packages/medusa/src/api/routes/admin/inventory-items/create-location-level.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { IInventoryService, IStockLocationService } from "@medusajs/types" -import { IsNumber, IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" -import { FindParams } from "../../../../types/common" - -/** - * @oas [post] /admin/inventory-items/{id}/location-levels - * operationId: "PostInventoryItemsInventoryItemLocationLevels" - * summary: "Create a Location Level" - * description: "Create a Location Level for a given Inventory Item." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Inventory Item. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned inventory item. - * - (query) fields {string} Comma-separated fields that should be included in the returned inventory item. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostInventoryItemsItemLocationLevelsReq" - * x-codegen: - * method: createLocationLevel - * queryParams: AdminPostInventoryItemsItemLocationLevelsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.createLocationLevel(inventoryItemId, { - * location_id: "sloc_123", - * stocked_quantity: 10, - * }) - * .then(({ inventory_item }) => { - * console.log(inventory_item.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateLocationLevel } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const createLocationLevel = useAdminCreateLocationLevel( - * inventoryItemId - * ) - * // ... - * - * const handleCreateLocationLevel = ( - * locationId: string, - * stockedQuantity: number - * ) => { - * createLocationLevel.mutate({ - * location_id: locationId, - * stocked_quantity: stockedQuantity, - * }, { - * onSuccess: ({ inventory_item }) => { - * console.log(inventory_item.id) - * } - * }) - * } - * - * // ... - * } - * - * export default InventoryItem - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/inventory-items/{id}/location-levels' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "location_id": "sloc_123", - * "stocked_quantity": 10 - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Inventory Items - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminInventoryItemsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - - const stockLocationService: IStockLocationService | undefined = - req.scope.resolve("stockLocationService") - - const validatedBody = - req.validatedBody as AdminPostInventoryItemsItemLocationLevelsReq - - const location_id = validatedBody.location_id - if (stockLocationService) { - // will throw an error if not found - await stockLocationService.retrieve(location_id) - } - - await inventoryService.createInventoryLevel({ - inventory_item_id: id, - location_id, - stocked_quantity: validatedBody.stocked_quantity, - incoming_quantity: validatedBody.incoming_quantity, - }) - - const inventoryItem = await inventoryService.retrieveInventoryItem( - id, - req.retrieveConfig - ) - - res.status(200).json({ inventory_item: inventoryItem }) -} - -/** - * @schema AdminPostInventoryItemsItemLocationLevelsReq - * type: object - * description: "The details of the location level to create." - * required: - * - location_id - * - stocked_quantity - * properties: - * location_id: - * description: the ID of the stock location - * type: string - * stocked_quantity: - * description: the stock quantity of the inventory item at this location - * type: number - * incoming_quantity: - * description: the incoming stock quantity of the inventory item at this location - * type: number - */ -export class AdminPostInventoryItemsItemLocationLevelsReq { - @IsString() - location_id: string - - @IsNumber() - stocked_quantity: number - - @IsOptional() - @IsNumber() - incoming_quantity?: number -} - -// eslint-disable-next-line -export class AdminPostInventoryItemsItemLocationLevelsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/inventory-items/delete-inventory-item.ts b/packages/medusa/src/api/routes/admin/inventory-items/delete-inventory-item.ts deleted file mode 100644 index df439c5eea..0000000000 --- a/packages/medusa/src/api/routes/admin/inventory-items/delete-inventory-item.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { IInventoryService } from "@medusajs/types" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { ProductVariantInventoryService } from "../../../../services" - -/** - * @oas [delete] /admin/inventory-items/{id} - * operationId: "DeleteInventoryItemsInventoryItem" - * summary: "Delete an Inventory Item" - * description: "Delete an Inventory Item. This does not delete the associated product variant." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Inventory Item to delete. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.delete(inventoryItemId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteInventoryItem } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const deleteInventoryItem = useAdminDeleteInventoryItem( - * inventoryItemId - * ) - * // ... - * - * const handleDelete = () => { - * deleteInventoryItem.mutate() - * } - * - * // ... - * } - * - * export default InventoryItem - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/inventory-items/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Inventory Items - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminInventoryItemsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - await productVariantInventoryService - .withTransaction(transactionManager) - .detachInventoryItem(id) - - await inventoryService.deleteInventoryItem(id) - }) - - res.status(200).send({ - id, - object: "inventory_item", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/inventory-items/delete-location-level.ts b/packages/medusa/src/api/routes/admin/inventory-items/delete-location-level.ts deleted file mode 100644 index 6ea7188232..0000000000 --- a/packages/medusa/src/api/routes/admin/inventory-items/delete-location-level.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { IInventoryService } from "@medusajs/types" -import { Request, Response } from "express" -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" - -/** - * @oas [delete] /admin/inventory-items/{id}/location-levels/{location_id} - * operationId: "DeleteInventoryItemsInventoryIteLocationLevelsLocation" - * summary: "Delete a Location Level" - * description: "Delete a location level of an Inventory Item." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Inventory Item. - * - (path) location_id=* {string} The ID of the location. - * x-codegen: - * method: deleteLocationLevel - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.deleteLocationLevel(inventoryItemId, locationId) - * .then(({ inventory_item }) => { - * console.log(inventory_item.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteLocationLevel } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const deleteLocationLevel = useAdminDeleteLocationLevel( - * inventoryItemId - * ) - * // ... - * - * const handleDelete = ( - * locationId: string - * ) => { - * deleteLocationLevel.mutate(locationId) - * } - * - * // ... - * } - * - * export default InventoryItem - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/inventory-items/{id}/location-levels/{location_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Inventory Items - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminInventoryItemsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id, location_id } = req.params - - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - const manager: EntityManager = req.scope.resolve("manager") - - const reservedQuantity = await inventoryService.retrieveReservedQuantity(id, [ - location_id, - ]) - - if (reservedQuantity > 0) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Cannot remove Inventory Level ${id} at Location ${location_id} because there are reserved items.` - ) - } - - await inventoryService.deleteInventoryLevel(id, location_id) - - const inventoryItem = await inventoryService.retrieveInventoryItem( - id, - req.retrieveConfig - ) - - res.status(200).json({ inventory_item: inventoryItem }) -} diff --git a/packages/medusa/src/api/routes/admin/inventory-items/get-inventory-item.ts b/packages/medusa/src/api/routes/admin/inventory-items/get-inventory-item.ts deleted file mode 100644 index 92aa730a53..0000000000 --- a/packages/medusa/src/api/routes/admin/inventory-items/get-inventory-item.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { IInventoryService } from "@medusajs/types" -import { Request, Response } from "express" -import { FindParams } from "../../../../types/common" -import { joinLevels } from "./utils/join-levels" - -/** - * @oas [get] /admin/inventory-items/{id} - * operationId: "GetInventoryItemsInventoryItem" - * summary: "Get an Inventory Item" - * description: "Retrieve an Inventory Item's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Inventory Item. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned inventory item. - * - (query) fields {string} Comma-separated fields that should be included in the returned inventory item. - * x-codegen: - * method: retrieve - * queryParams: AdminGetInventoryItemsItemParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.retrieve(inventoryItemId) - * .then(({ inventory_item }) => { - * console.log(inventory_item.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminInventoryItem } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const { - * inventory_item, - * isLoading - * } = useAdminInventoryItem(inventoryItemId) - * - * return ( - *
- * {isLoading && Loading...} - * {inventory_item && ( - * {inventory_item.sku} - * )} - *
- * ) - * } - * - * export default InventoryItem - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/inventory-items/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Inventory Items - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminInventoryItemsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - - const inventoryItem = await inventoryService.retrieveInventoryItem( - id, - req.retrieveConfig - ) - - const [data] = await joinLevels([inventoryItem], [], inventoryService) - - res.status(200).json({ inventory_item: data }) -} - -export class AdminGetInventoryItemsItemParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/inventory-items/index.ts b/packages/medusa/src/api/routes/admin/inventory-items/index.ts deleted file mode 100644 index ab69044d77..0000000000 --- a/packages/medusa/src/api/routes/admin/inventory-items/index.ts +++ /dev/null @@ -1,330 +0,0 @@ -import "reflect-metadata" - -import { - AdminPostInventoryItemsInventoryItemParams, - AdminPostInventoryItemsInventoryItemReq, -} from "./update-inventory-item" -import { - AdminPostInventoryItemsItemLocationLevelsLevelParams, - AdminPostInventoryItemsItemLocationLevelsLevelReq, -} from "./update-location-level" -import { - AdminPostInventoryItemsItemLocationLevelsParams, - AdminPostInventoryItemsItemLocationLevelsReq, -} from "./create-location-level" -import { - AdminPostInventoryItemsParams, - AdminPostInventoryItemsReq, -} from "./create-inventory-item" -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import { InventoryItemDTO, InventoryLevelDTO } from "@medusajs/types" -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" - -import { AdminGetInventoryItemsItemLocationLevelsParams } from "./list-location-levels" -import { AdminGetInventoryItemsItemParams } from "./get-inventory-item" -import { AdminGetInventoryItemsParams } from "./list-inventory-items" -import { ProductVariant } from "../../../../models" -import { Router } from "express" -import { checkRegisteredModules } from "../../../middlewares/check-registered-modules" - -const route = Router() - -export default (app) => { - app.use( - "/inventory-items", - checkRegisteredModules({ - inventoryService: - "Inventory is not enabled. Please add an Inventory module to enable this functionality.", - }), - route - ) - - route.get( - "/", - transformQuery(AdminGetInventoryItemsParams, { - defaultFields: defaultAdminInventoryItemFields, - defaultRelations: defaultAdminInventoryItemRelations, - isList: true, - }), - middlewares.wrap(require("./list-inventory-items").default) - ) - - route.post( - "/:id", - transformQuery(AdminPostInventoryItemsInventoryItemParams, { - defaultFields: defaultAdminInventoryItemFields, - defaultRelations: defaultAdminInventoryItemRelations, - isList: false, - }), - transformBody(AdminPostInventoryItemsInventoryItemReq), - middlewares.wrap(require("./update-inventory-item").default) - ) - - route.delete( - "/:id", - middlewares.wrap(require("./delete-inventory-item").default) - ) - - route.post( - "/:id/location-levels", - transformQuery(AdminPostInventoryItemsItemLocationLevelsParams, { - defaultFields: defaultAdminInventoryItemFields, - defaultRelations: defaultAdminInventoryItemRelations, - isList: false, - }), - transformBody(AdminPostInventoryItemsItemLocationLevelsReq), - middlewares.wrap(require("./create-location-level").default) - ) - - route.post( - "/", - transformQuery(AdminPostInventoryItemsParams, { - defaultFields: defaultAdminInventoryItemFields, - defaultRelations: defaultAdminInventoryItemRelations, - isList: false, - }), - transformBody(AdminPostInventoryItemsReq), - middlewares.wrap(require("./create-inventory-item").default) - ) - - route.get( - "/:id/location-levels", - transformQuery(AdminGetInventoryItemsItemLocationLevelsParams, { - defaultFields: defaultAdminLocationLevelFields, - defaultRelations: [], - isList: false, - }), - middlewares.wrap(require("./list-location-levels").default) - ) - - route.delete( - "/:id/location-levels/:location_id", - middlewares.wrap(require("./delete-location-level").default) - ) - - route.post( - "/:id/location-levels/:location_id", - transformQuery(AdminPostInventoryItemsItemLocationLevelsLevelParams, { - defaultFields: defaultAdminInventoryItemFields, - defaultRelations: defaultAdminInventoryItemRelations, - isList: false, - }), - transformBody(AdminPostInventoryItemsItemLocationLevelsLevelReq), - middlewares.wrap(require("./update-location-level").default) - ) - - route.get( - "/:id", - transformQuery(AdminGetInventoryItemsItemParams, { - defaultFields: defaultAdminInventoryItemFields, - defaultRelations: defaultAdminInventoryItemRelations, - isList: false, - }), - middlewares.wrap(require("./get-inventory-item").default) - ) - - return app -} - -export const defaultAdminInventoryItemFields: (keyof InventoryItemDTO)[] = [ - "id", - "sku", - "title", - "description", - "thumbnail", - "origin_country", - "hs_code", - "requires_shipping", - "mid_code", - "material", - "weight", - "length", - "height", - "width", - "metadata", - "created_at", - "updated_at", -] - -export const defaultAdminLocationLevelFields: (keyof InventoryLevelDTO)[] = [ - "id", - "inventory_item_id", - "location_id", - "stocked_quantity", - "reserved_quantity", - "incoming_quantity", - "metadata", - "created_at", - "updated_at", -] - -export const defaultAdminInventoryItemRelations = [] - -/** - * @schema AdminInventoryItemsRes - * type: object - * description: The inventory item's details. - * required: - * - inventory_item - * properties: - * inventory_item: - * description: Inventory Item details - * $ref: "#/components/schemas/InventoryItemDTO" - */ -export type AdminInventoryItemsRes = { - inventory_item: InventoryItemDTO -} - -/** - * @schema AdminInventoryItemsDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Inventory Item. - * object: - * type: string - * description: The type of the object that was deleted. - * format: inventory_item - * deleted: - * type: boolean - * description: Whether or not the Inventory Item was deleted. - * default: true - */ -export type AdminInventoryItemsDeleteRes = DeleteResponse - -/** - * @schema AdminInventoryItemsListRes - * type: object - * required: - * - inventory_items - * - count - * - offset - * - limit - * properties: - * inventory_items: - * type: array - * description: an array of Inventory Item details - * items: - * $ref: "#/components/schemas/InventoryItemDTO" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of inventory items skipped when retrieving the inventory items. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminInventoryItemsListRes = PaginatedResponse & { - inventory_items: InventoryItemDTO[] -} - -/** - * @schema DecoratedInventoryItemDTO - * type: object - * allOf: - * - $ref: "#/components/schemas/InventoryItemDTO" - * - type: object - * required: - * - stocked_quantity - * - reserved_quantity - * properties: - * location_levels: - * type: array - * description: An array of location level details - * items: - * $ref: "#/components/schemas/InventoryLevelDTO" - * variants: - * type: array - * description: An array of product variant details - * items: - * $ref: "#/components/schemas/ProductVariant" - * stocked_quantity: - * type: number - * description: The total quantity of the item in stock across levels - * reserved_quantity: - * type: number - * description: The total quantity of the item available across levels - */ -export type DecoratedInventoryItemDTO = InventoryItemDTO & { - location_levels?: InventoryLevelDTO[] - variants?: ProductVariant[] - stocked_quantity: number - reserved_quantity: number -} - -/** - * @schema AdminInventoryItemsListWithVariantsAndLocationLevelsRes - * type: object - * required: - * - inventory_items - * - count - * - offset - * - limit - * properties: - * inventory_items: - * type: array - * description: an array of Inventory Item details - * items: - * $ref: "#/components/schemas/DecoratedInventoryItemDTO" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of inventory items skipped when retrieving the inventory items. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminInventoryItemsListWithVariantsAndLocationLevelsRes = - PaginatedResponse & { - inventory_items: DecoratedInventoryItemDTO[] - } - -/** - * @schema AdminInventoryItemsLocationLevelsRes - * type: object - * description: "Details of inventory items and their associated location levels." - * required: - * - inventory_item - * properties: - * inventory_item: - * type: object - * description: "An inventory item's ID and associated location levels." - * required: - * - id - * - location_levels - * properties: - * id: - * description: The id of the location - * type: string - * location_levels: - * description: List of stock levels at a given location - * type: array - * items: - * $ref: "#/components/schemas/InventoryLevelDTO" - */ -export type AdminInventoryItemsLocationLevelsRes = { - inventory_item: { - id - location_levels: InventoryLevelDTO[] - } -} - -export * from "./create-inventory-item" -export * from "./create-location-level" -export * from "./get-inventory-item" -export * from "./list-inventory-items" -export * from "./list-location-levels" -export * from "./update-inventory-item" -export * from "./update-location-level" diff --git a/packages/medusa/src/api/routes/admin/inventory-items/list-inventory-items.ts b/packages/medusa/src/api/routes/admin/inventory-items/list-inventory-items.ts deleted file mode 100644 index 1c09ba1066..0000000000 --- a/packages/medusa/src/api/routes/admin/inventory-items/list-inventory-items.ts +++ /dev/null @@ -1,281 +0,0 @@ -import { IsBoolean, IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" -import { - ProductVariantInventoryService, - ProductVariantService, -} from "../../../../services" -import { - NumericalComparisonOperator, - StringComparisonOperator, - extendedFindParamsMixin, -} from "../../../../types/common" -import { joinLevels } from "./utils/join-levels" -import { joinVariants } from "./utils/join-variants" - -import { IInventoryService } from "@medusajs/types" -import { Transform } from "class-transformer" -import { IsType } from "../../../../utils/validators/is-type" - -/** - * @oas [get] /admin/inventory-items - * operationId: "GetInventoryItems" - * summary: "List Inventory Items" - * description: "Retrieve a list of inventory items. The inventory items can be filtered by fields such as `q` or `location_id`. The inventory items can also be paginated." - * x-authenticated: true - * parameters: - * - (query) offset=0 {integer} The number of inventory items to skip when retrieving the inventory items. - * - (query) limit=20 {integer} Limit the number of inventory items returned. - * - (query) expand {string} Comma-separated relations that should be expanded in each returned inventory item. - * - (query) fields {string} Comma-separated fields that should be included in the returned inventory item. - * - (query) q {string} term to search inventory item's sku, title, and description. - * - (query) order {string} Field to sort-order inventory items by. - * - in: query - * name: location_id - * style: form - * explode: false - * description: Filter by location IDs. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by the inventory ID - * schema: - * oneOf: - * - type: string - * description: inventory ID - * - type: array - * description: an array of inventory IDs - * items: - * type: string - * - (query) sku {string} Filter by SKU - * - (query) origin_country {string} Filter by origin country - * - (query) mid_code {string} Filter by MID code - * - (query) material {string} Filter by material - * - (query) hs_code {string} Filter by HS Code - * - (query) weight {string} Filter by weight - * - (query) length {string} Filter by length - * - (query) height {string} Filter by height - * - (query) width {string} Filter by width - * - (query) requires_shipping {string} Filter by whether the item requires shipping - * x-codegen: - * method: list - * queryParams: AdminGetInventoryItemsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.list() - * .then(({ inventory_items, count, offset, limit }) => { - * console.log(inventory_items.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminInventoryItems } from "medusa-react" - * - * function InventoryItems() { - * const { - * inventory_items, - * isLoading - * } = useAdminInventoryItems() - * - * return ( - *
- * {isLoading && Loading...} - * {inventory_items && !inventory_items.length && ( - * No Items - * )} - * {inventory_items && inventory_items.length > 0 && ( - *
    - * {inventory_items.map( - * (item) => ( - *
  • {item.id}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default InventoryItems - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/inventory-items' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Inventory Items - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminInventoryItemsListWithVariantsAndLocationLevelsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - const productVariantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - - const { filterableFields, listConfig } = req - const { skip, take } = listConfig - - let locationIds: string[] = [] - - if (filterableFields.location_id) { - locationIds = Array.isArray(filterableFields.location_id) - ? filterableFields.location_id - : [filterableFields.location_id] - } - - const [inventoryItems, count] = await inventoryService.listInventoryItems( - filterableFields, - listConfig - ) - - const inventory_items = await joinVariants( - inventoryItems, - productVariantInventoryService, - productVariantService - ).then(async (res) => { - return await joinLevels(res, locationIds, inventoryService) - }) - - res.status(200).json({ - inventory_items, - count, - offset: skip, - limit: take, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved inventory items. - */ -export class AdminGetInventoryItemsParams extends extendedFindParamsMixin({ - limit: 20, - offset: 0, -}) { - /** - * IDs to filter inventory items by. - */ - @IsOptional() - @IsType([String, [String]]) - id?: string | string[] - - /** - * Search terms to search inventory items' sku, title, and description. - */ - @IsOptional() - @IsString() - q?: string - - /** - * Location IDs to filter inventory items by. - */ - @IsOptional() - @IsType([String, [String]]) - location_id?: string | string[] - - /** - * SKUs to filter inventory items by. - */ - @IsOptional() - @IsType([String, [String]]) - sku?: string | string[] - - /** - * Origin countries to filter inventory items by. - */ - @IsOptional() - @IsType([String, [String]]) - origin_country?: string | string[] - - /** - * MID codes to filter inventory items by. - */ - @IsOptional() - @IsType([String, [String]]) - mid_code?: string | string[] - - /** - * Materials to filter inventory items by. - */ - @IsOptional() - @IsType([String, [String]]) - material?: string | string[] - - /** - * String filters to apply to inventory items' `hs_code` field. - */ - @IsOptional() - @IsType([String, [String], StringComparisonOperator]) - hs_code?: string | string[] | StringComparisonOperator - - /** - * Number filters to apply to inventory items' `weight` field. - */ - @IsOptional() - @IsType([Number, NumericalComparisonOperator]) - weight?: number | NumericalComparisonOperator - - /** - * Number filters to apply to inventory items' `length` field. - */ - @IsOptional() - @IsType([Number, NumericalComparisonOperator]) - length?: number | NumericalComparisonOperator - - /** - * Number filters to apply to inventory items' `height` field. - */ - @IsOptional() - @IsType([Number, NumericalComparisonOperator]) - height?: number | NumericalComparisonOperator - - /** - * Number filters to apply to inventory items' `width` field. - */ - @IsOptional() - @IsType([Number, NumericalComparisonOperator]) - width?: number | NumericalComparisonOperator - - /** - * Filter inventory items by whether they require shipping. - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => value === "true") - requires_shipping?: boolean -} diff --git a/packages/medusa/src/api/routes/admin/inventory-items/list-location-levels.ts b/packages/medusa/src/api/routes/admin/inventory-items/list-location-levels.ts deleted file mode 100644 index bb7c86e239..0000000000 --- a/packages/medusa/src/api/routes/admin/inventory-items/list-location-levels.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" - -import { FindParams } from "../../../../types/common" -import { IInventoryService } from "@medusajs/types" -import { IsType } from "../../../../utils/validators/is-type" - -/** - * @oas [get] /admin/inventory-items/{id}/location-levels - * operationId: "GetInventoryItemsInventoryItemLocationLevels" - * summary: "List Inventory Level" - * description: "Retrieve a list of inventory levels of an inventory item. The inventory levels can be filtered by fields such as `location_id`." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Inventory Item the locations are associated with. - * - in: query - * name: location_id - * style: form - * explode: false - * description: Filter by location IDs. - * schema: - * type: array - * items: - * type: string - * - (query) expand {string} Comma-separated relations that should be expanded in the returned inventory levels. - * - (query) fields {string} Comma-separated fields that should be included in the returned inventory levels. - * x-codegen: - * method: listLocationLevels - * queryParams: AdminGetInventoryItemsItemLocationLevelsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.listLocationLevels(inventoryItemId) - * .then(({ inventory_item }) => { - * console.log(inventory_item.location_levels); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminInventoryItemLocationLevels, - * } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const { - * inventory_item, - * isLoading, - * } = useAdminInventoryItemLocationLevels(inventoryItemId) - * - * return ( - *
- * {isLoading && Loading...} - * {inventory_item && ( - *
    - * {inventory_item.location_levels.map((level) => ( - * {level.stocked_quantity} - * ))} - *
- * )} - *
- * ) - * } - * - * export default InventoryItem - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/inventory-items/{id}/location-levels' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Inventory Items - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminInventoryItemsLocationLevelsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const { id } = req.params - - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - - const [levels] = await inventoryService.listInventoryLevels( - { - ...req.filterableFields, - inventory_item_id: id, - }, - req.retrieveConfig - ) - - res.status(200).json({ - inventory_item: { - id, - location_levels: levels, - }, - }) -} - -// eslint-disable-next-line max-len -export class AdminGetInventoryItemsItemLocationLevelsParams extends FindParams { - /** - * Location IDs to filter location levels. - */ - @IsOptional() - @IsString({ each: true }) - location_id?: string[] -} diff --git a/packages/medusa/src/api/routes/admin/inventory-items/update-inventory-item.ts b/packages/medusa/src/api/routes/admin/inventory-items/update-inventory-item.ts deleted file mode 100644 index 7013ff2e95..0000000000 --- a/packages/medusa/src/api/routes/admin/inventory-items/update-inventory-item.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { IsBoolean, IsNumber, IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" - -import { EntityManager } from "typeorm" -import { FindParams } from "../../../../types/common" -import { IInventoryService } from "@medusajs/types" - -/** - * @oas [post] /admin/inventory-items/{id} - * operationId: "PostInventoryItemsInventoryItem" - * summary: "Update an Inventory Item" - * description: "Update an Inventory Item's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Inventory Item. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned inventory level. - * - (query) fields {string} Comma-separated fields that should be included in the returned inventory level. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostInventoryItemsInventoryItemReq" - * x-codegen: - * method: update - * queryParams: AdminPostInventoryItemsInventoryItemParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.update(inventoryItemId, { - * origin_country: "US", - * }) - * .then(({ inventory_item }) => { - * console.log(inventory_item.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateInventoryItem } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const updateInventoryItem = useAdminUpdateInventoryItem( - * inventoryItemId - * ) - * // ... - * - * const handleUpdate = (origin_country: string) => { - * updateInventoryItem.mutate({ - * origin_country, - * }, { - * onSuccess: ({ inventory_item }) => { - * console.log(inventory_item.origin_country) - * } - * }) - * } - * - * // ... - * } - * - * export default InventoryItem - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/inventory-items/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "origin_country": "US" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Inventory Items - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminInventoryItemsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - const manager: EntityManager = req.scope.resolve("manager") - - await inventoryService.updateInventoryItem( - id, - req.validatedBody as AdminPostInventoryItemsInventoryItemReq - ) - - const inventoryItem = await inventoryService.retrieveInventoryItem( - id, - req.retrieveConfig - ) - - res.status(200).json({ inventory_item: inventoryItem }) -} - -/** - * @schema AdminPostInventoryItemsInventoryItemReq - * type: object - * description: "The attributes to update in an inventory item." - * properties: - * hs_code: - * description: The Harmonized System code of the Inventory Item. May be used by Fulfillment Providers to pass customs information to shipping carriers. - * type: string - * origin_country: - * description: The country in which the Inventory Item was produced. May be used by Fulfillment Providers to pass customs information to shipping carriers. - * type: string - * mid_code: - * description: The Manufacturers Identification code that identifies the manufacturer of the Inventory Item. May be used by Fulfillment Providers to pass customs information to shipping carriers. - * type: string - * material: - * description: The material and composition that the Inventory Item is made of, May be used by Fulfillment Providers to pass customs information to shipping carriers. - * type: string - * weight: - * description: The weight of the Inventory Item. May be used in shipping rate calculations. - * type: number - * height: - * description: The height of the Inventory Item. May be used in shipping rate calculations. - * type: number - * width: - * description: The width of the Inventory Item. May be used in shipping rate calculations. - * type: number - * length: - * description: The length of the Inventory Item. May be used in shipping rate calculations. - * type: number - * title: - * description: The inventory item's title. - * type: string - * description: - * description: The inventory item's description. - * type: string - * thumbnail: - * description: The inventory item's thumbnail. - * type: string - * requires_shipping: - * description: Whether the item requires shipping. - * type: boolean - */ - -export class AdminPostInventoryItemsInventoryItemReq { - @IsString() - @IsOptional() - sku?: string - - @IsOptional() - @IsString() - origin_country?: string - - @IsOptional() - @IsString() - hs_code?: string - - @IsOptional() - @IsString() - mid_code?: string - - @IsOptional() - @IsString() - material?: string - - @IsOptional() - @IsNumber() - weight?: number - - @IsOptional() - @IsNumber() - height?: number - - @IsOptional() - @IsNumber() - length?: number - - @IsOptional() - @IsNumber() - width?: number - - @IsString() - @IsOptional() - title?: string - - @IsString() - @IsOptional() - description?: string - - @IsString() - @IsOptional() - thumbnail?: string - - @IsBoolean() - @IsOptional() - requires_shipping?: boolean -} - -export class AdminPostInventoryItemsInventoryItemParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/inventory-items/update-location-level.ts b/packages/medusa/src/api/routes/admin/inventory-items/update-location-level.ts deleted file mode 100644 index 50f196ca25..0000000000 --- a/packages/medusa/src/api/routes/admin/inventory-items/update-location-level.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { IInventoryService } from "@medusajs/types" -import { IsNumber, IsOptional, Min } from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { FindParams } from "../../../../types/common" - -/** - * @oas [post] /admin/inventory-items/{id}/location-levels/{location_id} - * operationId: "PostInventoryItemsInventoryItemLocationLevelsLocationLevel" - * summary: "Update a Location Level" - * description: "Update a Location Level's details for a given Inventory Item." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Inventory Item that the location is associated with. - * - (path) location_id=* {string} The ID of the Location to update. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned location level. - * - (query) fields {string} Comma-separated fields that should be included in the returned location level. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostInventoryItemsItemLocationLevelsLevelReq" - * x-codegen: - * method: updateLocationLevel - * queryParams: AdminPostInventoryItemsItemLocationLevelsLevelParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.inventoryItems.updateLocationLevel(inventoryItemId, locationId, { - * stocked_quantity: 15, - * }) - * .then(({ inventory_item }) => { - * console.log(inventory_item.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateLocationLevel } from "medusa-react" - * - * type Props = { - * inventoryItemId: string - * } - * - * const InventoryItem = ({ inventoryItemId }: Props) => { - * const updateLocationLevel = useAdminUpdateLocationLevel( - * inventoryItemId - * ) - * // ... - * - * const handleUpdate = ( - * stockLocationId: string, - * stocked_quantity: number - * ) => { - * updateLocationLevel.mutate({ - * stockLocationId, - * stocked_quantity, - * }, { - * onSuccess: ({ inventory_item }) => { - * console.log(inventory_item.id) - * } - * }) - * } - * - * // ... - * } - * - * export default InventoryItem - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/inventory-items/{id}/location-levels/{location_id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "stocked_quantity": 15 - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Inventory Items - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminInventoryItemsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id, location_id } = req.params - - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - const manager: EntityManager = req.scope.resolve("manager") - - const validatedBody = - req.validatedBody as AdminPostInventoryItemsItemLocationLevelsLevelReq - - await inventoryService.updateInventoryLevel(id, location_id, validatedBody) - - const inventoryItem = await inventoryService.retrieveInventoryItem( - id, - req.retrieveConfig - ) - - res.status(200).json({ inventory_item: inventoryItem }) -} - -/** - * @schema AdminPostInventoryItemsItemLocationLevelsLevelReq - * type: object - * properties: - * stocked_quantity: - * description: the total stock quantity of an inventory item at the given location ID - * type: number - * incoming_quantity: - * description: the incoming stock quantity of an inventory item at the given location ID - * type: number - */ -export class AdminPostInventoryItemsItemLocationLevelsLevelReq { - @IsOptional() - @IsNumber() - @Min(0) - incoming_quantity?: number - - @IsOptional() - @IsNumber() - @Min(0) - stocked_quantity?: number -} - -// eslint-disable-next-line -export class AdminPostInventoryItemsItemLocationLevelsLevelParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/inventory-items/utils/join-levels.ts b/packages/medusa/src/api/routes/admin/inventory-items/utils/join-levels.ts deleted file mode 100644 index eb72c51c02..0000000000 --- a/packages/medusa/src/api/routes/admin/inventory-items/utils/join-levels.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { - FilterableInventoryLevelProps, - IInventoryService, - InventoryItemDTO, - InventoryLevelDTO, -} from "@medusajs/types" -import { promiseAll } from "@medusajs/utils" -import { LevelWithAvailability, ResponseInventoryItem } from "../../variants" - -export const buildLevelsByInventoryItemId = ( - inventoryLevels: InventoryLevelDTO[], - locationIds: string[] -) => { - const filteredLevels = inventoryLevels.filter((level) => { - return !locationIds.length || locationIds.includes(level.location_id) - }) - - return filteredLevels.reduce((acc, level) => { - acc[level.inventory_item_id] = acc[level.inventory_item_id] ?? [] - acc[level.inventory_item_id].push(level) - return acc - }, {}) -} - -export const getLevelsByInventoryItemId = async ( - items: InventoryItemDTO[], - locationIds: string[], - inventoryService: IInventoryService -): Promise> => { - const selector: FilterableInventoryLevelProps = { - inventory_item_id: items.map((inventoryItem) => inventoryItem.id), - } - if (locationIds.length) { - selector.location_id = locationIds - } - - const [levels] = await inventoryService.listInventoryLevels(selector, {}) - - const levelsWithAvailability: LevelWithAvailability[] = await promiseAll( - levels.map(async (level) => { - const availability = await inventoryService.retrieveAvailableQuantity( - level.inventory_item_id, - [level.location_id] - ) - return { - ...level, - available_quantity: availability, - } - }) - ) - - return buildLevelsByInventoryItemId(levelsWithAvailability, locationIds) -} - -export const joinLevels = async ( - inventoryItems: InventoryItemDTO[], - locationIds: string[], - inventoryService: IInventoryService -): Promise => { - const levelsByItemId = await getLevelsByInventoryItemId( - inventoryItems, - locationIds, - inventoryService - ) - - return inventoryItems.map((inventoryItem) => { - const levels = levelsByItemId[inventoryItem.id] ?? [] - const itemAvailability = levels.reduce( - (acc, curr) => { - return { - reserved_quantity: acc.reserved_quantity + curr.reserved_quantity, - stocked_quantity: acc.stocked_quantity + curr.stocked_quantity, - } - }, - { reserved_quantity: 0, stocked_quantity: 0 } - ) - - return { - ...inventoryItem, - ...itemAvailability, - location_levels: levels, - } - }) -} diff --git a/packages/medusa/src/api/routes/admin/inventory-items/utils/join-variants.ts b/packages/medusa/src/api/routes/admin/inventory-items/utils/join-variants.ts deleted file mode 100644 index 63c83d1af7..0000000000 --- a/packages/medusa/src/api/routes/admin/inventory-items/utils/join-variants.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { - ProductVariantInventoryService, - ProductVariantService, -} from "../../../../../services" - -import { InventoryItemDTO } from "@medusajs/types" -import { ProductVariant } from "../../../../../models" - -export type InventoryItemsWithVariants = Partial & { - variants?: ProductVariant[] -} - -export const getVariantsByInventoryItemId = async ( - inventoryItems: InventoryItemDTO[], - productVariantInventoryService: ProductVariantInventoryService, - productVariantService: ProductVariantService -): Promise> => { - const variantInventory = await productVariantInventoryService.listByItem( - inventoryItems.map((item) => item.id) - ) - - const variants = await productVariantService.list( - { - id: variantInventory.map((varInventory) => varInventory.variant_id), - }, - { - relations: ["product"], - } - ) - const variantMap = new Map(variants.map((variant) => [variant.id, variant])) - - return variantInventory.reduce((acc, cur) => { - acc[cur.inventory_item_id] = acc[cur.inventory_item_id] ?? [] - acc[cur.inventory_item_id].push(variantMap.get(cur.variant_id)) - return acc - }, {}) -} - -export const joinVariants = async ( - inventoryItems: InventoryItemDTO[], - productVariantInventoryService: ProductVariantInventoryService, - productVariantService: ProductVariantService -) => { - const variantsByInventoryItemId = await getVariantsByInventoryItemId( - inventoryItems, - productVariantInventoryService, - productVariantService - ) - - return inventoryItems.map((inventoryItem) => { - return { - ...inventoryItem, - variants: variantsByInventoryItemId[inventoryItem.id] ?? [], - } - }) -} diff --git a/packages/medusa/src/api/routes/admin/invites/__tests__/accept-invite.js b/packages/medusa/src/api/routes/admin/invites/__tests__/accept-invite.js deleted file mode 100644 index a73c9d5cbf..0000000000 --- a/packages/medusa/src/api/routes/admin/invites/__tests__/accept-invite.js +++ /dev/null @@ -1,38 +0,0 @@ -import { request } from "../../../../../helpers/test-request" -import { InviteServiceMock } from "../../../../../services/__mocks__/invite" - -describe("POST /invites/accept", () => { - describe("successfully accepts an invite", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/admin/invites/accept`, { - payload: { - token: "jwt_test_invite", - user: { - first_name: "John", - last_name: "Doe", - password: "supersecret", - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls InviteService accept", () => { - expect(InviteServiceMock.accept).toHaveBeenCalledTimes(1) - expect(InviteServiceMock.accept).toHaveBeenCalledWith("jwt_test_invite", { - first_name: "John", - last_name: "Doe", - password: "supersecret", - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/invites/__tests__/create-invite.js b/packages/medusa/src/api/routes/admin/invites/__tests__/create-invite.js deleted file mode 100644 index c6467009e7..0000000000 --- a/packages/medusa/src/api/routes/admin/invites/__tests__/create-invite.js +++ /dev/null @@ -1,65 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { InviteServiceMock } from "../../../../../services/__mocks__/invite" -import { UserRole } from "../../../../../types/user" - -describe("POST /invites", () => { - describe("checks that role must not be empty", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/admin/invites`, { - payload: { - role: "admin", - }, - adminSession: { - jwt: { - userId: "test_user", - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("throws when role is empty", () => { - expect(subject.error).toBeTruthy() - expect(subject.error.text).toEqual( - `{"type":"invalid_data","message":"user must be an email"}` - ) - expect(subject.error.status).toEqual(400) - }) - }) - - describe("successfully creates an invite", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/admin/invites`, { - payload: { - role: "admin", - user: "lebron@james.com", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls InviteService create", () => { - expect(InviteServiceMock.create).toHaveBeenCalledTimes(1) - expect(InviteServiceMock.create).toHaveBeenCalledWith( - "lebron@james.com", - UserRole.ADMIN - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/invites/__tests__/resend-invite.js b/packages/medusa/src/api/routes/admin/invites/__tests__/resend-invite.js deleted file mode 100644 index 56814277b2..0000000000 --- a/packages/medusa/src/api/routes/admin/invites/__tests__/resend-invite.js +++ /dev/null @@ -1,31 +0,0 @@ -import { request } from "../../../../../helpers/test-request" -import { InviteServiceMock } from "../../../../../services/__mocks__/invite" - -describe("POST /invites/:invite_id/resend", () => { - describe("successfully resends an invite", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/admin/invites/invite_test/resend`, { - adminSession: { - jwt: { - userId: "test_user", - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls InviteService accept", () => { - expect(InviteServiceMock.resend).toHaveBeenCalledTimes(1) - expect(InviteServiceMock.resend).toHaveBeenCalledWith("invite_test") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/invites/accept-invite.ts b/packages/medusa/src/api/routes/admin/invites/accept-invite.ts deleted file mode 100644 index 93d738ba6d..0000000000 --- a/packages/medusa/src/api/routes/admin/invites/accept-invite.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { - IsNotEmpty, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" - -import InviteService from "../../../../services/invite" -import { Type } from "class-transformer" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/invites/accept - * operationId: "PostInvitesInviteAccept" - * summary: "Accept an Invite" - * description: "Accept an Invite. This will also delete the invite and create a new user that can log in and perform admin functionalities. The user will have the email associated with the invite, and the password - * provided in the request body." - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostInvitesInviteAcceptReq" - * x-codegen: - * method: accept - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.invites.accept({ - * token, - * user: { - * first_name: "Brigitte", - * last_name: "Collier", - * password: "supersecret" - * } - * }) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // an error occurred - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminAcceptInvite } from "medusa-react" - * - * const AcceptInvite = () => { - * const acceptInvite = useAdminAcceptInvite() - * // ... - * - * const handleAccept = ( - * token: string, - * firstName: string, - * lastName: string, - * password: string - * ) => { - * acceptInvite.mutate({ - * token, - * user: { - * first_name: firstName, - * last_name: lastName, - * password, - * }, - * }, { - * onSuccess: () => { - * // invite accepted successfully. - * } - * }) - * } - * - * // ... - * } - * - * export default AcceptInvite - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/invites/accept' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "token": "{token}", - * "user": { - * "first_name": "Brigitte", - * "last_name": "Collier", - * "password": "supersecret" - * } - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Invites - * responses: - * 200: - * description: OK - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminPostInvitesInviteAcceptReq, req.body) - - const inviteService: InviteService = req.scope.resolve("inviteService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await inviteService - .withTransaction(transactionManager) - .accept(validated.token, validated.user) - }) - - res.sendStatus(200) -} - -/** - * Details of the use accepting the invite. - */ -export class AdminPostInvitesInviteAcceptUserReq { - /** - * The invite's first name. - */ - @IsString() - @IsOptional() - first_name: string - - /** - * The invite's last name. - */ - @IsString() - @IsOptional() - last_name: string - - /** - * The invite's password - */ - @IsString() - password: string -} - -/** - * @schema AdminPostInvitesInviteAcceptReq - * type: object - * description: "The details of the invite to be accepted." - * required: - * - token - * - user - * properties: - * token: - * description: "The token of the invite to accept. This is a unique token generated when the invite was created or resent." - * type: string - * user: - * description: "The details of the user to create." - * type: object - * required: - * - first_name - * - last_name - * - password - * properties: - * first_name: - * type: string - * description: the first name of the User - * last_name: - * type: string - * description: the last name of the User - * password: - * description: The password for the User - * type: string - * format: password - */ -export class AdminPostInvitesInviteAcceptReq { - @IsString() - @IsNotEmpty() - token: string - - @IsNotEmpty() - @ValidateNested() - @Type(() => AdminPostInvitesInviteAcceptUserReq) - user: AdminPostInvitesInviteAcceptUserReq -} diff --git a/packages/medusa/src/api/routes/admin/invites/create-invite.ts b/packages/medusa/src/api/routes/admin/invites/create-invite.ts deleted file mode 100644 index ec21f7684b..0000000000 --- a/packages/medusa/src/api/routes/admin/invites/create-invite.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { IsEmail, IsEnum } from "class-validator" - -import InviteService from "../../../../services/invite" -import { UserRoles } from "../../../../models/user" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/invites - * operationId: "PostInvites" - * summary: "Create an Invite" - * description: "Create an Invite. This will generate a token associated with the invite and trigger an `invite.created` event. If you have a Notification Provider installed that handles this - * event, a notification should be sent to the email associated with the invite to allow them to accept the invite." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostInvitesReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.invites.create({ - * user: "user@example.com", - * role: "admin" - * }) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // an error occurred - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/invites' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "user": "user@example.com", - * "role": "admin" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Invites - * responses: - * 200: - * description: OK - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminPostInvitesReq, req.body) - - const inviteService: InviteService = req.scope.resolve("inviteService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await inviteService - .withTransaction(transactionManager) - .create(validated.user, validated.role) - }) - - res.sendStatus(200) -} - -/** - * @schema AdminPostInvitesReq - * type: object - * required: - * - user - * - role - * properties: - * user: - * description: "The email associated with the invite. Once the invite is accepted, the email will be associated with the created user." - * type: string - * format: email - * role: - * description: "The role of the user to be created. This does not actually change the privileges of the user that is eventually created." - * type: string - * enum: [admin, member, developer] - */ -export class AdminPostInvitesReq { - @IsEmail() - user: string - - @IsEnum(UserRoles) - role: UserRoles -} diff --git a/packages/medusa/src/api/routes/admin/invites/delete-invite.ts b/packages/medusa/src/api/routes/admin/invites/delete-invite.ts deleted file mode 100644 index f78fa15d5d..0000000000 --- a/packages/medusa/src/api/routes/admin/invites/delete-invite.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { EntityManager } from "typeorm" -import InviteService from "../../../../services/invite" - -/** - * @oas [delete] /admin/invites/{invite_id} - * operationId: "DeleteInvitesInvite" - * summary: "Delete an Invite" - * description: "Delete an Invite. Only invites that weren't accepted can be deleted." - * x-authenticated: true - * parameters: - * - (path) invite_id=* {string} The ID of the Invite - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.invites.delete(inviteId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteInvite } from "medusa-react" - * - * type Props = { - * inviteId: string - * } - * - * const DeleteInvite = ({ inviteId }: Props) => { - * const deleteInvite = useAdminDeleteInvite(inviteId) - * // ... - * - * const handleDelete = () => { - * deleteInvite.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Invite - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/invites/{invite_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Invites - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminInviteDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { invite_id } = req.params - - const inviteService: InviteService = req.scope.resolve("inviteService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - await inviteService.withTransaction(transactionManager).delete(invite_id) - }) - - res.status(200).send({ - id: invite_id, - object: "invite", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/invites/index.ts b/packages/medusa/src/api/routes/admin/invites/index.ts deleted file mode 100644 index 72a06d8985..0000000000 --- a/packages/medusa/src/api/routes/admin/invites/index.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Router } from "express" -import { Invite } from "../../../../models/invite" -import { DeleteResponse } from "../../../../types/common" -import middlewares from "../../../middlewares" -import "reflect-metadata" - -export const unauthenticatedInviteRoutes = (app) => { - const route = Router() - app.use("/invites", route) - - route.post("/accept", middlewares.wrap(require("./accept-invite").default)) -} - -export default (app) => { - const route = Router() - app.use("/invites", route) - - route.get("/", middlewares.wrap(require("./list-invites").default)) - - route.post("/", middlewares.wrap(require("./create-invite").default)) - - route.post( - "/:invite_id/resend", - middlewares.wrap(require("./resend-invite").default) - ) - - route.delete( - "/:invite_id", - middlewares.wrap(require("./delete-invite").default) - ) - - return app -} - -/** - * @schema AdminInviteDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Invite. - * object: - * type: string - * description: The type of the object that was deleted. - * default: invite - * deleted: - * type: boolean - * description: Whether or not the invite was deleted. - * default: true - */ -export type AdminInviteDeleteRes = DeleteResponse - -/** - * @schema AdminListInvitesRes - * description: "The list of invites." - * type: object - * required: - * - invites - * properties: - * invites: - * type: array - * description: An array of invites - * items: - * $ref: "#/components/schemas/Invite" - */ -export type AdminListInvitesRes = { - invites: Invite[] -} - -export * from "./accept-invite" -export * from "./create-invite" -export * from "./delete-invite" -export * from "./list-invites" -export * from "./resend-invite" diff --git a/packages/medusa/src/api/routes/admin/invites/list-invites.ts b/packages/medusa/src/api/routes/admin/invites/list-invites.ts deleted file mode 100644 index 55b358f0e7..0000000000 --- a/packages/medusa/src/api/routes/admin/invites/list-invites.ts +++ /dev/null @@ -1,58 +0,0 @@ -import InviteService from "../../../../services/invite" - -/** - * @oas [get] /admin/invites - * operationId: "GetInvites" - * summary: "Lists Invites" - * description: "Retrieve a list of invites." - * x-authenticated: true - * x-codegen: - * method: list - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.invites.list() - * .then(({ invites }) => { - * console.log(invites.length); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/invites' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Invites - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminListInvitesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const inviteService: InviteService = req.scope.resolve("inviteService") - const invites = await inviteService.list({}) - - res.status(200).json({ invites }) -} diff --git a/packages/medusa/src/api/routes/admin/invites/resend-invite.ts b/packages/medusa/src/api/routes/admin/invites/resend-invite.ts deleted file mode 100644 index 9ec6711796..0000000000 --- a/packages/medusa/src/api/routes/admin/invites/resend-invite.ts +++ /dev/null @@ -1,92 +0,0 @@ -import InviteService from "../../../../services/invite" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/invites/{invite_id}/resend - * operationId: "PostInvitesInviteResend" - * summary: "Resend an Invite" - * description: "Resend an Invite. This renews the expiry date by 7 days and generates a new token for the invite. It also triggers the `invite.created` event, so if you have a Notification Provider installed that handles this - * event, a notification should be sent to the email associated with the invite to allow them to accept the invite." - * x-authenticated: true - * parameters: - * - (path) invite_id=* {string} The ID of the Invite - * x-codegen: - * method: resend - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.invites.resend(inviteId) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // an error occurred - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminResendInvite } from "medusa-react" - * - * type Props = { - * inviteId: string - * } - * - * const ResendInvite = ({ inviteId }: Props) => { - * const resendInvite = useAdminResendInvite(inviteId) - * // ... - * - * const handleResend = () => { - * resendInvite.mutate(void 0, { - * onSuccess: () => { - * // invite resent successfully - * } - * }) - * } - * - * // ... - * } - * - * export default ResendInvite - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/invites/{invite_id}/resend' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Invites - * responses: - * 200: - * description: OK - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { invite_id } = req.params - const inviteService: InviteService = req.scope.resolve("inviteService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - await inviteService.withTransaction(transactionManager).resend(invite_id) - }) - - res.sendStatus(200) -} diff --git a/packages/medusa/src/api/routes/admin/notes/create-note.ts b/packages/medusa/src/api/routes/admin/notes/create-note.ts deleted file mode 100644 index fbc454ff06..0000000000 --- a/packages/medusa/src/api/routes/admin/notes/create-note.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { IsNotEmpty, IsString } from "class-validator" - -import NoteService from "../../../../services/note" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/notes - * operationId: "PostNotes" - * summary: "Create a Note" - * description: "Create a Note which can be associated with any resource." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostNotesReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notes.create({ - * resource_id, - * resource_type: "order", - * value: "We delivered this order" - * }) - * .then(({ note }) => { - * console.log(note.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateNote } from "medusa-react" - * - * const CreateNote = () => { - * const createNote = useAdminCreateNote() - * // ... - * - * const handleCreate = () => { - * createNote.mutate({ - * resource_id: "order_123", - * resource_type: "order", - * value: "We delivered this order" - * }, { - * onSuccess: ({ note }) => { - * console.log(note.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateNote - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/notes' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "resource_id": "{resource_id}", - * "resource_type": "order", - * "value": "We delivered this order" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Notes - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminNotesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - * - */ -export default async (req, res) => { - const validated = await validator(AdminPostNotesReq, req.body) - - const userId: string = req.user.id || req.user.userId - - const noteService: NoteService = req.scope.resolve("noteService") - - const manager: EntityManager = req.scope.resolve("manager") - const result = await manager.transaction(async (transactionManager) => { - return await noteService.withTransaction(transactionManager).create({ - resource_id: validated.resource_id, - resource_type: validated.resource_type, - value: validated.value, - author_id: userId, - }) - }) - - res.status(200).json({ note: result }) -} - -/** - * @schema AdminPostNotesReq - * type: object - * description: "The details of the note to be created." - * required: - * - resource_id - * - resource_type - * - value - * properties: - * resource_id: - * type: string - * description: The ID of the resource which the Note relates to. For example, an order ID. - * resource_type: - * type: string - * description: The type of resource which the Note relates to. For example, `order`. - * value: - * type: string - * description: The content of the Note to create. - */ -export class AdminPostNotesReq { - @IsString() - @IsNotEmpty() - resource_id: string - - @IsString() - @IsNotEmpty() - resource_type: string - - @IsString() - @IsNotEmpty() - value: string -} diff --git a/packages/medusa/src/api/routes/admin/notes/delete-note.ts b/packages/medusa/src/api/routes/admin/notes/delete-note.ts deleted file mode 100644 index 41d19dee5f..0000000000 --- a/packages/medusa/src/api/routes/admin/notes/delete-note.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { EntityManager } from "typeorm" -import NoteService from "../../../../services/note" - -/** - * @oas [delete] /admin/notes/{id} - * operationId: "DeleteNotesNote" - * summary: "Delete a Note" - * description: "Delete a Note." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Note to delete. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notes.delete(noteId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteNote } from "medusa-react" - * - * type Props = { - * noteId: string - * } - * - * const Note = ({ noteId }: Props) => { - * const deleteNote = useAdminDeleteNote(noteId) - * // ... - * - * const handleDelete = () => { - * deleteNote.mutate() - * } - * - * // ... - * } - * - * export default Note - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/notes/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Notes - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminNotesDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const noteService: NoteService = req.scope.resolve("noteService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await noteService.withTransaction(transactionManager).delete(id) - }) - - res.status(200).json({ id, object: "note", deleted: true }) -} diff --git a/packages/medusa/src/api/routes/admin/notes/get-note.ts b/packages/medusa/src/api/routes/admin/notes/get-note.ts deleted file mode 100644 index 26a95e4ed9..0000000000 --- a/packages/medusa/src/api/routes/admin/notes/get-note.ts +++ /dev/null @@ -1,84 +0,0 @@ -import NoteService from "../../../../services/note" - -/** - * @oas [get] /admin/notes/{id} - * operationId: "GetNotesNote" - * summary: "Get a Note" - * description: "Retrieve a note's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the note. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notes.retrieve(noteId) - * .then(({ note }) => { - * console.log(note.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminNote } from "medusa-react" - * - * type Props = { - * noteId: string - * } - * - * const Note = ({ noteId }: Props) => { - * const { note, isLoading } = useAdminNote(noteId) - * - * return ( - *
- * {isLoading && Loading...} - * {note && {note.resource_type}} - *
- * ) - * } - * - * export default Note - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/notes/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Notes - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminNotesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const noteService: NoteService = req.scope.resolve("noteService") - const note = await noteService.retrieve(id, { relations: ["author"] }) - - res.status(200).json({ note }) -} diff --git a/packages/medusa/src/api/routes/admin/notes/index.ts b/packages/medusa/src/api/routes/admin/notes/index.ts deleted file mode 100644 index 83c928ed66..0000000000 --- a/packages/medusa/src/api/routes/admin/notes/index.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { Router } from "express" -import { Note } from "../../../.." -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import middlewares from "../../../middlewares" -import "reflect-metadata" - -const route = Router() - -export default (app) => { - app.use("/notes", route) - - route.get("/:id", middlewares.wrap(require("./get-note").default)) - - route.get("/", middlewares.wrap(require("./list-notes").default)) - - route.post("/", middlewares.wrap(require("./create-note").default)) - - route.post("/:id", middlewares.wrap(require("./update-note").default)) - - route.delete("/:id", middlewares.wrap(require("./delete-note").default)) - - return app -} - -/** - * @schema AdminNotesRes - * type: object - * description: "The note's details." - * required: - * - note - * properties: - * note: - * description: Note details. - * $ref: "#/components/schemas/Note" - */ -export type AdminNotesRes = { - note: Note -} - -/** - * @schema AdminNotesDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Note. - * object: - * type: string - * description: The type of the object that was deleted. - * default: note - * deleted: - * type: boolean - * description: Whether or not the Note was deleted. - * default: true - */ -export type AdminNotesDeleteRes = DeleteResponse - -/** - * @schema AdminNotesListRes - * type: object - * description: "The list of notes with pagination fields." - * required: - * - notes - * - count - * - offset - * - limit - * properties: - * notes: - * type: array - * description: An array of notes - * items: - * $ref: "#/components/schemas/Note" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of notes skipped when retrieving the notes. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminNotesListRes = PaginatedResponse & { - notes: Note[] -} -export * from "./create-note" -export * from "./delete-note" -export * from "./get-note" -export * from "./list-notes" -export * from "./update-note" diff --git a/packages/medusa/src/api/routes/admin/notes/list-notes.ts b/packages/medusa/src/api/routes/admin/notes/list-notes.ts deleted file mode 100644 index c5441682c8..0000000000 --- a/packages/medusa/src/api/routes/admin/notes/list-notes.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { IsNumber, IsOptional, IsString } from "class-validator" - -import NoteService from "../../../../services/note" -import { Type } from "class-transformer" -import { selector } from "../../../../types/note" -import { validator } from "../../../../utils/validator" - -/** - * @oas [get] /admin/notes - * operationId: "GetNotes" - * summary: "List Notes" - * x-authenticated: true - * description: "Retrieve a list of notes. The notes can be filtered by fields such as `resource_id`. The notes can also be paginated." - * parameters: - * - (query) limit=50 {number} Limit the number of notes returned. - * - (query) offset=0 {number} The number of notes to skip when retrieving the notes. - * - (query) resource_id {string} Filter by resource ID - * x-codegen: - * method: list - * queryParams: AdminGetNotesParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notes.list() - * .then(({ notes, limit, offset, count }) => { - * console.log(notes.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminNotes } from "medusa-react" - * - * const Notes = () => { - * const { notes, isLoading } = useAdminNotes() - * - * return ( - *
- * {isLoading && Loading...} - * {notes && !notes.length && No Notes} - * {notes && notes.length > 0 && ( - *
    - * {notes.map((note) => ( - *
  • {note.resource_type}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Notes - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/notes' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Notes - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminNotesListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminGetNotesParams, req.query) - - const selector: selector = {} - - if (validated.resource_id) { - selector.resource_id = validated.resource_id - } - - const noteService: NoteService = req.scope.resolve("noteService") - const [notes, count] = await noteService.listAndCount(selector, { - take: validated.limit, - skip: validated.offset, - relations: ["author"], - }) - - res.status(200).json({ - notes, - count, - offset: validated.offset, - limit: validated.limit, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved notes. - */ -export class AdminGetNotesParams { - /** - * Resource ID to filter notes by. - */ - @IsString() - @IsOptional() - resource_id?: string - - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 50 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit = 50 - - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - offset = 0 -} diff --git a/packages/medusa/src/api/routes/admin/notes/update-note.ts b/packages/medusa/src/api/routes/admin/notes/update-note.ts deleted file mode 100644 index 9e510cb161..0000000000 --- a/packages/medusa/src/api/routes/admin/notes/update-note.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { IsString } from "class-validator" -import NoteService from "../../../../services/note" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/notes/{id} - * operationId: "PostNotesNote" - * summary: "Update a Note" - * x-authenticated: true - * description: "Update a Note's details." - * parameters: - * - (path) id=* {string} The ID of the Note - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostNotesNoteReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notes.update(noteId, { - * value: "We delivered this order" - * }) - * .then(({ note }) => { - * console.log(note.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateNote } from "medusa-react" - * - * type Props = { - * noteId: string - * } - * - * const Note = ({ noteId }: Props) => { - * const updateNote = useAdminUpdateNote(noteId) - * // ... - * - * const handleUpdate = ( - * value: string - * ) => { - * updateNote.mutate({ - * value - * }, { - * onSuccess: ({ note }) => { - * console.log(note.value) - * } - * }) - * } - * - * // ... - * } - * - * export default Note - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/notes/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "value": "We delivered this order" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Notes - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminNotesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = await validator(AdminPostNotesNoteReq, req.body) - - const noteService: NoteService = req.scope.resolve("noteService") - const manager: EntityManager = req.scope.resolve("manager") - const note = await manager.transaction(async (transactionManager) => { - return await noteService - .withTransaction(transactionManager) - .update(id, validated.value) - }) - - res.status(200).json({ note }) -} - -/** - * @schema AdminPostNotesNoteReq - * type: object - * description: "The details to update of the note." - * required: - * - value - * properties: - * value: - * type: string - * description: The description of the Note. - */ -export class AdminPostNotesNoteReq { - @IsString() - value: string -} diff --git a/packages/medusa/src/api/routes/admin/notifications/index.ts b/packages/medusa/src/api/routes/admin/notifications/index.ts deleted file mode 100644 index 3e58d629c2..0000000000 --- a/packages/medusa/src/api/routes/admin/notifications/index.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Notification } from "./../../../../" -import { PaginatedResponse } from "@medusajs/types" -import { Router } from "express" -import middlewares from "../../../middlewares" - -const route = Router() - -export default (app) => { - app.use("/notifications", route) - - /** - * List notifications - */ - route.get("/", middlewares.wrap(require("./list-notifications").default)) - - /** - * Resend a notification - */ - route.post( - "/:id/resend", - middlewares.wrap(require("./resend-notification").default) - ) - - return app -} - -export const defaultAdminNotificationsRelations = ["resends"] - -export const defaultAdminNotificationsFields = [ - "id", - "resource_type", - "resource_id", - "event_name", - "to", - "provider_id", - "created_at", - "updated_at", -] - -/** - * @schema AdminNotificationsListRes - * type: object - * x-expanded-relations: - * field: notifications - * relations: - * - resends - * required: - * - notifications - * properties: - * notifications: - * type: array - * description: an array of notifications - * items: - * $ref: "#/components/schemas/Notification" - * count: - * type: integer - * description: The total number of notifications - * offset: - * type: integer - * description: The number of notifications skipped when retrieving the notifications. - * limit: - * type: integer - * description: The number of notifications per page - */ -export type AdminNotificationsListRes = PaginatedResponse & { - notifications: Notification[] -} - -/** - * @schema AdminNotificationsRes - * type: object - * description: "The notification's details." - * x-expanded-relations: - * field: notification - * relations: - * - resends - * required: - * - notification - * properties: - * notification: - * description: Notification details - * $ref: "#/components/schemas/Notification" - */ -export type AdminNotificationsRes = { - notification: Notification -} - -export * from "./list-notifications" -export * from "./resend-notification" diff --git a/packages/medusa/src/api/routes/admin/notifications/list-notifications.ts b/packages/medusa/src/api/routes/admin/notifications/list-notifications.ts deleted file mode 100644 index 992cb44174..0000000000 --- a/packages/medusa/src/api/routes/admin/notifications/list-notifications.ts +++ /dev/null @@ -1,250 +0,0 @@ -import { IsBooleanString, IsInt, IsOptional, IsString } from "class-validator" -import { - defaultAdminNotificationsFields, - defaultAdminNotificationsRelations, -} from "./" - -import { FindConfig } from "../../../../types/common" -import { Notification } from "../../../../models" -import { NotificationService } from "../../../../services" -import { Type } from "class-transformer" -import { pick } from "lodash" -import { validator } from "../../../../utils/validator" - -/** - * @oas [get] /admin/notifications - * operationId: "GetNotifications" - * summary: "List Notifications" - * description: "Retrieve a list of notifications. The notifications can be filtered by fields such as `event_name` or `resource_type`. The notifications can also be paginated." - * x-authenticated: true - * parameters: - * - (query) offset=0 {integer} The number of inventory items to skip when retrieving the inventory items. - * - (query) limit=50 {integer} Limit the number of notifications returned. - * - (query) fields {string} Comma-separated fields that should be included in each returned notification. - * - (query) expand {string} Comma-separated relations that should be expanded in each returned notification. - * - (query) event_name {string} Filter by the name of the event that triggered sending this notification. - * - (query) resource_type {string} Filter by the resource type. - * - (query) resource_id {string} Filter by the resource ID. - * - (query) to {string} Filter by the address that the Notification was sent to. This will usually be an email address, but it can also represent other addresses such as a chat bot user id. - * - (query) include_resends {string} A boolean indicating whether the result set should include resent notifications or not - * x-codegen: - * method: list - * queryParams: AdminGetNotificationsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notifications.list() - * .then(({ notifications }) => { - * console.log(notifications.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminNotifications } from "medusa-react" - * - * const Notifications = () => { - * const { notifications, isLoading } = useAdminNotifications() - * - * return ( - *
- * {isLoading && Loading...} - * {notifications && !notifications.length && ( - * No Notifications - * )} - * {notifications && notifications.length > 0 && ( - *
    - * {notifications.map((notification) => ( - *
  • {notification.to}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Notifications - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/notifications' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Notifications - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminNotificationsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const notificationService: NotificationService = req.scope.resolve( - "notificationService" - ) - const { - limit, - offset, - fields, - expand, - event_name, - resource_id, - resource_type, - to, - include_resends, - } = await validator(AdminGetNotificationsParams, req.query) - - const selector: Record = {} - - let includeFields: string[] = [] - if (fields) { - includeFields = fields.split(",") - } - - let expandFields: string[] = [] - if (expand) { - expandFields = expand.split(",") - } - - if (event_name) { - const values = event_name.split(",") - selector.event_name = values.length > 1 ? values : values[0] - } - - if (resource_type) { - const values = resource_type.split(",") - selector.resource_type = values.length > 1 ? values : values[0] - } - - if (resource_id) { - const values = resource_id.split(",") - selector.resource_id = values.length > 1 ? values : values[0] - } - - if (to) { - const values = to.split(",") - selector.to = values.length > 1 ? values : values[0] - } - - if (!include_resends || include_resends === "false") { - selector.parent_id = null - } - - const listConfig = { - select: (includeFields.length - ? includeFields - : defaultAdminNotificationsFields) as (keyof Notification)[], - relations: expandFields.length - ? expandFields - : defaultAdminNotificationsRelations, - skip: offset, - take: limit, - order: { created_at: "DESC" }, - } as FindConfig - - const [notifications, count] = await notificationService.listAndCount( - selector, - listConfig - ) - - const resultFields = [ - ...(listConfig.select ?? []), - ...(listConfig.relations ?? []), - ] - const data = notifications.map((o) => pick(o, resultFields)) - - res.json({ notifications: data, count, limit, offset }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved notifications. - */ -export class AdminGetNotificationsParams { - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 50 - */ - @IsOptional() - @IsInt() - @Type(() => Number) - limit?: number = 50 - - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsOptional() - @IsInt() - @Type(() => Number) - offset?: number = 0 - - /** - * {@inheritDoc FindParams.fields} - */ - @IsOptional() - @IsString() - fields?: string - - /** - * {@inheritDoc FindParams.expand} - */ - @IsOptional() - @IsString() - expand?: string - - /** - * Event name to filter notifications by. - */ - @IsOptional() - @IsString() - event_name?: string - - /** - * Resource type to filter notifications by. - */ - @IsOptional() - @IsString() - resource_type?: string - - /** - * Resource ID to filter notifications by. - */ - @IsOptional() - @IsString() - resource_id?: string - - /** - * Filter notifications by their `to` field. - */ - @IsOptional() - @IsString() - to?: string - - /** - * Whether to include resends in the results. - */ - @IsOptional() - @IsBooleanString() - include_resends?: string -} diff --git a/packages/medusa/src/api/routes/admin/notifications/resend-notification.ts b/packages/medusa/src/api/routes/admin/notifications/resend-notification.ts deleted file mode 100644 index d7f0ccd2d9..0000000000 --- a/packages/medusa/src/api/routes/admin/notifications/resend-notification.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { - defaultAdminNotificationsFields, - defaultAdminNotificationsRelations, -} from "." - -import { EntityManager } from "typeorm" -import { IsOptional, IsString } from "class-validator" -import { Notification } from "../../../../models" -import { NotificationService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/notifications/{id}/resend - * operationId: "PostNotificationsNotificationResend" - * summary: "Resend Notification" - * description: "Resend a previously sent notifications, with the same data but optionally to a different address." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Notification - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostNotificationsNotificationResendReq" - * x-codegen: - * method: resend - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.notifications.resend(notificationId) - * .then(({ notification }) => { - * console.log(notification.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminResendNotification } from "medusa-react" - * - * type Props = { - * notificationId: string - * } - * - * const Notification = ({ notificationId }: Props) => { - * const resendNotification = useAdminResendNotification( - * notificationId - * ) - * // ... - * - * const handleResend = () => { - * resendNotification.mutate({}, { - * onSuccess: ({ notification }) => { - * console.log(notification.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Notification - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/notifications/{id}/resend' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Notifications - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminNotificationsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validatedBody = await validator( - AdminPostNotificationsNotificationResendReq, - req.body - ) - - const notificationService: NotificationService = req.scope.resolve( - "notificationService" - ) - - const config: Record = {} - - if (validatedBody.to) { - config.to = validatedBody.to - } - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await notificationService - .withTransaction(transactionManager) - .resend(id, config) - }) - - const notification = await notificationService.retrieve(id, { - select: defaultAdminNotificationsFields as (keyof Notification)[], - relations: defaultAdminNotificationsRelations, - }) - - res.json({ notification }) -} - -/** - * @schema AdminPostNotificationsNotificationResendReq - * type: object - * description: "The resend details." - * properties: - * to: - * description: >- - * A new address or user identifier that the Notification should be sent to. If not provided, the previous `to` field of the notification will be used. - * type: string - */ -export class AdminPostNotificationsNotificationResendReq { - @IsOptional() - @IsString() - to?: string -} diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/cancel-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/cancel-order-edit.ts deleted file mode 100644 index 6266fe4e04..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/cancel-order-edit.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" - -describe("POST /admin/order-edits/:id/cancel", () => { - describe("cancels an order edit", () => { - const orderEditId = IdMap.getId("testCancelOrderEdit") - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/order-edits/${orderEditId}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - } - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService cancel", () => { - expect(orderEditServiceMock.cancel).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.cancel).toHaveBeenCalledWith(orderEditId, { - canceledBy: IdMap.getId("admin_user"), - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns cancel result", () => { - expect(subject.body.order_edit).toEqual( - expect.objectContaining({ - id: orderEditId, - canceled_at: expect.any(String), - status: "canceled", - }) - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/confirm-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/confirm-order-edit.ts deleted file mode 100644 index 62843e9640..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/confirm-order-edit.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" - -describe("POST /admin/order-edits/:id/confirm", () => { - describe("confirms an order edit", () => { - const orderEditId = IdMap.getId("testConfirmOrderEdit") - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/order-edits/${orderEditId}/confirm`, - { - adminSession: { - jwt: { - userId: "admin_user", - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService confirm", () => { - expect(orderEditServiceMock.confirm).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.confirm).toHaveBeenCalledWith(orderEditId, { - confirmedBy: "admin_user", - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns confirm result", () => { - expect(subject.body.order_edit).toEqual( - expect.objectContaining({ - id: orderEditId, - confirmed_at: expect.any(String), - confirmed_by: "admin_user", - status: "confirmed", - }) - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/create-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/create-order-edit.ts deleted file mode 100644 index 9c4c0ee4b0..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/create-order-edit.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" - -describe("POST /admin/order-edits", () => { - describe("successfully create an order edit", () => { - const orderId = IdMap.getId("order-edit-order-id-test") - const internalNote = "test internal note" - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/order-edits", { - payload: { - order_id: orderId, - internal_note: internalNote, - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(async () => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls order edit service create", () => { - expect(orderEditServiceMock.decorateTotals).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.create).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.create).toHaveBeenCalledWith( - { - order_id: orderId, - internal_note: internalNote, - }, - { - createdBy: IdMap.getId("admin_user"), - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/delete-line-item.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/delete-line-item.ts deleted file mode 100644 index 2fcdef25a8..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/delete-line-item.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" - -describe("DELETE /admin/order-edits/:id/items/:item_id", () => { - describe("deletes a line item", () => { - const lineItemId = IdMap.getId("testLineItem") - const orderEditId = IdMap.getId("testCreatedOrder") - let subject - - beforeAll(async () => { - subject = await request("DELETE", `/admin/order-edits/${orderEditId}/items/${lineItemId}`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService removeLineItem", () => { - expect(orderEditServiceMock.removeLineItem).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.removeLineItem).toHaveBeenCalledWith(orderEditId, lineItemId) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns retrieve result", () => { - expect(subject.body.order_edit).toEqual(expect.objectContaining({ - id: orderEditId, - })) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/delete-order-edit-item-change.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/delete-order-edit-item-change.ts deleted file mode 100644 index 873c0f98db..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/delete-order-edit-item-change.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" - -describe("DELETE /admin/order-edits/:id/changes/:change_id", () => { - describe("deletes an order edit item change", () => { - const orderEditId = IdMap.getId("test-order-edit") - const orderEditItemChangeId = IdMap.getId("test-order-edit-item-change") - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/order-edits/${orderEditId}/changes/${orderEditItemChangeId}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderEditService delete", () => { - expect(orderEditServiceMock.deleteItemChange).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.deleteItemChange).toHaveBeenCalledWith( - orderEditId, - orderEditItemChangeId - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns delete result", () => { - expect(subject.body).toEqual({ - id: orderEditItemChangeId, - object: "item_change", - deleted: true, - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/delete-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/delete-order-edit.ts deleted file mode 100644 index e6eb06b791..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/delete-order-edit.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" - -describe("DELETE /admin/order-edits/:id", () => { - describe("deletes an order edit", () => { - const orderEditId = IdMap.getId("test-order-edit") - let subject - - beforeAll(async () => { - subject = await request("DELETE", `/admin/order-edits/${orderEditId}`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderEditService delete", () => { - expect(orderEditServiceMock.delete).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.delete).toHaveBeenCalledWith(orderEditId) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns delete result", () => { - expect(subject.body).toEqual({ - id: orderEditId, - object: "order_edit", - deleted: true, - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/get-order.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/get-order.ts deleted file mode 100644 index f0eee17bd7..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/get-order.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" -import { - defaultOrderEditFields, - defaultOrderEditRelations, -} from "../../../../../types/order-edit" - -describe("GET /admin/order-edits/:id", () => { - describe("successfully gets an order edit", () => { - const orderEditId = IdMap.getId("testCreatedOrder") - let subject - - beforeAll(async () => { - subject = await request("GET", `/admin/order-edits/${orderEditId}`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService retrieve", () => { - expect(orderEditServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.retrieve).toHaveBeenCalledWith(orderEditId, { - select: defaultOrderEditFields, - relations: defaultOrderEditRelations, - }) - expect(orderEditServiceMock.decorateTotals).toHaveBeenCalledTimes(1) - }) - - it("returns order", () => { - expect(subject.body.order_edit.id).toEqual(orderEditId) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/list-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/list-order-edit.ts deleted file mode 100644 index 704e7188d6..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/list-order-edit.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" -import { - defaultOrderEditFields, - defaultOrderEditRelations -} from "../../../../../types/order-edit" - -describe("GET /admin/order-edits", () => { - describe("successfully list order edits", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/admin/order-edits`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService listAndCount", () => { - expect(orderEditServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - { - select: defaultOrderEditFields, - relations: defaultOrderEditRelations, - order: { created_at: "DESC" }, - skip: 0, - take: 20, - } - ) - expect(orderEditServiceMock.decorateTotals).toHaveBeenCalledTimes(1) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/request-confirmation.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/request-confirmation.ts deleted file mode 100644 index a1f3ffca48..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/request-confirmation.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" - -describe("GET /admin/order-edits/:id", () => { - describe("successfully requests an order edit confirmation", () => { - const orderEditId = IdMap.getId("testRequestOrder") - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/order-edits/${orderEditId}/request`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - payload: { - payment_collection_description: "PayCol description", - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderEditService requestConfirmation", () => { - expect(orderEditServiceMock.requestConfirmation).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.requestConfirmation).toHaveBeenCalledWith( - orderEditId, - { requestedBy: IdMap.getId("admin_user") } - ) - }) - - it("returns updated orderEdit", () => { - expect(subject.body.order_edit).toEqual( - expect.objectContaining({ - id: orderEditId, - requested_at: expect.any(String), - requested_by: IdMap.getId("admin_user"), - }) - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/order-edits/__tests__/update-order-edit-line-item.ts b/packages/medusa/src/api/routes/admin/order-edits/__tests__/update-order-edit-line-item.ts deleted file mode 100644 index d1b0be3ee7..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/__tests__/update-order-edit-line-item.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" - -describe("POST /admin/order-edits/:id/items/:item_id", () => { - describe("update line item and create an item change of type update", () => { - const orderEditId = IdMap.getId("test-order-edit") - const lineItemId = IdMap.getId("line-item") - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/order-edits/${orderEditId}/items/${lineItemId}`, - { - payload: { - quantity: 3, - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderEditService updateLineItem", () => { - expect(orderEditServiceMock.updateLineItem).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.updateLineItem).toHaveBeenCalledWith( - orderEditId, - lineItemId, - { quantity: 3 } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/order-edits/add-line-item.ts b/packages/medusa/src/api/routes/admin/order-edits/add-line-item.ts deleted file mode 100644 index 6118255489..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/add-line-item.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { Request, Response } from "express" -import { IsInt, IsOptional, IsString } from "class-validator" -import { EntityManager } from "typeorm" - -import { OrderEditService } from "../../../../services" -import { - defaultOrderEditFields, - defaultOrderEditRelations, -} from "../../../../types/order-edit" - -/** - * @oas [post] /admin/order-edits/{id}/items - * operationId: "PostOrderEditsEditLineItems" - * summary: "Add a Line Item" - * description: "Create a line item change in the order edit that indicates adding an item in the original order. The item will not be added to the original order until the order edit is - * confirmed." - * parameters: - * - (path) id=* {string} The ID of the Order Edit. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrderEditsEditLineItemsReq" - * x-authenticated: true - * x-codegen: - * method: addLineItem - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.addLineItem(orderEditId, { - * variant_id, - * quantity - * }) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminOrderEditAddLineItem } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const addLineItem = useAdminOrderEditAddLineItem( - * orderEditId - * ) - * - * const handleAddLineItem = - * (quantity: number, variantId: string) => { - * addLineItem.mutate({ - * quantity, - * variant_id: variantId, - * }, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.changes) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/order-edits/{id}/items' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ "variant_id": "variant_01G1G5V2MRX2V3PVSR2WXYPFB6", "quantity": 3 }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrderEditsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const orderEditService = req.scope.resolve( - "orderEditService" - ) as OrderEditService - - const { id } = req.params - - const manager = req.scope.resolve("manager") as EntityManager - - const data = req.validatedBody as AdminPostOrderEditsEditLineItemsReq - - await manager.transaction(async (transactionManager) => { - await orderEditService - .withTransaction(transactionManager) - .addLineItem(id, data) - }) - - let orderEdit = await orderEditService.retrieve(id, { - select: defaultOrderEditFields, - relations: defaultOrderEditRelations, - }) - - orderEdit = await orderEditService.decorateTotals(orderEdit) - - res.status(200).send({ - order_edit: orderEdit, - }) -} - -/** - * @schema AdminPostOrderEditsEditLineItemsReq - * type: object - * description: "The details of the line item change to create." - * required: - * - variant_id - * - quantity - * properties: - * variant_id: - * description: The ID of the product variant associated with the item. - * type: string - * quantity: - * description: The quantity of the item. - * type: number - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostOrderEditsEditLineItemsReq { - @IsString() - variant_id: string - - @IsInt() - quantity: number - - @IsOptional() - metadata?: Record | undefined -} diff --git a/packages/medusa/src/api/routes/admin/order-edits/cancel-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/cancel-order-edit.ts deleted file mode 100644 index 8ba987ae5d..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/cancel-order-edit.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { OrderEditService } from "../../../../services" -import { - defaultOrderEditFields, - defaultOrderEditRelations, -} from "../../../../types/order-edit" - -/** - * @oas [post] /admin/order-edits/{id}/cancel - * operationId: "PostOrderEditsOrderEditCancel" - * summary: "Cancel an Order Edit" - * description: "Cancel an Order Edit." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the OrderEdit. - * x-codegen: - * method: cancel - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.cancel(orderEditId) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminCancelOrderEdit - * } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const cancelOrderEdit = - * useAdminCancelOrderEdit( - * orderEditId - * ) - * - * const handleCancel = () => { - * cancelOrderEdit.mutate(void 0, { - * onSuccess: ({ order_edit }) => { - * console.log( - * order_edit.id - * ) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/order-edits/{id}/cancel' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrderEditsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const orderEditService = req.scope.resolve( - "orderEditService" - ) as OrderEditService - - const manager = req.scope.resolve("manager") as EntityManager - - const userId = req.user?.id ?? req.user?.userId - - await manager.transaction(async (transactionManager) => { - await orderEditService - .withTransaction(transactionManager) - .cancel(id, { canceledBy: userId }) - }) - - let orderEdit = await orderEditService.retrieve(id, { - select: defaultOrderEditFields, - relations: defaultOrderEditRelations, - }) - orderEdit = await orderEditService.decorateTotals(orderEdit) - - return res.json({ order_edit: orderEdit }) -} diff --git a/packages/medusa/src/api/routes/admin/order-edits/confirm-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/confirm-order-edit.ts deleted file mode 100644 index cfd4c070b7..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/confirm-order-edit.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { OrderEditService } from "../../../../services" -import { - defaultOrderEditFields, - defaultOrderEditRelations, -} from "../../../../types/order-edit" - -/** - * @oas [post] /admin/order-edits/{id}/confirm - * operationId: "PostOrderEditsOrderEditConfirm" - * summary: "Confirm an OrderEdit" - * description: "Confirm an Order Edit. This will reflect the changes in the order edit on the associated order." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the order edit. - * x-codegen: - * method: confirm - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.confirm(orderEditId) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminConfirmOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const confirmOrderEdit = useAdminConfirmOrderEdit( - * orderEditId - * ) - * - * const handleConfirmOrderEdit = () => { - * confirmOrderEdit.mutate(void 0, { - * onSuccess: ({ order_edit }) => { - * console.log( - * order_edit.confirmed_at, - * order_edit.confirmed_by - * ) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/order-edits/{id}/confirm' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrderEditsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const orderEditService = req.scope.resolve( - "orderEditService" - ) as OrderEditService - - const manager = req.scope.resolve("manager") as EntityManager - - const userId = req.user?.id ?? req.user?.userId - - await manager.transaction(async (transactionManager) => { - await orderEditService - .withTransaction(transactionManager) - .confirm(id, { confirmedBy: userId }) - }) - - let orderEdit = await orderEditService.retrieve(id, { - select: defaultOrderEditFields, - relations: defaultOrderEditRelations, - }) - orderEdit = await orderEditService.decorateTotals(orderEdit) - - return res.json({ order_edit: orderEdit }) -} diff --git a/packages/medusa/src/api/routes/admin/order-edits/create-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/create-order-edit.ts deleted file mode 100644 index 2ff425f514..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/create-order-edit.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { OrderEditService } from "../../../../services" -import { - defaultOrderEditFields, - defaultOrderEditRelations, -} from "../../../../types/order-edit" - -/** - * @oas [post] /admin/order-edits - * operationId: "PostOrderEdits" - * summary: "Create an OrderEdit" - * description: "Create an Order Edit." - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrderEditsReq" - * x-authenticated: true - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.create({ orderId }) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateOrderEdit } from "medusa-react" - * - * const CreateOrderEdit = () => { - * const createOrderEdit = useAdminCreateOrderEdit() - * - * const handleCreateOrderEdit = (orderId: string) => { - * createOrderEdit.mutate({ - * order_id: orderId, - * }, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateOrderEdit - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/order-edits' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ "order_id": "my_order_id", "internal_note": "my_optional_note" }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrderEditsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const orderEditService = req.scope.resolve( - "orderEditService" - ) as OrderEditService - const manager = req.scope.resolve("manager") as EntityManager - - const data = req.validatedBody as AdminPostOrderEditsReq - const createdBy = (req.user?.id ?? req.user?.userId) as string - - const createdOrderEdit = await manager.transaction( - async (transactionManager) => { - return await orderEditService - .withTransaction(transactionManager) - .create(data, { createdBy }) - } - ) - - let orderEdit = await orderEditService.retrieve(createdOrderEdit.id, { - select: defaultOrderEditFields, - relations: defaultOrderEditRelations, - }) - orderEdit = await orderEditService.decorateTotals(orderEdit) - - return res.json({ order_edit: orderEdit }) -} - -/** - * @schema AdminPostOrderEditsReq - * type: object - * description: "The details of the order edit to create." - * required: - * - order_id - * properties: - * order_id: - * description: The ID of the order to create the edit for. - * type: string - * internal_note: - * description: An optional note to associate with the order edit. - * type: string - */ -export class AdminPostOrderEditsReq { - @IsString() - order_id: string - - @IsOptional() - @IsString() - internal_note?: string - - @IsOptional() - @IsString() - created_by?: string -} diff --git a/packages/medusa/src/api/routes/admin/order-edits/delete-line-item.ts b/packages/medusa/src/api/routes/admin/order-edits/delete-line-item.ts deleted file mode 100644 index 2737dbd161..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/delete-line-item.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { EntityManager } from "typeorm" -import { OrderEditService } from "../../../../services" -import { Request, Response } from "express" -import { - defaultOrderEditFields, - defaultOrderEditRelations, -} from "../../../../types/order-edit" - -/** - * @oas [delete] /admin/order-edits/{id}/items/{item_id} - * operationId: "DeleteOrderEditsOrderEditLineItemsLineItem" - * summary: "Delete Line Item" - * description: "Create a line item change in the order edit that indicates deleting an item in the original order. The item in the original order will not be deleted until the order edit is - * confirmed." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order Edit. - * - (path) item_id=* {string} The ID of line item in the original order. - * x-codegen: - * method: removeLineItem - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.removeLineItem(orderEditId, lineItemId) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminOrderEditDeleteLineItem } from "medusa-react" - * - * type Props = { - * orderEditId: string - * itemId: string - * } - * - * const OrderEditLineItem = ({ - * orderEditId, - * itemId - * }: Props) => { - * const removeLineItem = useAdminOrderEditDeleteLineItem( - * orderEditId, - * itemId - * ) - * - * const handleRemoveLineItem = () => { - * removeLineItem.mutate(void 0, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.changes) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEditLineItem - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/order-edits/{id}/items/{item_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrderEditsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id, item_id } = req.params - - const orderEditService: OrderEditService = - req.scope.resolve("orderEditService") - - const manager: EntityManager = req.scope.resolve("manager") - - await manager.transaction(async (transactionManager) => { - await orderEditService - .withTransaction(transactionManager) - .removeLineItem(id, item_id) - }) - - let orderEdit = await orderEditService.retrieve(id, { - select: defaultOrderEditFields, - relations: defaultOrderEditRelations, - }) - orderEdit = await orderEditService.decorateTotals(orderEdit) - - res.status(200).send({ - order_edit: orderEdit, - }) -} diff --git a/packages/medusa/src/api/routes/admin/order-edits/delete-order-edit-item-change.ts b/packages/medusa/src/api/routes/admin/order-edits/delete-order-edit-item-change.ts deleted file mode 100644 index a5d1dfb4fe..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/delete-order-edit-item-change.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { EntityManager } from "typeorm" -import { OrderEditService } from "../../../../services" - -/** - * @oas [delete] /admin/order-edits/{id}/changes/{change_id} - * operationId: "DeleteOrderEditsOrderEditItemChange" - * summary: "Delete a Line Item Change" - * description: "Delete a line item change that indicates the addition, deletion, or update of a line item in the original order." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order Edit. - * - (path) change_id=* {string} The ID of the Line Item Change to delete. - * x-codegen: - * method: deleteItemChange - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.deleteItemChange(orderEdit_id, itemChangeId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteOrderEditItemChange } from "medusa-react" - * - * type Props = { - * orderEditId: string - * itemChangeId: string - * } - * - * const OrderEditItemChange = ({ - * orderEditId, - * itemChangeId - * }: Props) => { - * const deleteItemChange = useAdminDeleteOrderEditItemChange( - * orderEditId, - * itemChangeId - * ) - * - * const handleDeleteItemChange = () => { - * deleteItemChange.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEditItemChange - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/order-edits/{id}/changes/{change_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrderEditItemChangeDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - */ -export default async (req, res) => { - const { id, change_id } = req.params - - const orderEditService: OrderEditService = - req.scope.resolve("orderEditService") - - const manager: EntityManager = req.scope.resolve("manager") - - await manager.transaction(async (transactionManager) => { - await orderEditService - .withTransaction(transactionManager) - .deleteItemChange(id, change_id) - }) - - res.status(200).send({ - id: change_id, - object: "item_change", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/order-edits/delete-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/delete-order-edit.ts deleted file mode 100644 index af3b99b357..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/delete-order-edit.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { EntityManager } from "typeorm" -import { OrderEditService } from "../../../../services" - -/** - * @oas [delete] /admin/order-edits/{id} - * operationId: "DeleteOrderEditsOrderEdit" - * summary: "Delete an Order Edit" - * description: "Delete an Order Edit. Only order edits that have the status `created` can be deleted." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order Edit to delete. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.delete(orderEditId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const deleteOrderEdit = useAdminDeleteOrderEdit( - * orderEditId - * ) - * - * const handleDelete = () => { - * deleteOrderEdit.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/order-edits/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrderEditDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - */ -export default async (req, res) => { - const { id } = req.params - - const orderEditService: OrderEditService = - req.scope.resolve("orderEditService") - - const manager: EntityManager = req.scope.resolve("manager") - - await manager.transaction(async (transactionManager) => { - await orderEditService.withTransaction(transactionManager).delete(id) - }) - - res.status(200).send({ - id, - object: "order_edit", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/order-edits/get-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/get-order-edit.ts deleted file mode 100644 index a153dc536a..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/get-order-edit.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Request, Response } from "express" -import { OrderEditService } from "../../../../services" -import { FindParams } from "../../../../types/common" - -/** - * @oas [get] /admin/order-edits/{id} - * operationId: "GetOrderEditsOrderEdit" - * summary: "Get an Order Edit" - * description: "Retrieve an Order Edit's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the OrderEdit. - * - (query) expand {string} Comma-separated relations that should be expanded in each returned order edit. - * - (query) fields {string} Comma-separated fields that should be included in the returned order edit. - * x-codegen: - * method: retrieve - * queryParams: GetOrderEditsOrderEditParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.retrieve(orderEditId) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const { - * order_edit, - * isLoading, - * } = useAdminOrderEdit(orderEditId) - * - * return ( - *
- * {isLoading && Loading...} - * {order_edit && {order_edit.status}} - *
- * ) - * } - * - * export default OrderEdit - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/order-edits/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrderEditsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const orderEditService: OrderEditService = - req.scope.resolve("orderEditService") - - const { id } = req.params - const retrieveConfig = req.retrieveConfig - - let orderEdit = await orderEditService.retrieve(id, retrieveConfig) - orderEdit = await orderEditService.decorateTotals(orderEdit) - - return res.json({ order_edit: orderEdit }) -} - -export class GetOrderEditsOrderEditParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/order-edits/index.ts b/packages/medusa/src/api/routes/admin/order-edits/index.ts deleted file mode 100644 index be6ba64473..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/index.ts +++ /dev/null @@ -1,270 +0,0 @@ -import { Router } from "express" - -import { OrderEdit } from "../../../../models" -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import { - defaultOrderEditFields, - defaultOrderEditRelations, -} from "../../../../types/order-edit" -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" -import { AdminPostOrderEditsEditLineItemsReq } from "./add-line-item" -import { AdminPostOrderEditsReq } from "./create-order-edit" -import { GetOrderEditsOrderEditParams } from "./get-order-edit" -import { GetOrderEditsParams } from "./list-order-edit" -import { AdminPostOrderEditsRequestConfirmationReq } from "./request-confirmation" -import { AdminPostOrderEditsOrderEditReq } from "./update-order-edit" -import { AdminPostOrderEditsEditLineItemsLineItemReq } from "./update-order-edit-line-item" - -const route = Router() - -export default (app) => { - app.use("/order-edits", route) - - route.post( - "/", - transformBody(AdminPostOrderEditsReq), - middlewares.wrap(require("./create-order-edit").default) - ) - - route.get( - "/", - transformQuery(GetOrderEditsParams, { - defaultFields: defaultOrderEditFields, - defaultRelations: defaultOrderEditRelations, - isList: true, - }), - middlewares.wrap(require("./list-order-edit").default) - ) - - route.get( - "/:id", - transformQuery(GetOrderEditsOrderEditParams, { - defaultRelations: defaultOrderEditRelations, - defaultFields: defaultOrderEditFields, - isList: false, - }), - middlewares.wrap(require("./get-order-edit").default) - ) - - route.post( - "/:id", - transformBody(AdminPostOrderEditsOrderEditReq), - middlewares.wrap(require("./update-order-edit").default) - ) - - route.post( - "/:id/cancel", - middlewares.wrap(require("./cancel-order-edit").default) - ) - - route.post( - "/:id/items", - transformBody(AdminPostOrderEditsEditLineItemsReq), - middlewares.wrap(require("./add-line-item").default) - ) - - route.post( - "/:id/confirm", - middlewares.wrap(require("./confirm-order-edit").default) - ) - - route.delete("/:id", middlewares.wrap(require("./delete-order-edit").default)) - - route.delete( - "/:id/changes/:change_id", - middlewares.wrap(require("./delete-order-edit-item-change").default) - ) - - route.post( - "/:id/request", - transformBody(AdminPostOrderEditsRequestConfirmationReq), - middlewares.wrap(require("./request-confirmation").default) - ) - - route.post( - "/:id/items/:item_id", - transformBody(AdminPostOrderEditsEditLineItemsLineItemReq), - middlewares.wrap(require("./update-order-edit-line-item").default) - ) - - route.delete( - "/:id/items/:item_id", - middlewares.wrap(require("./delete-line-item").default) - ) - - return app -} - -/** - * @schema AdminOrderEditsRes - * type: object - * description: "The order edit details." - * x-expanded-relations: - * field: order_edit - * relations: - * - changes - * - changes.line_item - * - changes.line_item.variant - * - changes.original_line_item - * - changes.original_line_item.variant - * - items - * - items.adjustments - * - items.tax_lines - * - items.variant - * - payment_collection - * implicit: - * - items - * - items.tax_lines - * - items.adjustments - * - items.variant - * totals: - * - difference_due - * - discount_total - * - gift_card_tax_total - * - gift_card_total - * - shipping_total - * - subtotal - * - tax_total - * - total - * - items.discount_total - * - items.gift_card_total - * - items.original_tax_total - * - items.original_total - * - items.refundable - * - items.subtotal - * - items.tax_total - * - items.total - * required: - * - order_edit - * properties: - * order_edit: - * description: "Order edit details" - * $ref: "#/components/schemas/OrderEdit" - */ -export type AdminOrderEditsRes = { - order_edit: OrderEdit -} - -/** - * @schema AdminOrderEditsListRes - * type: object - * description: "The list of order edits with pagination fields." - * x-expanded-relations: - * field: order_edits - * relations: - * - changes - * - changes.line_item - * - changes.line_item.variant - * - changes.original_line_item - * - changes.original_line_item.variant - * - items - * - items.adjustments - * - items.tax_lines - * - items.variant - * - payment_collection - * implicit: - * - items - * - items.tax_lines - * - items.adjustments - * - items.variant - * totals: - * - difference_due - * - discount_total - * - gift_card_tax_total - * - gift_card_total - * - shipping_total - * - subtotal - * - tax_total - * - total - * - items.discount_total - * - items.gift_card_total - * - items.original_tax_total - * - items.original_total - * - items.refundable - * - items.subtotal - * - items.tax_total - * - items.total - * required: - * - order_edits - * - count - * - offset - * - limit - * properties: - * order_edits: - * type: array - * description: "An array of order edit details" - * items: - * $ref: "#/components/schemas/OrderEdit" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of order edits skipped when retrieving the order edits. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminOrderEditsListRes = PaginatedResponse & { - order_edits: OrderEdit[] -} - -/** - * @schema AdminOrderEditDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Order Edit. - * object: - * type: string - * description: The type of the object that was deleted. - * default: order_edit - * deleted: - * type: boolean - * description: Whether or not the Order Edit was deleted. - * default: true - */ -export type AdminOrderEditDeleteRes = DeleteResponse - -/** - * @schema AdminOrderEditItemChangeDeleteRes - * type: object - * description: "The details of deleting order edit item changes." - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Order Edit Item Change. - * object: - * type: string - * description: The type of the object that was deleted. - * default: item_change - * deleted: - * type: boolean - * description: Whether or not the Order Edit Item Change was deleted. - * default: true - */ -export type AdminOrderEditItemChangeDeleteRes = { - id: string - object: "item_change" - deleted: boolean -} - -export * from "./add-line-item" -export * from "./create-order-edit" -export * from "./get-order-edit" -export * from "./list-order-edit" -export * from "./request-confirmation" -export * from "./update-order-edit" -export * from "./update-order-edit-line-item" diff --git a/packages/medusa/src/api/routes/admin/order-edits/list-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/list-order-edit.ts deleted file mode 100644 index 6486ea5990..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/list-order-edit.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { Request, Response } from "express" -import { OrderEditService } from "../../../../services" -import { extendedFindParamsMixin } from "../../../../types/common" -import { IsOptional, IsString } from "class-validator" - -/** - * @oas [get] /admin/order-edits - * operationId: "GetOrderEdits" - * summary: "List Order Edits" - * description: "Retrieve a list of order edits. The order edits can be filtered by fields such as `q` or `order_id`. The order edits can also be paginated." - * x-authenticated: true - * parameters: - * - (query) q {string} term to search order edits' internal note. - * - (query) order_id {string} Filter by order ID - * - (query) limit=20 {number} Limit the number of order edits returned. - * - (query) offset=0 {number} The number of order edits to skip when retrieving the order edits. - * - (query) expand {string} Comma-separated relations that should be expanded in each returned order edit. - * - (query) fields {string} Comma-separated fields that should be included in each returned order edit. - * x-codegen: - * method: list - * queryParams: GetOrderEditsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.list() - * .then(({ order_edits, count, limit, offset }) => { - * console.log(order_edits.length) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminOrderEdits } from "medusa-react" - * - * const OrderEdits = () => { - * const { order_edits, isLoading } = useAdminOrderEdits() - * - * return ( - *
- * {isLoading && Loading...} - * {order_edits && !order_edits.length && ( - * No Order Edits - * )} - * {order_edits && order_edits.length > 0 && ( - *
    - * {order_edits.map((orderEdit) => ( - *
  • - * {orderEdit.status} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default OrderEdits - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/order-edits' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrderEditsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const orderEditService: OrderEditService = - req.scope.resolve("orderEditService") - - const { filterableFields, listConfig } = req - const { skip, take } = listConfig - - const [orderEdits, orderEditCount] = await orderEditService.listAndCount( - filterableFields, - listConfig - ) - - for (let orderEdit of orderEdits) { - orderEdit = await orderEditService.decorateTotals(orderEdit) - } - - return res.json({ - order_edits: orderEdits, - count: orderEditCount, - limit: take, - offset: skip, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved order edits. - */ -export class GetOrderEditsParams extends extendedFindParamsMixin({ - limit: 20, - offset: 0, -}) { - /** - * Search term to search order edits by their internal note. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Filter the order edits by their associated order's ID. - */ - @IsString() - @IsOptional() - order_id?: string -} diff --git a/packages/medusa/src/api/routes/admin/order-edits/request-confirmation.ts b/packages/medusa/src/api/routes/admin/order-edits/request-confirmation.ts deleted file mode 100644 index a5ba7dc102..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/request-confirmation.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { IsOptional, IsString } from "class-validator" -import { EntityManager } from "typeorm" -import { PaymentCollectionType } from "../../../../models" -import { - OrderEditService, - OrderService, - PaymentCollectionService, -} from "../../../../services" -import { - defaultOrderEditFields, - defaultOrderEditRelations, -} from "../../../../types/order-edit" - -/** - * @oas [post] /admin/order-edits/{id}/request - * operationId: "PostOrderEditsOrderEditRequest" - * summary: "Request Confirmation" - * description: "Request customer confirmation of an Order Edit. This would emit the event `order-edit.requested` which Notification Providers listen to and send - * a notification to the customer about the order edit." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order Edit. - * x-codegen: - * method: requestConfirmation - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.requestConfirmation(orderEditId) - * .then({ order_edit }) => { - * console.log(order_edit.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminRequestOrderEditConfirmation, - * } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const requestOrderConfirmation = - * useAdminRequestOrderEditConfirmation( - * orderEditId - * ) - * - * const handleRequestConfirmation = () => { - * requestOrderConfirmation.mutate(void 0, { - * onSuccess: ({ order_edit }) => { - * console.log( - * order_edit.requested_at, - * order_edit.requested_by - * ) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/order-edits/{id}/request' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrderEditsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const validatedBody = - req.validatedBody as AdminPostOrderEditsRequestConfirmationReq - - const orderEditService: OrderEditService = - req.scope.resolve("orderEditService") - - const orderService: OrderService = req.scope.resolve("orderService") - - const paymentCollectionService: PaymentCollectionService = req.scope.resolve( - "paymentCollectionService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - - const loggedInUser = (req.user?.id ?? req.user?.userId) as string - - await manager.transaction(async (transactionManager) => { - const orderEditServiceTx = - orderEditService.withTransaction(transactionManager) - - const orderEdit = await orderEditServiceTx.requestConfirmation(id, { - requestedBy: loggedInUser, - }) - - const total = await orderEditServiceTx.decorateTotals(orderEdit) - - if (total.difference_due > 0) { - const order = await orderService - .withTransaction(transactionManager) - .retrieve(orderEdit.order_id, { - select: ["currency_code", "region_id"], - }) - - const paymentCollection = await paymentCollectionService - .withTransaction(transactionManager) - .create({ - type: PaymentCollectionType.ORDER_EDIT, - amount: total.difference_due, - currency_code: order.currency_code, - region_id: order.region_id, - description: validatedBody.payment_collection_description, - created_by: loggedInUser, - }) - - orderEdit.payment_collection_id = paymentCollection.id - - await orderEditServiceTx.update(orderEdit.id, { - payment_collection_id: paymentCollection.id, - }) - } - }) - - let orderEdit = await orderEditService.retrieve(id, { - relations: defaultOrderEditRelations, - select: defaultOrderEditFields, - }) - orderEdit = await orderEditService.decorateTotals(orderEdit) - - res.status(200).send({ - order_edit: orderEdit, - }) -} - -export class AdminPostOrderEditsRequestConfirmationReq { - @IsString() - @IsOptional() - payment_collection_description?: string | undefined -} diff --git a/packages/medusa/src/api/routes/admin/order-edits/update-order-edit-line-item.ts b/packages/medusa/src/api/routes/admin/order-edits/update-order-edit-line-item.ts deleted file mode 100644 index 7467cc535c..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/update-order-edit-line-item.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { EntityManager } from "typeorm" -import { OrderEditService } from "../../../../services" -import { Request, Response } from "express" -import { IsNumber } from "class-validator" -import { - defaultOrderEditFields, - defaultOrderEditRelations, -} from "../../../../types/order-edit" - -/** - * @oas [post] /admin/order-edits/{id}/items/{item_id} - * operationId: "PostOrderEditsEditLineItemsLineItem" - * summary: "Upsert Line Item Change" - * description: "Create or update a line item change in the order edit that indicates addition, deletion, or update of a line item into an original order. Line item changes - * are only reflected on the original order after the order edit is confirmed." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order Edit. - * - (path) item_id=* {string} The ID of the line item in the original order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrderEditsEditLineItemsLineItemReq" - * x-codegen: - * method: updateLineItem - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.updateLineItem(orderEditId, lineItemId, { - * quantity: 5 - * }) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminOrderEditUpdateLineItem } from "medusa-react" - * - * type Props = { - * orderEditId: string - * itemId: string - * } - * - * const OrderEditItemChange = ({ - * orderEditId, - * itemId - * }: Props) => { - * const updateLineItem = useAdminOrderEditUpdateLineItem( - * orderEditId, - * itemId - * ) - * - * const handleUpdateLineItem = (quantity: number) => { - * updateLineItem.mutate({ - * quantity, - * }, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.items) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEditItemChange - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/order-edits/{id}/items/{item_id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ "quantity": 5 }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrderEditsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id, item_id } = req.params - - const validatedBody = - req.validatedBody as AdminPostOrderEditsEditLineItemsLineItemReq - - const orderEditService: OrderEditService = - req.scope.resolve("orderEditService") - - const manager: EntityManager = req.scope.resolve("manager") - - const decoratedEdit = await manager.transaction( - async (transactionManager) => { - const orderEditTx = orderEditService.withTransaction(transactionManager) - - await orderEditTx.updateLineItem(id, item_id, validatedBody) - - const orderEdit = await orderEditTx.retrieve(id, { - select: defaultOrderEditFields, - relations: defaultOrderEditRelations, - }) - - await orderEditTx.decorateTotals(orderEdit) - - return orderEdit - } - ) - - res.status(200).send({ - order_edit: decoratedEdit, - }) -} - -/** - * @schema AdminPostOrderEditsEditLineItemsLineItemReq - * type: object - * description: "The details to create or update of the line item change." - * required: - * - quantity - * properties: - * quantity: - * description: The quantity to update - * type: number - */ -export class AdminPostOrderEditsEditLineItemsLineItemReq { - @IsNumber() - quantity: number -} diff --git a/packages/medusa/src/api/routes/admin/order-edits/update-order-edit.ts b/packages/medusa/src/api/routes/admin/order-edits/update-order-edit.ts deleted file mode 100644 index 50cabc6ab8..0000000000 --- a/packages/medusa/src/api/routes/admin/order-edits/update-order-edit.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" - -import { OrderEditService } from "../../../../services" -import { - defaultOrderEditFields, - defaultOrderEditRelations, -} from "../../../../types/order-edit" - -/** - * @oas [post] /admin/order-edits/{id} - * operationId: "PostOrderEditsOrderEdit" - * summary: "Update an Order Edit" - * description: "Update an Order Edit's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the OrderEdit. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrderEditsOrderEditReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orderEdits.update(orderEditId, { - * internal_note: "internal reason XY" - * }) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const updateOrderEdit = useAdminUpdateOrderEdit( - * orderEditId, - * ) - * - * const handleUpdate = ( - * internalNote: string - * ) => { - * updateOrderEdit.mutate({ - * internal_note: internalNote - * }, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.internal_note) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/order-edits/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "internal_note": "internal reason XY" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrderEditsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - const { validatedBody } = req as { - validatedBody: AdminPostOrderEditsOrderEditReq - } - - const orderEditService: OrderEditService = - req.scope.resolve("orderEditService") - - const manager: EntityManager = req.scope.resolve("manager") - - const updatedOrderEdit = await manager.transaction( - async (transactionManager) => { - return await orderEditService - .withTransaction(transactionManager) - .update(id, validatedBody) - } - ) - - let orderEdit = await orderEditService.retrieve(updatedOrderEdit.id, { - select: defaultOrderEditFields, - relations: defaultOrderEditRelations, - }) - orderEdit = await orderEditService.decorateTotals(orderEdit) - - res.status(200).json({ order_edit: orderEdit }) -} - -/** - * @schema AdminPostOrderEditsOrderEditReq - * type: object - * description: "The details to update of the order edit." - * properties: - * internal_note: - * description: An optional note to create or update in the order edit. - * type: string - */ -export class AdminPostOrderEditsOrderEditReq { - @IsOptional() - @IsString() - internal_note?: string -} diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/archive-order.js b/packages/medusa/src/api/routes/admin/orders/__tests__/archive-order.js deleted file mode 100644 index 9ca2108a6e..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/archive-order.js +++ /dev/null @@ -1,40 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { OrderServiceMock } from "../../../../../services/__mocks__/order" - -describe("POST /admin/orders/:id/archive", () => { - describe("successfully archives an order", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("processed-order")}/archive`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls OrderService archive", () => { - expect(OrderServiceMock.archive).toHaveBeenCalledTimes(1) - expect(OrderServiceMock.archive).toHaveBeenCalledWith( - IdMap.getId("processed-order") - ) - }) - - it("returns order with status = archived", () => { - expect(subject.status).toEqual(200) - expect(subject.body.order.id).toEqual(IdMap.getId("processed-order")) - expect(subject.body.order.status).toEqual("archived") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-claim.js b/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-claim.js deleted file mode 100644 index 8d74d62504..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-claim.js +++ /dev/null @@ -1,64 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ClaimServiceMock } from "../../../../../services/__mocks__/claim" - -describe("POST /admin/orders/:id/claims/:claim_id/cancel", () => { - describe("successfully cancels a claim", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/claims/${IdMap.getId( - "test-claim" - )}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls ClaimService cancel", () => { - expect(ClaimServiceMock.cancel).toHaveBeenCalledTimes(1) - expect(ClaimServiceMock.cancel).toHaveBeenCalledWith( - IdMap.getId("test-claim") - ) - }) - }) - - describe("Trying to cancel a claim unrelated to the order fails", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order2")}/claims/${IdMap.getId( - "test-claim" - )}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns error", () => { - expect(subject.status).toEqual(404) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-fulfillment-claim.js b/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-fulfillment-claim.js deleted file mode 100644 index 9e612909b1..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-fulfillment-claim.js +++ /dev/null @@ -1,92 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ClaimServiceMock } from "../../../../../services/__mocks__/claim" - -describe("POST /admin/orders/:id/claims/:claim_id/fulfillments/:fulfillment_id/cancel", () => { - describe("successfully cancels a fulfillment", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/claims/${IdMap.getId( - "test-claim" - )}/fulfillments/${IdMap.getId("claim-fulfillment")}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls claimService cancelFulfillment", () => { - expect(ClaimServiceMock.cancelFulfillment).toHaveBeenCalledTimes(1) - expect(ClaimServiceMock.cancelFulfillment).toHaveBeenCalledWith( - IdMap.getId("claim-fulfillment") - ) - }) - }) - - describe("Trying to cancel a fulfillment unrelated to the claim fails", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/claims/${IdMap.getId( - "claim-fulfillment2" - )}/fulfillments/${IdMap.getId("claim-fulfillment")}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns error", () => { - expect(subject.status).toEqual(404) - }) - }) - - describe("Trying to cancel a fulfillment, where claim and order are unrelated", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order2")}/claims/${IdMap.getId( - "test-claim" - )}/fulfillments/${IdMap.getId("claim-fulfillment")}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns error", () => { - expect(subject.status).toEqual(404) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-fulfillment-swap.js b/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-fulfillment-swap.js deleted file mode 100644 index 797b1c1713..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-fulfillment-swap.js +++ /dev/null @@ -1,92 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { SwapServiceMock } from "../../../../../services/__mocks__/swap" - -describe("POST /admin/orders/:id/swaps/:swap_id/fulfillments/:fulfillment_id/cancel", () => { - describe("successfully cancels a fulfillment", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/swaps/${IdMap.getId( - "test-swap" - )}/fulfillments/${IdMap.getId("swap-fulfillment")}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls SwapService cancelFulfillment", () => { - expect(SwapServiceMock.cancelFulfillment).toHaveBeenCalledTimes(1) - expect(SwapServiceMock.cancelFulfillment).toHaveBeenCalledWith( - IdMap.getId("swap-fulfillment") - ) - }) - }) - - describe("Trying to cancel a fulfillment unrelated to the swap fails", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/swaps/${IdMap.getId( - "swap-fulfillment2" - )}/fulfillments/${IdMap.getId("swap-fulfillment")}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns error", () => { - expect(subject.status).toEqual(404) - }) - }) - - describe("Trying to cancel a fulfillment, where swap and order are unrelated", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order2")}/swaps/${IdMap.getId( - "test-swap" - )}/fulfillments/${IdMap.getId("swap-fulfillment")}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns error", () => { - expect(subject.status).toEqual(404) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-fulfillment.js b/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-fulfillment.js deleted file mode 100644 index cfc27e1fc9..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-fulfillment.js +++ /dev/null @@ -1,64 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { OrderServiceMock } from "../../../../../services/__mocks__/order" - -describe("POST /admin/orders/:id/fulfillments/:fulfillment_id/cancel", () => { - describe("successfully cancels a fulfillment", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/fulfillments/${IdMap.getId( - "order-fulfillment" - )}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls OrderService cancelFulfillment", () => { - expect(OrderServiceMock.cancelFulfillment).toHaveBeenCalledTimes(1) - expect(OrderServiceMock.cancelFulfillment).toHaveBeenCalledWith( - IdMap.getId("order-fulfillment") - ) - }) - }) - - describe("Trying to cancel a fulfillment unrelated to the order fails", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order2")}/fulfillments/${IdMap.getId( - "order-fulfillment" - )}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns error", () => { - expect(subject.status).toEqual(404) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-order.js b/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-order.js deleted file mode 100644 index 27d94ba353..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-order.js +++ /dev/null @@ -1,40 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { OrderServiceMock } from "../../../../../services/__mocks__/order" - -describe("POST /admin/orders/:id/cancel", () => { - describe("successfully cancels an order", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls OrderService cancel", () => { - expect(OrderServiceMock.cancel).toHaveBeenCalledTimes(1) - expect(OrderServiceMock.cancel).toHaveBeenCalledWith( - IdMap.getId("test-order") - ) - }) - - it("returns order with status = cancelled", () => { - expect(subject.status).toEqual(200) - expect(subject.body.order.id).toEqual(IdMap.getId("test-order")) - expect(subject.body.order.status).toEqual("cancelled") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-swap.js b/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-swap.js deleted file mode 100644 index 72b5ec77fe..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/cancel-swap.js +++ /dev/null @@ -1,64 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { SwapServiceMock } from "../../../../../services/__mocks__/swap" - -describe("POST /admin/orders/:id/swaps/:swap_id/cancel", () => { - describe("successfully cancels a claim", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/swaps/${IdMap.getId( - "test-swap" - )}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls SwapService cancel", () => { - expect(SwapServiceMock.cancel).toHaveBeenCalledTimes(1) - expect(SwapServiceMock.cancel).toHaveBeenCalledWith( - IdMap.getId("test-swap") - ) - }) - }) - - describe("Trying to cancel a claim unrelated to the order fails", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order2")}/swaps/${IdMap.getId( - "test-swap" - )}/cancel`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns error", () => { - expect(subject.status).toEqual(404) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/capture-payment.js b/packages/medusa/src/api/routes/admin/orders/__tests__/capture-payment.js deleted file mode 100644 index 427040ef9d..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/capture-payment.js +++ /dev/null @@ -1,40 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { OrderServiceMock } from "../../../../../services/__mocks__/order" - -describe("POST /admin/orders/:id/capture", () => { - describe("successfully captures payment for an order", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/capture`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls OrderService capturePayment", () => { - expect(OrderServiceMock.capturePayment).toHaveBeenCalledTimes(1) - expect(OrderServiceMock.capturePayment).toHaveBeenCalledWith( - IdMap.getId("test-order") - ) - }) - - it("returns order with payment_status = captured", () => { - expect(subject.status).toEqual(200) - expect(subject.body.order.id).toEqual(IdMap.getId("test-order")) - expect(subject.body.order.payment_status).toEqual("captured") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/create-claim.js b/packages/medusa/src/api/routes/admin/orders/__tests__/create-claim.js deleted file mode 100644 index 206ee51b0c..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/create-claim.js +++ /dev/null @@ -1,176 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ClaimServiceMock } from "../../../../../services/__mocks__/claim" - -describe("POST /admin/orders/:id/claims", () => { - describe("successfully creates a claim", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/claims`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - payload: { - type: "replace", - claim_items: [ - { - item_id: "test-claim-item", - quantity: 1, - }, - ], - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls ClaimService create", () => { - expect(ClaimServiceMock.create).toHaveBeenCalledTimes(1) - expect(ClaimServiceMock.create).toHaveBeenCalledWith( - expect.objectContaining({ - type: "replace", - claim_items: [ - { - item_id: "test-claim-item", - quantity: 1, - }, - ], - }) - ) - }) - }) - - describe("fails to create a claim when type is not known", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/claims`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - payload: { - type: "something", - claim_items: [ - { - item_id: "test-claim-item", - quantity: 1, - }, - ], - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("throws an error", () => { - expect(subject.status).toEqual(400) - expect(subject.body.message).toEqual( - "type must be one of the following values: refund, replace" - ) - }) - }) - - describe("successfully creates a claim with a reason", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/claims`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - payload: { - type: "replace", - claim_items: [ - { - item_id: "test-claim-item", - quantity: 1, - reason: "production_failure", - }, - ], - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls ClaimService create", () => { - expect(ClaimServiceMock.create).toHaveBeenCalledTimes(1) - expect(ClaimServiceMock.create).toHaveBeenCalledWith( - expect.objectContaining({ - type: "replace", - claim_items: [ - { - item_id: "test-claim-item", - quantity: 1, - reason: "production_failure", - }, - ], - }) - ) - }) - - describe("fails to create a claim when type is not known", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/claims`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - payload: { - type: "refund", - claim_items: [ - { - item_id: "test-claim-item", - quantity: 1, - reason: "should_throw_error", - }, - ], - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("throws an error", () => { - expect(subject.status).toEqual(400) - expect(subject.body.message).toEqual( - "reason must be one of the following values: missing_item, wrong_item, production_failure, other" - ) - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/create-fulfillment.js b/packages/medusa/src/api/routes/admin/orders/__tests__/create-fulfillment.js deleted file mode 100644 index 95350aa0d7..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/create-fulfillment.js +++ /dev/null @@ -1,55 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { OrderServiceMock } from "../../../../../services/__mocks__/order" - -describe("POST /admin/orders/:id/fulfillment", () => { - describe("successfully fulfills an order", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/fulfillment`, - { - payload: { - items: [ - { - item_id: IdMap.getId("line1"), - quantity: 1, - }, - ], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls OrderService createFulfillment", () => { - expect(OrderServiceMock.createFulfillment).toHaveBeenCalledTimes(1) - expect(OrderServiceMock.createFulfillment).toHaveBeenCalledWith( - IdMap.getId("test-order"), - [ - { - item_id: IdMap.getId("line1"), - quantity: 1, - }, - ], - { metadata: undefined, no_notification: undefined } - ) - }) - - it("returns order with fulfillment_status = fulfilled", () => { - expect(subject.status).toEqual(200) - expect(subject.body.order.id).toEqual(IdMap.getId("test-order")) - expect(subject.body.order.fulfillment_status).toEqual("fulfilled") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/get-order.js b/packages/medusa/src/api/routes/admin/orders/__tests__/get-order.js deleted file mode 100644 index 86ca3f7422..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/get-order.js +++ /dev/null @@ -1,75 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { OrderServiceMock } from "../../../../../services/__mocks__/order" -import { - defaultAdminOrdersFields, - defaultAdminOrdersRelations, -} from "../../../../../types/orders" - -describe("GET /admin/orders", () => { - describe("successfully gets an order", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/admin/orders/${IdMap.getId("test-order")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService retrieve", () => { - expect(OrderServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - - const expectedRelations = [ - ...defaultAdminOrdersRelations, - "sales_channel", - ] - - expect( - OrderServiceMock.retrieveWithTotals.mock.calls[0][1].relations - ).toHaveLength(expectedRelations.length) - expect(OrderServiceMock.retrieveWithTotals).toHaveBeenCalledWith( - IdMap.getId("test-order"), - { - // TODO [MEDUSA_FF_SALES_CHANNELS]: Remove when sales channel flag is removed entirely - select: [...defaultAdminOrdersFields, "sales_channel_id"].filter( - (field) => { - return ![ - "shipping_total", - "discount_total", - "tax_total", - "refunded_total", - "total", - "subtotal", - "refundable_amount", - "gift_card_total", - "gift_card_tax_total", - ].includes(field) - } - ), - // TODO [MEDUSA_FF_SALES_CHANNELS]: Remove when sales channel flag is removed entirely - relations: expect.arrayContaining(expectedRelations), - }, - { - includes: undefined, - } - ) - }) - - it("returns order", () => { - expect(subject.status).toEqual(200) - expect(subject.body.order.id).toEqual(IdMap.getId("test-order")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/return-order.js b/packages/medusa/src/api/routes/admin/orders/__tests__/return-order.js deleted file mode 100644 index 661a5498a9..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/return-order.js +++ /dev/null @@ -1,294 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ReturnService } from "../../../../../services/__mocks__/return" -import { EventBusServiceMock } from "../../../../../services/__mocks__/event-bus" - -describe("POST /admin/orders/:id/return", () => { - describe("successfully returns full order", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/return`, - { - payload: { - items: [ - { - item_id: IdMap.getId("existingLine"), - quantity: 10, - }, - ], - refund: 10, - no_notification: true, - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls OrderService return", () => { - expect(ReturnService.create).toHaveBeenCalledTimes(1) - expect(ReturnService.create).toHaveBeenCalledWith({ - order_id: IdMap.getId("test-order"), - idempotency_key: "testkey", - items: [ - { - item_id: IdMap.getId("existingLine"), - quantity: 10, - }, - ], - refund_amount: 10, - no_notification: true, - shipping_method: undefined, - }) - }) - }) - - describe("defaults to 0 on negative refund amount", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/return`, - { - payload: { - items: [ - { - item_id: IdMap.getId("existingLine"), - quantity: 10, - }, - ], - refund: -1, - no_notification: true, - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls OrderService return", () => { - expect(ReturnService.create).toHaveBeenCalledTimes(1) - expect(ReturnService.create).toHaveBeenCalledWith({ - order_id: IdMap.getId("test-order"), - idempotency_key: "testkey", - items: [ - { - item_id: IdMap.getId("existingLine"), - quantity: 10, - }, - ], - refund_amount: 0, - no_notification: true, - shipping_method: undefined, - }) - }) - }) - - describe("defaults to 0 on negative refund amount", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/return`, - { - payload: { - items: [ - { - item_id: IdMap.getId("existingLine"), - quantity: 10, - }, - ], - refund: -1, - }, - no_notification: true, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls OrderService return", () => { - expect(ReturnService.create).toHaveBeenCalledTimes(1) - expect(ReturnService.create).toHaveBeenCalledWith({ - order_id: IdMap.getId("test-order"), - idempotency_key: "testkey", - items: [ - { - item_id: IdMap.getId("existingLine"), - quantity: 10, - }, - ], - refund_amount: 0, - no_notification: true, - shipping_method: undefined, - }) - }) - }) - - describe("fulfills", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/return`, - { - payload: { - items: [ - { - item_id: IdMap.getId("existingLine"), - quantity: 10, - }, - ], - refund: 100, - no_notification: true, - return_shipping: { - option_id: "opt_1234", - price: 12, - }, - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls OrderService return", () => { - expect(ReturnService.create).toHaveBeenCalledTimes(1) - expect(ReturnService.create).toHaveBeenCalledWith({ - order_id: IdMap.getId("test-order"), - idempotency_key: "testkey", - items: [ - { - item_id: IdMap.getId("existingLine"), - quantity: 10, - }, - ], - refund_amount: 100, - no_notification: true, - shipping_method: { - option_id: "opt_1234", - price: 12, - }, - }) - - expect(ReturnService.fulfill).toHaveBeenCalledTimes(1) - expect(ReturnService.fulfill).toHaveBeenCalledWith("return") - }) - }) - - describe("the api call overrides notification settings of order", () => { - it("eventBus is called with the proper no notification feature", async () => { - jest.clearAllMocks() - const subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/return`, - { - payload: { - items: [ - { - item_id: IdMap.getId("existingLine"), - quantity: 10, - }, - ], - refund: 100, - return_shipping: { - option_id: "opt_1234", - price: 12, - }, - no_notification: false, - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - expect.any(String), - { - id: expect.any(String), - no_notification: false, - return_id: expect.any(String), - } - ) - }) - }) - - describe("the api call inherits notification settings of order", () => { - it("eventBus is called with the proper no notification feature", async () => { - jest.clearAllMocks() - await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}/return`, - { - payload: { - items: [ - { - item_id: IdMap.getId("existingLine"), - quantity: 10, - }, - ], - refund: 100, - return_shipping: { - option_id: "opt_1234", - price: 12, - }, - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - expect.any(String), - { - id: expect.any(String), - no_notification: true, - return_id: expect.any(String), - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/update-order.js b/packages/medusa/src/api/routes/admin/orders/__tests__/update-order.js deleted file mode 100644 index 4c2bbe9d39..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/update-order.js +++ /dev/null @@ -1,63 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { OrderServiceMock } from "../../../../../services/__mocks__/order" - -describe("POST /admin/orders/:id", () => { - describe("successfully updates an order", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/orders/${IdMap.getId("test-order")}`, - { - payload: { - email: "oliver@test.dk", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls OrderService update", () => { - expect(OrderServiceMock.update).toHaveBeenCalledTimes(1) - expect(OrderServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("test-order"), - { - email: "oliver@test.dk", - } - ) - }) - }) - - describe("handles failed update operation", () => { - it("throws if metadata is to be updated", async () => { - try { - await request("POST", `/admin/orders/${IdMap.getId("test-order")}`, { - payload: { - _id: IdMap.getId("test-order"), - metadata: "Test Description", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - } catch (error) { - expect(error.status).toEqual(400) - expect(error.message).toEqual( - "Use setMetadata to update metadata fields" - ) - } - }) - }) -}) 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 deleted file mode 100644 index 046dc0a316..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/add-shipping-method.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { - IsInt, - IsNotEmpty, - IsObject, - IsOptional, - IsString, -} from "class-validator" - -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 - * operationId: "PostOrdersOrderShippingMethods" - * summary: "Add a Shipping Method" - * description: "Add a Shipping Method to an Order. If another Shipping Method exists with the same Shipping Profile, the previous Shipping Method will be replaced." - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderShippingMethodsReq" - * x-authenticated: true - * x-codegen: - * method: addShippingMethod - * params: AdminPostOrdersOrderShippingMethodsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.addShippingMethod(orderId, { - * price: 1000, - * option_id - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminAddShippingMethod } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const addShippingMethod = useAdminAddShippingMethod( - * orderId - * ) - * // ... - * - * const handleAddShippingMethod = ( - * optionId: string, - * price: number - * ) => { - * addShippingMethod.mutate({ - * option_id: optionId, - * price - * }, { - * onSuccess: ({ order }) => { - * console.log(order.shipping_methods) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/shipping-methods' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "price": 1000, - * "option_id": "{option_id}" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = req.validatedBody - - const orderService: OrderService = req.scope.resolve("orderService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await orderService - .withTransaction(transactionManager) - .addShippingMethod(id, validated.option_id, validated.data, { - price: validated.price, - }) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.status(200).json({ order: cleanResponseData(order, []) }) -} - -/** - * @schema AdminPostOrdersOrderShippingMethodsReq - * type: object - * description: "The shipping method's details." - * required: - * - price - * - option_id - * properties: - * price: - * type: number - * description: The price (excluding VAT) that should be charged for the Shipping Method - * option_id: - * type: string - * description: The ID of the Shipping Option to create the Shipping Method from. - * data: - * type: object - * description: The data required for the Shipping Option to create a Shipping Method. This depends on the Fulfillment Provider. - */ -export class AdminPostOrdersOrderShippingMethodsReq { - @IsInt() - @IsNotEmpty() - price: number - - @IsString() - @IsNotEmpty() - option_id: string - - @IsObject() - @IsOptional() - data?: Record = {} -} - -export class AdminPostOrdersOrderShippingMethodsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/archive-order.ts b/packages/medusa/src/api/routes/admin/orders/archive-order.ts deleted file mode 100644 index b608108e47..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/archive-order.ts +++ /dev/null @@ -1,106 +0,0 @@ -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 - * operationId: "PostOrdersOrderArchive" - * summary: "Archive Order" - * description: "Archive an order and change its status." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * x-codegen: - * method: archive - * params: AdminPostOrdersOrderArchiveParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.archive(orderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminArchiveOrder } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const archiveOrder = useAdminArchiveOrder( - * orderId - * ) - * // ... - * - * const handleArchivingOrder = () => { - * archiveOrder.mutate(void 0, { - * onSuccess: ({ order }) => { - * console.log(order.status) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/archive' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const orderService: OrderService = req.scope.resolve("orderService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await orderService.withTransaction(transactionManager).archive(id) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - 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 deleted file mode 100644 index 58e63aba5d..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/cancel-claim.ts +++ /dev/null @@ -1,119 +0,0 @@ -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 - * operationId: "PostOrdersClaimCancel" - * summary: "Cancel a Claim" - * description: "Cancel a Claim and change its status. A claim can't be canceled if it has a refund, if its fulfillments haven't been canceled, of if its associated return hasn't been canceled." - * x-authenticated: true - * externalDocs: - * description: Canceling a claim - * url: https://docs.medusajs.com/modules/orders/claims#cancel-a-claim - * parameters: - * - (path) id=* {string} The ID of the order the claim is associated with. - * - (path) claim_id=* {string} The ID of the Claim. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * x-codegen: - * method: cancelClaim - * params: AdminPostOrdersClaimCancel - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.cancelClaim(orderId, claimId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCancelClaim } from "medusa-react" - * - * type Props = { - * orderId: string - * claimId: string - * } - * - * const Claim = ({ orderId, claimId }: Props) => { - * const cancelClaim = useAdminCancelClaim(orderId) - * // ... - * - * const handleCancel = () => { - * cancelClaim.mutate(claimId) - * } - * - * // ... - * } - * - * export default Claim - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/claims/{claim_id}/cancel' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, claim_id } = req.params - - const claimService: ClaimService = req.scope.resolve("claimService") - const orderService: OrderService = req.scope.resolve("orderService") - - const claim = await claimService.retrieve(claim_id) - - if (claim.order_id !== id) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `no claim was found with the id: ${claim_id} related to order: ${id}` - ) - } - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await claimService - .withTransaction(transactionManager) - .cancel(claim_id) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - 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 deleted file mode 100644 index b00d2b5285..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-claim.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { - ClaimService, - FulfillmentService, - 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}/fulfillments/{fulfillment_id}/cancel - * operationId: "PostOrdersClaimFulfillmentsCancel" - * summary: "Cancel Claim's Fulfillment" - * description: "Cancel a claim's fulfillment and change its fulfillment status to `canceled`." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the order the claim is associated with. - * - (path) claim_id=* {string} The ID of the claim. - * - (path) fulfillment_id=* {string} The ID of the fulfillment. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * x-codegen: - * method: cancelClaimFulfillment - * params: AdminPostOrdersClaimFulfillmentsCancelParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.cancelClaimFulfillment(orderId, claimId, fulfillmentId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCancelClaimFulfillment } from "medusa-react" - * - * type Props = { - * orderId: string - * claimId: string - * } - * - * const Claim = ({ orderId, claimId }: Props) => { - * const cancelFulfillment = useAdminCancelClaimFulfillment( - * orderId - * ) - * // ... - * - * const handleCancel = (fulfillmentId: string) => { - * cancelFulfillment.mutate({ - * claim_id: claimId, - * fulfillment_id: fulfillmentId, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.claims) - * } - * }) - * } - * - * // ... - * } - * - * export default Claim - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/claims/{claim_id}/fulfillments/{fulfillment_id}/cancel' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, claim_id, fulfillment_id } = req.params - - const fulfillmentService: FulfillmentService = - req.scope.resolve("fulfillmentService") - const claimService: ClaimService = req.scope.resolve("claimService") - const orderService: OrderService = req.scope.resolve("orderService") - - const fulfillment = await fulfillmentService.retrieve(fulfillment_id) - - if (fulfillment.claim_order_id !== claim_id) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `no fulfillment was found with the id: ${fulfillment_id} related to claim: ${claim_id}` - ) - } - - const claim = await claimService.retrieve(claim_id) - - if (claim.order_id !== id) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `no claim was found with the id: ${claim_id} related to order: ${id}` - ) - } - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await claimService - .withTransaction(transactionManager) - .cancelFulfillment(fulfillment_id) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - 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 deleted file mode 100644 index c0b6092917..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-swap.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { - FulfillmentService, - 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}/fulfillments/{fulfillment_id}/cancel - * operationId: "PostOrdersSwapFulfillmentsCancel" - * summary: "Cancel Swap's Fulfilmment" - * description: "Cancel a swap's fulfillment and change its fulfillment status to `canceled`." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the order the swap is associated with. - * - (path) swap_id=* {string} The ID of the swap. - * - (path) fulfillment_id=* {string} The ID of the fulfillment. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * x-codegen: - * method: cancelSwapFulfillment - * params: AdminPostOrdersSwapFulfillementsCancelParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.cancelSwapFulfillment(orderId, swapId, fulfillmentId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCancelSwapFulfillment } from "medusa-react" - * - * type Props = { - * orderId: string, - * swapId: string - * } - * - * const Swap = ({ - * orderId, - * swapId - * }: Props) => { - * const cancelFulfillment = useAdminCancelSwapFulfillment( - * orderId - * ) - * // ... - * - * const handleCancelFulfillment = ( - * fulfillmentId: string - * ) => { - * cancelFulfillment.mutate({ - * swap_id: swapId, - * fulfillment_id: fulfillmentId, - * }) - * } - * - * // ... - * } - * - * export default Swap - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/swaps/{swap_id}/fulfillments/{fulfillment_id}/cancel' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, swap_id, fulfillment_id } = req.params - - const swapService: SwapService = req.scope.resolve("swapService") - const orderService: OrderService = req.scope.resolve("orderService") - const fulfillmentService: FulfillmentService = - req.scope.resolve("fulfillmentService") - - const fulfillment = await fulfillmentService.retrieve(fulfillment_id) - - if (fulfillment.swap_id !== swap_id) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `no fulfillment was found with the id: ${fulfillment_id} related to swap: ${id}` - ) - } - - const swap = await swapService.retrieve(swap_id) - - if (swap.order_id !== id) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `no swap was found with the id: ${swap_id} related to order: ${id}` - ) - } - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await swapService - .withTransaction(transactionManager) - .cancelFulfillment(fulfillment_id) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.json({ order: cleanResponseData(order, []) }) -} - -// eslint-disable-next-line max-len -export class AdminPostOrdersOrderSwapFulfillementsCancelParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment.ts b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment.ts deleted file mode 100644 index 0bde669cc6..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { - FulfillmentService, - OrderService, - ProductVariantInventoryService, -} from "../../../../services" - -import { IInventoryService } from "@medusajs/types" -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" -import { promiseAll } from "@medusajs/utils" - -/** - * @oas [post] /admin/orders/{id}/fulfillments/{fulfillment_id}/cancel - * operationId: "PostOrdersOrderFulfillmentsCancel" - * summary: "Cancel a Fulfilmment" - * description: "Cancel an order's fulfillment and change its fulfillment status to `canceled`." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (path) fulfillment_id=* {string} The ID of the Fulfillment. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * x-codegen: - * method: cancelFulfillment - * params: AdminPostOrdersOrderFulfillementsCancelParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.cancelFulfillment(orderId, fulfillmentId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCancelFulfillment } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const cancelFulfillment = useAdminCancelFulfillment( - * orderId - * ) - * // ... - * - * const handleCancel = ( - * fulfillmentId: string - * ) => { - * cancelFulfillment.mutate(fulfillmentId, { - * onSuccess: ({ order }) => { - * console.log(order.fulfillments) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/fulfillments/{fulfillment_id}/cancel' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, fulfillment_id } = req.params - - const orderService: OrderService = req.scope.resolve("orderService") - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - const fulfillmentService: FulfillmentService = - req.scope.resolve("fulfillmentService") - - const fulfillment = await fulfillmentService.retrieve(fulfillment_id) - - if (fulfillment.order_id !== id) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `no fulfillment was found with the id: ${fulfillment_id} related to order: ${id}` - ) - } - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - await orderService - .withTransaction(transactionManager) - .cancelFulfillment(fulfillment_id) - - const fulfillment = await fulfillmentService - .withTransaction(transactionManager) - .retrieve(fulfillment_id, { relations: ["items", "items.item"] }) - - if (fulfillment.location_id && inventoryService) { - await adjustInventoryForCancelledFulfillment(fulfillment, { - productVariantInventoryService: - productVariantInventoryService.withTransaction(transactionManager), - }) - } - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.json({ order: cleanResponseData(order, []) }) -} - -export const adjustInventoryForCancelledFulfillment = async ( - fulfillment: Fulfillment, - context: { - productVariantInventoryService: ProductVariantInventoryService - } -) => { - const { productVariantInventoryService } = context - await promiseAll( - fulfillment.items.map(async ({ item, quantity }) => { - if (item.variant_id) { - await productVariantInventoryService.adjustInventory( - item.variant_id, - fulfillment.location_id!, - quantity - ) - } - }) - ) -} - -export class AdminPostOrdersOrderFulfillementsCancelParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-order.ts b/packages/medusa/src/api/routes/admin/orders/cancel-order.ts deleted file mode 100644 index fed6709062..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/cancel-order.ts +++ /dev/null @@ -1,105 +0,0 @@ -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 - * operationId: "PostOrdersOrderCancel" - * summary: "Cancel an Order" - * description: "Cancel an order and change its status. This will also cancel any associated Fulfillments and Payments, and it may fail if the Payment or Fulfillment Provider is unable to cancel the Payment/Fulfillment." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * x-codegen: - * method: cancel - * params: AdminPostOrdersOrderCancel - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.cancel(orderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCancelOrder } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const cancelOrder = useAdminCancelOrder( - * orderId - * ) - * // ... - * - * const handleCancel = () => { - * cancelOrder.mutate(void 0, { - * onSuccess: ({ order }) => { - * console.log(order.status) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/cancel' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const orderService: OrderService = req.scope.resolve("orderService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await orderService.withTransaction(transactionManager).cancel(id) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - 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 deleted file mode 100644 index 112a8a7ff7..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/cancel-swap.ts +++ /dev/null @@ -1,126 +0,0 @@ -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 - * operationId: "PostOrdersSwapCancel" - * summary: "Cancel a Swap" - * description: "Cancel a Swap and change its status." - * x-authenticated: true - * externalDocs: - * description: Canceling a swap - * url: https://docs.medusajs.com/modules/orders/swaps#canceling-a-swap - * parameters: - * - (path) id=* {string} The ID of the Order the swap is associated with. - * - (path) swap_id=* {string} The ID of the Swap. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * x-codegen: - * method: cancelSwap - * params: AdminPostOrdersSwapCancelParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.cancelSwap(orderId, swapId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCancelSwap } from "medusa-react" - * - * type Props = { - * orderId: string, - * swapId: string - * } - * - * const Swap = ({ - * orderId, - * swapId - * }: Props) => { - * const cancelSwap = useAdminCancelSwap( - * orderId - * ) - * // ... - * - * const handleCancel = () => { - * cancelSwap.mutate(swapId, { - * onSuccess: ({ order }) => { - * console.log(order.swaps) - * } - * }) - * } - * - * // ... - * } - * - * export default Swap - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{order_id}/swaps/{swap_id}/cancel' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, swap_id } = req.params - - const swapService: SwapService = req.scope.resolve("swapService") - const orderService: OrderService = req.scope.resolve("orderService") - - const swap = await swapService.retrieve(swap_id) - - if (swap.order_id !== id) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `no swap was found with the id: ${swap_id} related to order: ${id}` - ) - } - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await swapService.withTransaction(transactionManager).cancel(swap_id) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - 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 deleted file mode 100644 index 5db0f6ec38..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/capture-payment.ts +++ /dev/null @@ -1,108 +0,0 @@ -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 - * operationId: "PostOrdersOrderCapture" - * summary: "Capture an Order's Payments" - * description: "Capture all the Payments associated with an Order. The payment of canceled orders can't be captured." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * x-codegen: - * method: capturePayment - * params: AdminPostOrdersOrderCaptureParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.capturePayment(orderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCapturePayment } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const capturePayment = useAdminCapturePayment( - * orderId - * ) - * // ... - * - * const handleCapture = () => { - * capturePayment.mutate(void 0, { - * onSuccess: ({ order }) => { - * console.log(order.status) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/capture' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const orderService: OrderService = req.scope.resolve("orderService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await orderService - .withTransaction(transactionManager) - .capturePayment(id) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - 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 deleted file mode 100644 index 0461342d25..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/complete-order.ts +++ /dev/null @@ -1,108 +0,0 @@ -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 - * operationId: "PostOrdersOrderComplete" - * summary: "Complete an Order" - * description: "Complete an Order and change its status. A canceled order can't be completed." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * x-codegen: - * method: complete - * params: AdminPostOrdersOrderCompleteParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.complete(orderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCompleteOrder } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const completeOrder = useAdminCompleteOrder( - * orderId - * ) - * // ... - * - * const handleComplete = () => { - * completeOrder.mutate(void 0, { - * onSuccess: ({ order }) => { - * console.log(order.status) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/complete' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const orderService: OrderService = req.scope.resolve("orderService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await orderService - .withTransaction(transactionManager) - .completeOrder(id) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - 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 deleted file mode 100644 index 3374f03eaf..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/create-claim-shipment.ts +++ /dev/null @@ -1,161 +0,0 @@ -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 - * operationId: "PostOrdersOrderClaimsClaimShipments" - * summary: "Ship a Claim's Fulfillment" - * description: "Create a shipment for the claim and mark its fulfillment as shipped. This changes the claim's fulfillment status to either `partially_shipped` or `shipped`, depending on - * whether all the items were shipped." - * x-authenticated: true - * externalDocs: - * description: Fulfill a claim - * url: https://docs.medusajs.com/modules/orders/claims#fulfill-a-claim - * parameters: - * - (path) id=* {string} The ID of the Order the claim is associated with. - * - (path) claim_id=* {string} The ID of the Claim. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderClaimsClaimShipmentsReq" - * x-codegen: - * method: createClaimShipment - * params: AdminPostOrdersOrderClaimsClaimShipmentsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.createClaimShipment(orderId, claimId, { - * fulfillment_id - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateClaimShipment } from "medusa-react" - * - * type Props = { - * orderId: string - * claimId: string - * } - * - * const Claim = ({ orderId, claimId }: Props) => { - * const createShipment = useAdminCreateClaimShipment(orderId) - * // ... - * - * const handleCreateShipment = (fulfillmentId: string) => { - * createShipment.mutate({ - * claim_id: claimId, - * fulfillment_id: fulfillmentId, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.claims) - * } - * }) - * } - * - * // ... - * } - * - * export default Claim - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/claims/{claim_id}/shipments' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "fulfillment_id": "{fulfillment_id}" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, claim_id } = req.params - - const validated = req.validatedBody - - const orderService: OrderService = req.scope.resolve("orderService") - const claimService: ClaimService = req.scope.resolve("claimService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await claimService - .withTransaction(transactionManager) - .createShipment( - claim_id, - validated.fulfillment_id, - validated.tracking_numbers?.map((n) => ({ tracking_number: n })) - ) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.json({ order: cleanResponseData(order, []) }) -} - -/** - * @schema AdminPostOrdersOrderClaimsClaimShipmentsReq - * type: object - * required: - * - fulfillment_id - * properties: - * fulfillment_id: - * description: The ID of the Fulfillment. - * type: string - * tracking_numbers: - * description: An array of tracking numbers for the shipment. - * type: array - * items: - * type: string - */ -export class AdminPostOrdersOrderClaimsClaimShipmentsReq { - @IsString() - @IsNotEmpty() - fulfillment_id: string - - @IsArray() - @IsOptional() - @IsString({ each: true }) - tracking_numbers?: string[] -} - -// eslint-disable-next-line max-len -export class AdminPostOrdersOrderClaimsClaimShipmentsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/create-claim.ts b/packages/medusa/src/api/routes/admin/orders/create-claim.ts deleted file mode 100644 index 6a48974f81..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/create-claim.ts +++ /dev/null @@ -1,583 +0,0 @@ -import { - IsArray, - IsBoolean, - IsEnum, - IsInt, - IsNotEmpty, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { ClaimReason, ClaimType } from "../../../../models" - -import { Type } from "class-transformer" -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 - * operationId: "PostOrdersOrderClaims" - * summary: "Create a Claim" - * description: "Create a Claim for an order. If a return shipping method is specified, a return will also be created and associated with the claim. If the claim's type is `refund`, - * the refund is processed as well." - * externalDocs: - * description: How are claims created - * url: https://docs.medusajs.com/modules/orders/claims#how-are-claims-created - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderClaimsReq" - * x-codegen: - * method: createClaim - * params: AdminPostOrdersOrderClaimsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.createClaim(orderId, { - * type: 'refund', - * claim_items: [ - * { - * item_id, - * quantity: 1 - * } - * ] - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateClaim } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const CreateClaim = ({ orderId }: Props) => { - * - * const CreateClaim = (orderId: string) => { - * const createClaim = useAdminCreateClaim(orderId) - * // ... - * - * const handleCreate = (itemId: string) => { - * createClaim.mutate({ - * type: "refund", - * claim_items: [ - * { - * item_id: itemId, - * quantity: 1, - * }, - * ], - * }, { - * onSuccess: ({ order }) => { - * console.log(order.claims) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateClaim - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/claims' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "type": "refund", - * "claim_items": [ - * { - * "item_id": "asdsd", - * "quantity": 1 - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const { id } = req.params - - const value = req.validatedBody - - const idempotencyKeyService = req.scope.resolve("idempotencyKeyService") - const manager: EntityManager = req.scope.resolve("manager") - - const headerKey = req.get("Idempotency-Key") || "" - - let idempotencyKey - try { - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .initializeRequest(headerKey, req.method, req.params, req.path) - }) - } catch (error) { - res.status(409).send("Failed to create idempotency key") - return - } - - res.setHeader("Access-Control-Expose-Headers", "Idempotency-Key") - res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key) - - const orderService = req.scope.resolve("orderService") - const claimService = req.scope.resolve("claimService") - const returnService = req.scope.resolve("returnService") - - let inProgress = true - let err = false - - while (inProgress) { - switch (idempotencyKey.recovery_point) { - case "started": { - await manager - .transaction("SERIALIZABLE", async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .workStage(idempotencyKey.idempotency_key, async (manager) => { - const order = await orderService - .withTransaction(manager) - .retrieve(id, { - relations: [ - "customer", - "shipping_address", - "region", - "items", - "items.tax_lines", - "discounts", - "discounts.rule", - "claims", - "claims.additional_items", - "claims.additional_items.tax_lines", - "swaps", - "swaps.additional_items", - "swaps.additional_items.tax_lines", - ], - }) - - await claimService.withTransaction(manager).create({ - idempotency_key: idempotencyKey.idempotency_key, - order, - ...value, - }) - - return { - recovery_point: "claim_created", - } - }) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "claim_created": { - await manager - .transaction("SERIALIZABLE", async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .workStage(idempotencyKey.idempotency_key, async (manager) => { - let claim = await claimService.withTransaction(manager).list({ - idempotency_key: idempotencyKey.idempotency_key, - }) - - if (!claim.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Claim not found` - ) - } - - claim = claim[0] - - if (claim.type === "refund") { - await claimService - .withTransaction(manager) - .processRefund(claim.id) - } - - return { - recovery_point: "refund_handled", - } - }) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "refund_handled": { - await manager - .transaction("SERIALIZABLE", async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .workStage(idempotencyKey.idempotency_key, async (manager) => { - let order = await orderService - .withTransaction(manager) - .retrieve(id, { - relations: ["items", "discounts"], - }) - - let claim = await claimService.withTransaction(manager).list( - { - idempotency_key: idempotencyKey.idempotency_key, - }, - { - relations: ["return_order"], - } - ) - - if (!claim.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Claim not found` - ) - } - - claim = claim[0] - - if (claim.return_order) { - await returnService - .withTransaction(manager) - .fulfill(claim.return_order.id) - } - - order = await orderService - .withTransaction(manager) - .retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - return { - response_code: 200, - response_body: { - order, - }, - } - }) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "finished": { - inProgress = false - break - } - - default: - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .update(idempotencyKey.idempotency_key, { - recovery_point: "finished", - response_code: 500, - response_body: { message: "Unknown recovery point" }, - }) - }) - break - } - } - - if (err) { - 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) -} - -/** - * The return's shipping method details. - */ -class ReturnShipping { - /** - * The ID of the shipping option used for the return. - */ - @IsString() - @IsOptional() - option_id?: string - - /** - * The shipping method's price. - */ - @IsInt() - @IsOptional() - price?: number -} - -class ShippingMethod { - @IsString() - @IsOptional() - id?: string - - @IsString() - @IsOptional() - option_id?: string - - @IsInt() - @IsOptional() - price?: number - - @IsObject() - @IsOptional() - data?: Record -} - -class Item { - @IsString() - @IsNotEmpty() - item_id: string - - @IsInt() - @IsNotEmpty() - quantity: number - - @IsString() - @IsOptional() - note?: string - - @IsEnum(ClaimReason) - @IsOptional() - reason?: ClaimReason - - @IsArray() - @IsOptional() - @IsString({ each: true }) - tags?: string[] - - @IsArray() - @IsOptional() - @IsString({ each: true }) - images?: string[] -} - -class AdditionalItem { - @IsString() - @IsNotEmpty() - variant_id: string - - @IsInt() - @IsNotEmpty() - quantity: number -} - -/** - * @schema AdminPostOrdersOrderClaimsReq - * type: object - * description: "The details of the claim to be created." - * required: - * - type - * - claim_items - * properties: - * type: - * description: >- - * The type of the Claim. This will determine how the Claim is treated: `replace` Claims will result in a Fulfillment with new items being created, while a `refund` Claim will refund the amount paid for the claimed items. - * type: string - * enum: - * - replace - * - refund - * claim_items: - * description: The Claim Items that the Claim will consist of. - * type: array - * items: - * type: object - * required: - * - item_id - * - quantity - * properties: - * item_id: - * description: The ID of the Line Item that will be claimed. - * type: string - * quantity: - * description: The number of items that will be returned - * type: integer - * note: - * description: Short text describing the Claim Item in further detail. - * type: string - * reason: - * description: The reason for the Claim - * type: string - * enum: - * - missing_item - * - wrong_item - * - production_failure - * - other - * tags: - * description: A list of tags to add to the Claim Item - * type: array - * items: - * type: string - * images: - * description: A list of image URL's that will be associated with the Claim - * items: - * type: string - * return_shipping: - * description: Optional details for the Return Shipping Method, if the items are to be sent back. Providing this field will result in a return being created and associated with the claim. - * type: object - * properties: - * option_id: - * type: string - * description: The ID of the Shipping Option to create the Shipping Method from. - * price: - * type: integer - * description: The price to charge for the Shipping Method. - * additional_items: - * description: The new items to send to the Customer. This is only used if the claim's type is `replace`. - * type: array - * items: - * type: object - * required: - * - variant_id - * - quantity - * properties: - * variant_id: - * description: The ID of the Product Variant. - * type: string - * quantity: - * description: The quantity of the Product Variant. - * type: integer - * shipping_methods: - * description: The Shipping Methods to send the additional Line Items with. This is only used if the claim's type is `replace`. - * type: array - * items: - * type: object - * properties: - * id: - * description: The ID of an existing Shipping Method - * type: string - * option_id: - * description: The ID of the Shipping Option to create a Shipping Method from - * type: string - * price: - * description: The price to charge for the Shipping Method - * type: integer - * data: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * shipping_address: - * description: "An optional shipping address to send the claimed items to. If not provided, the parent order's shipping address will be used." - * $ref: "#/components/schemas/AddressPayload" - * refund_amount: - * description: The amount to refund the customer. This is used when the claim's type is `refund`. - * type: integer - * no_notification: - * description: If set to true no notification will be send related to this Claim. - * type: boolean - * return_location_id: - * description: The ID of the location used for the associated return. - * type: string - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostOrdersOrderClaimsReq { - @IsEnum(ClaimType) - @IsNotEmpty() - type: ClaimTypeValue - - @IsArray() - @IsNotEmpty() - @Type(() => Item) - @ValidateNested({ each: true }) - claim_items: Item[] - - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => ReturnShipping) - return_shipping?: ReturnShipping - - @IsArray() - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => AdditionalItem) - additional_items?: AdditionalItem[] - - @IsArray() - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => ShippingMethod) - shipping_methods?: ShippingMethod[] - - @IsInt() - @IsOptional() - refund_amount?: number - - @IsObject() - @IsOptional() - @ValidateNested() - @Type(() => AddressPayload) - shipping_address?: AddressPayload - - @IsBoolean() - @IsOptional() - no_notification?: boolean - - @IsOptional() - @IsString() - return_location_id?: string - - @IsObject() - @IsOptional() - metadata?: Record -} - -export class AdminPostOrdersOrderClaimsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts b/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts deleted file mode 100644 index 8b30ea60d7..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts +++ /dev/null @@ -1,311 +0,0 @@ -import { - IsArray, - IsBoolean, - IsInt, - IsNotEmpty, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { Transform, Type } from "class-transformer" - -import { EntityManager } from "typeorm" -import { - OrderService, - ProductVariantInventoryService, -} from "../../../../services" -import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean" -import { Fulfillment, LineItem } from "../../../../models" -import { FindParams } from "../../../../types/common" -import { cleanResponseData } from "../../../../utils/clean-response-data" -import { promiseAll } from "@medusajs/utils" - -/** - * @oas [post] /admin/orders/{id}/fulfillment - * operationId: "PostOrdersOrderFulfillments" - * summary: "Create a Fulfillment" - * description: "Create a Fulfillment of an Order using the fulfillment provider, and change the order's fulfillment status to either `partially_fulfilled` or `fulfilled`, depending on - * whether all the items were fulfilled." - * x-authenticated: true - * externalDocs: - * description: Fulfillments of orders - * url: https://docs.medusajs.com/modules/orders/#fulfillments-in-orders - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderFulfillmentsReq" - * x-codegen: - * method: createFulfillment - * params: AdminPostOrdersOrderFulfillmentsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.createFulfillment(orderId, { - * items: [ - * { - * item_id, - * quantity: 1 - * } - * ] - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateFulfillment } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const createFulfillment = useAdminCreateFulfillment( - * orderId - * ) - * // ... - * - * const handleCreateFulfillment = ( - * itemId: string, - * quantity: number - * ) => { - * createFulfillment.mutate({ - * items: [ - * { - * item_id: itemId, - * quantity, - * }, - * ], - * }, { - * onSuccess: ({ order }) => { - * console.log(order.fulfillments) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/fulfillment' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "items": [ - * { - * "item_id": "{item_id}", - * "quantity": 1 - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const { validatedBody } = req as { - validatedBody: AdminPostOrdersOrderFulfillmentsReq - } - - const orderService: OrderService = req.scope.resolve("orderService") - const pvInventoryService: ProductVariantInventoryService = req.scope.resolve( - "productVariantInventoryService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - const orderServiceTx = orderService.withTransaction(transactionManager) - - const { fulfillments: existingFulfillments } = - await orderServiceTx.retrieve(id, { - relations: ["fulfillments"], - }) - const existingFulfillmentSet = new Set( - existingFulfillments.map((fulfillment) => fulfillment.id) - ) - - await orderServiceTx.createFulfillment(id, validatedBody.items, { - metadata: validatedBody.metadata, - no_notification: validatedBody.no_notification, - location_id: validatedBody.location_id, - }) - - if (validatedBody.location_id) { - const { fulfillments } = await orderServiceTx.retrieve(id, { - relations: [ - "fulfillments", - "fulfillments.items", - "fulfillments.items.item", - ], - }) - - const pvInventoryServiceTx = - pvInventoryService.withTransaction(transactionManager) - - await updateInventoryAndReservations( - fulfillments.filter((f) => !existingFulfillmentSet.has(f.id)), - { - inventoryService: pvInventoryServiceTx, - locationId: validatedBody.location_id, - } - ) - } - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.json({ order: cleanResponseData(order, []) }) -} - -export const updateInventoryAndReservations = async ( - fulfillments: Fulfillment[], - context: { - inventoryService: ProductVariantInventoryService - locationId: string - } -) => { - const { inventoryService, locationId } = context - - await promiseAll( - fulfillments.map(async ({ items }) => { - await inventoryService.validateInventoryAtLocation( - items.map(({ item, quantity }) => ({ ...item, quantity } as LineItem)), - locationId - ) - }) - ) - - await promiseAll( - fulfillments.map(async ({ items }) => { - await promiseAll( - items.map(async ({ item, quantity }) => { - if (!item.variant_id) { - return - } - - await inventoryService.adjustReservationsQuantityByLineItem( - item.id, - item.variant_id, - locationId, - -quantity - ) - - await inventoryService.adjustInventory( - item.variant_id, - locationId, - -quantity - ) - }) - ) - }) - ) -} - -/** - * @schema AdminPostOrdersOrderFulfillmentsReq - * type: object - * description: "The details of the fulfillment to be created." - * required: - * - items - * properties: - * items: - * description: The Line Items to include in the Fulfillment. - * type: array - * items: - * type: object - * required: - * - item_id - * - quantity - * properties: - * item_id: - * description: The ID of the Line Item to fulfill. - * type: string - * quantity: - * description: The quantity of the Line Item to fulfill. - * type: integer - * location_id: - * type: string - * description: "The ID of the location where the items will be fulfilled from." - * no_notification: - * description: >- - * If set to `true`, no notification will be sent to the customer related to this fulfillment. - * type: boolean - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostOrdersOrderFulfillmentsReq { - @IsArray() - @ValidateNested({ each: true }) - @Type(() => Item) - items: Item[] - - @IsString() - @IsOptional() - location_id?: string - - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value)) - no_notification?: boolean - - @IsObject() - @IsOptional() - metadata?: Record -} - -class Item { - @IsString() - @IsNotEmpty() - item_id: string - - @IsInt() - @IsNotEmpty() - quantity: number -} - -export class AdminPostOrdersOrderFulfillmentsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/create-reservation-for-line-item.ts b/packages/medusa/src/api/routes/admin/orders/create-reservation-for-line-item.ts deleted file mode 100644 index 1903af1885..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/create-reservation-for-line-item.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { - LineItemService, - ProductVariantInventoryService, -} from "../../../../services" - -/** - * @oas [post] /admin/orders/{id}/line-items/{line_item_id}/reserve - * operationId: "PostOrdersOrderLineItemReservations" - * summary: "Create a Reservation" - * description: "Create a Reservation for a line item at a specified location, optionally for a partial quantity." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (path) line_item_id=* {string} The ID of the Line item. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersOrderLineItemReservationReq" - * x-codeSamples: - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/line-items/{line_item_id}/reserve' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "location_id": "loc_1" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostReservationsReq" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, line_item_id } = req.params - - const { validatedBody } = req as { - validatedBody: AdminOrdersOrderLineItemReservationReq - } - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - const manager: EntityManager = req.scope.resolve("manager") - - const lineItemService: LineItemService = req.scope.resolve("lineItemService") - - const reservations = await manager.transaction(async (manager) => { - const lineItem = await lineItemService - .withTransaction(manager) - .retrieve(line_item_id) - - if (!lineItem.variant_id) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Can't create a reservation for a Line Item wihtout a variant` - ) - } - - const quantity = validatedBody.quantity || lineItem.quantity - - const productVariantInventoryServiceTx = - productVariantInventoryService.withTransaction(manager) - - return await productVariantInventoryServiceTx.reserveQuantity( - lineItem.variant_id, - quantity, - { - locationId: validatedBody.location_id, - } - ) - }) - - res.json({ reservation: reservations[0] }) -} - -/** - * @schema AdminOrdersOrderLineItemReservationReq - * type: object - * required: - * - location_id - * properties: - * location_id: - * description: "The ID of the location of the reservation" - * type: string - * quantity: - * description: "The quantity to reserve" - * type: number - */ -export class AdminOrdersOrderLineItemReservationReq { - location_id: string - - quantity?: number -} diff --git a/packages/medusa/src/api/routes/admin/orders/create-shipment.ts b/packages/medusa/src/api/routes/admin/orders/create-shipment.ts deleted file mode 100644 index c44fc59e75..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/create-shipment.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { - IsArray, - IsBoolean, - IsNotEmpty, - IsOptional, - IsString, -} from "class-validator" - -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 - * operationId: "PostOrdersOrderShipment" - * summary: "Ship a Fulfillment" - * description: "Create a shipment and mark a fulfillment as shipped. This changes the order's fulfillment status to either `partially_shipped` or `shipped`, depending on - * whether all the items were shipped." - * x-authenticated: true - * externalDocs: - * description: Fulfillments of orders - * url: https://docs.medusajs.com/modules/orders/#fulfillments-in-orders - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderShipmentReq" - * x-codegen: - * method: createShipment - * params: AdminPostOrdersOrderShipmentParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.createShipment(order_id, { - * fulfillment_id - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateShipment } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const createShipment = useAdminCreateShipment( - * orderId - * ) - * // ... - * - * const handleCreate = ( - * fulfillmentId: string - * ) => { - * createShipment.mutate({ - * fulfillment_id: fulfillmentId, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.fulfillment_status) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/shipment' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "fulfillment_id": "{fulfillment_id}" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = req.validatedBody - - const orderService: OrderService = req.scope.resolve("orderService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await orderService - .withTransaction(transactionManager) - .createShipment( - id, - validated.fulfillment_id, - validated.tracking_numbers?.map((n) => ({ - tracking_number: n, - })) as TrackingLink[], - { - metadata: {}, - no_notification: validated.no_notification, - } - ) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.json({ order: cleanResponseData(order, []) }) -} - -/** - * @schema AdminPostOrdersOrderShipmentReq - * type: object - * description: "The details of the shipment to create." - * required: - * - fulfillment_id - * properties: - * fulfillment_id: - * description: The ID of the Fulfillment. - * type: string - * tracking_numbers: - * description: The tracking numbers for the shipment. - * type: array - * items: - * type: string - * no_notification: - * description: If set to true no notification will be send related to this Shipment. - * type: boolean - */ -export class AdminPostOrdersOrderShipmentReq { - @IsString() - @IsNotEmpty() - fulfillment_id: string - - @IsArray() - @IsOptional() - @IsString({ each: true }) - tracking_numbers?: string[] - - @IsBoolean() - @IsOptional() - no_notification?: boolean -} - -export class AdminPostOrdersOrderShipmentParams extends FindParams {} 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 deleted file mode 100644 index c49bd8d649..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { - IsArray, - IsBoolean, - IsNotEmpty, - IsOptional, - IsString, -} from "class-validator" -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 - * operationId: "PostOrdersOrderSwapsSwapShipments" - * summary: "Ship a Swap's Fulfillment" - * description: "Create a shipment for a swap and mark its fulfillment as shipped. This changes the swap's fulfillment status to either `partially_shipped` or `shipped`, depending on - * whether all the items were shipped." - * x-authenticated: true - * externalDocs: - * description: Handling swap fulfillments - * url: https://docs.medusajs.com/modules/orders/swaps#handling-swap-fulfillment - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (path) swap_id=* {string} The ID of the Swap. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderSwapsSwapShipmentsReq" - * x-codegen: - * method: createSwapShipment - * params: AdminPostOrdersOrderSwapsSwapShipmentsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.createSwapShipment(orderId, swapId, { - * fulfillment_id - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateSwapShipment } from "medusa-react" - * - * type Props = { - * orderId: string, - * swapId: string - * } - * - * const Swap = ({ - * orderId, - * swapId - * }: Props) => { - * const createShipment = useAdminCreateSwapShipment( - * orderId - * ) - * // ... - * - * const handleCreateShipment = ( - * fulfillmentId: string - * ) => { - * createShipment.mutate({ - * swap_id: swapId, - * fulfillment_id: fulfillmentId, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.swaps) - * } - * }) - * } - * - * // ... - * } - * - * export default Swap - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/swaps/{swap_id}/shipments' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "fulfillment_id": "{fulfillment_id}" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, swap_id } = req.params - - const validated = await validator( - AdminPostOrdersOrderSwapsSwapShipmentsReq, - req.body - ) - - const orderService: OrderService = req.scope.resolve("orderService") - const swapService: SwapService = req.scope.resolve("swapService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await swapService.withTransaction(transactionManager).createShipment( - swap_id, - validated.fulfillment_id, - validated.tracking_numbers?.map((n) => ({ tracking_number: n })), - { no_notification: validated.no_notification } - ) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.json({ order: cleanResponseData(order, []) }) -} - -/** - * @schema AdminPostOrdersOrderSwapsSwapShipmentsReq - * type: object - * required: - * - fulfillment_id - * properties: - * fulfillment_id: - * description: The ID of the Fulfillment. - * type: string - * tracking_numbers: - * description: The tracking numbers for the shipment. - * type: array - * items: - * type: string - * no_notification: - * description: If set to true no notification will be sent related to this Claim. - * type: boolean - */ -export class AdminPostOrdersOrderSwapsSwapShipmentsReq { - @IsString() - @IsNotEmpty() - fulfillment_id: string - - @IsArray() - @IsOptional() - @IsString({ each: true }) - tracking_numbers?: string[] = [] - - @IsBoolean() - @IsOptional() - no_notification?: boolean -} - -export class AdminPostOrdersOrderSwapsSwapShipmentsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/create-swap.ts b/packages/medusa/src/api/routes/admin/orders/create-swap.ts deleted file mode 100644 index 15a108768a..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/create-swap.ts +++ /dev/null @@ -1,487 +0,0 @@ -import { - IsArray, - IsBoolean, - IsInt, - IsNotEmpty, - IsNumber, - IsObject, - IsOptional, - IsString, - Min, - ValidateNested, -} from "class-validator" -import { - IdempotencyKeyService, - OrderService, - ReturnService, - SwapService, -} from "../../../../services" - -import { Type } from "class-transformer" -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { FindParams } from "../../../../types/common" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [post] /admin/orders/{id}/swaps - * operationId: "PostOrdersOrderSwaps" - * summary: "Create a Swap" - * description: "Create a Swap. This includes creating a return that is associated with the swap." - * x-authenticated: true - * externalDocs: - * description: How are swaps created - * url: https://docs.medusajs.com/modules/orders/swaps#how-are-swaps-created - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderSwapsReq" - * x-codegen: - * method: createSwap - * queryParams: AdminPostOrdersOrderSwapsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.createSwap(orderId, { - * return_items: [ - * { - * item_id, - * quantity: 1 - * } - * ] - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateSwap } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const CreateSwap = ({ orderId }: Props) => { - * const createSwap = useAdminCreateSwap(orderId) - * // ... - * - * const handleCreate = ( - * returnItems: { - * item_id: string, - * quantity: number - * }[] - * ) => { - * createSwap.mutate({ - * return_items: returnItems - * }, { - * onSuccess: ({ order }) => { - * console.log(order.swaps) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateSwap - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/swaps' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "return_items": [ - * { - * "item_id": "asfasf", - * "quantity": 1 - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = req.validatedBody - - const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve( - "idempotencyKeyService" - ) - const orderService: OrderService = req.scope.resolve("orderService") - const swapService: SwapService = req.scope.resolve("swapService") - const returnService: ReturnService = req.scope.resolve("returnService") - const manager: EntityManager = req.scope.resolve("manager") - - const headerKey = req.get("Idempotency-Key") || "" - - let idempotencyKey - try { - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .initializeRequest(headerKey, req.method, req.params, req.path) - }) - } catch (error) { - res.status(409).send("Failed to create idempotency key") - return - } - - res.setHeader("Access-Control-Expose-Headers", "Idempotency-Key") - res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key) - - let inProgress = true - let err: unknown = false - - while (inProgress) { - switch (idempotencyKey.recovery_point) { - case "started": { - await manager - .transaction("SERIALIZABLE", async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .workStage(idempotencyKey.idempotency_key, async (manager) => { - const order = await orderService - .withTransaction(manager) - .retrieveWithTotals(id, { - relations: [ - "cart", - "items", - "items.variant", - "items.tax_lines", - "swaps", - "swaps.additional_items", - "swaps.additional_items.variant", - "swaps.additional_items.tax_lines", - ], - }) - - const swap = await swapService - .withTransaction(manager) - .create( - order, - validated.return_items, - validated.additional_items, - validated.return_shipping, - { - idempotency_key: idempotencyKey.idempotency_key, - no_notification: validated.no_notification, - allow_backorder: validated.allow_backorder, - location_id: validated.return_location_id, - } - ) - - await swapService - .withTransaction(manager) - .createCart(swap.id, validated.custom_shipping_options, { - sales_channel_id: validated.sales_channel_id, - }) - - const returnOrder = await returnService - .withTransaction(manager) - .retrieveBySwap(swap.id) - - await returnService - .withTransaction(manager) - .fulfill(returnOrder.id) - - return { - recovery_point: "swap_created", - } - }) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "swap_created": { - await manager - .transaction("SERIALIZABLE", async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .workStage(idempotencyKey.idempotency_key, async (manager) => { - const swaps = await swapService - .withTransaction(transactionManager) - .list({ - idempotency_key: idempotencyKey.idempotency_key, - }) - - if (!swaps.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Swap not found" - ) - } - - const order = await orderService - .withTransaction(transactionManager) - .retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - return { - response_code: 200, - response_body: { - order: cleanResponseData(order, []), - }, - } - }) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "finished": { - inProgress = false - break - } - - default: - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .update(idempotencyKey.idempotency_key, { - recovery_point: "finished", - response_code: 500, - response_body: { message: "Unknown recovery point" }, - }) - }) - break - } - } - - if (err) { - throw err - } - - res.status(idempotencyKey.response_code).json(idempotencyKey.response_body) -} - -class ReturnItem { - @IsString() - @IsNotEmpty() - item_id: string - - @IsNumber() - @IsNotEmpty() - @Min(1) - quantity: number - - @IsOptional() - @IsString() - reason_id?: string - - @IsOptional() - @IsString() - note?: string -} - -/** - * The return's shipping method details. - */ -class ReturnShipping { - /** - * The ID of the shipping option used for the return. - */ - @IsString() - @IsNotEmpty() - option_id: string - - /** - * The shipping method's price. - */ - @IsInt() - @IsOptional() - price?: number -} - -class CustomShippingOption { - @IsString() - @IsNotEmpty() - option_id: string - - @IsInt() - @IsNotEmpty() - price: number -} - -class AdditionalItem { - @IsString() - @IsNotEmpty() - variant_id: string - - @IsNumber() - @IsNotEmpty() - quantity: number -} - -/** - * @schema AdminPostOrdersOrderSwapsReq - * type: object - * description: "The details of the swap to create." - * required: - * - return_items - * properties: - * return_items: - * description: The Line Items to associate with the swap's return. - * type: array - * items: - * type: object - * required: - * - item_id - * - quantity - * properties: - * item_id: - * description: The ID of the Line Item that will be returned. - * type: string - * quantity: - * description: The number of items that will be returned - * type: integer - * reason_id: - * description: The ID of the Return Reason to use. - * type: string - * note: - * description: An optional note with information about the Return. - * type: string - * return_shipping: - * description: The shipping method associated with the swap's return. - * type: object - * required: - * - option_id - * properties: - * option_id: - * type: string - * description: The ID of the Shipping Option to create the Shipping Method from. - * price: - * type: integer - * description: The price to charge for the Shipping Method. - * additional_items: - * description: The new items to send to the Customer. - * type: array - * items: - * type: object - * required: - * - variant_id - * - quantity - * properties: - * variant_id: - * description: The ID of the Product Variant. - * type: string - * quantity: - * description: The quantity of the Product Variant. - * type: integer - * sales_channel_id: - * type: string - * description: "The ID of the sales channel associated with the swap." - * custom_shipping_options: - * description: An array of custom shipping options to potentially create a Shipping Method from to send the additional items. - * type: array - * items: - * type: object - * required: - * - option_id - * - price - * properties: - * option_id: - * description: The ID of the Shipping Option. - * type: string - * price: - * description: The custom price of the Shipping Option. - * type: integer - * no_notification: - * description: >- - * If set to `true`, no notification will be sent to the customer related to this Swap. - * type: boolean - * return_location_id: - * type: string - * description: "The ID of the location used for the associated return." - * allow_backorder: - * description: >- - * If set to `true`, swaps can be completed with items out of stock - * type: boolean - * default: true - */ -export class AdminPostOrdersOrderSwapsReq { - @IsArray() - @IsNotEmpty() - @ValidateNested({ each: true }) - @Type(() => ReturnItem) - return_items: ReturnItem[] - - @IsObject() - @IsOptional() - @ValidateNested() - @Type(() => ReturnShipping) - return_shipping?: ReturnShipping - - @IsOptional() - @IsString() - sales_channel_id?: string - - @IsArray() - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => AdditionalItem) - additional_items?: AdditionalItem[] - - @IsArray() - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => CustomShippingOption) - custom_shipping_options?: CustomShippingOption[] = [] - - @IsBoolean() - @IsOptional() - no_notification?: boolean - - @IsOptional() - @IsString() - return_location_id?: string - - @IsBoolean() - @IsOptional() - allow_backorder?: boolean = true -} - -export class AdminPostOrdersOrderSwapsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/fulfill-claim.ts b/packages/medusa/src/api/routes/admin/orders/fulfill-claim.ts deleted file mode 100644 index 0e488553d2..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/fulfill-claim.ts +++ /dev/null @@ -1,203 +0,0 @@ -import { IsBoolean, IsObject, IsOptional, IsString } from "class-validator" -import { - ClaimService, - OrderService, - ProductVariantInventoryService, -} from "../../../../services" - -import { EntityManager } from "typeorm" -import { FindParams } from "../../../../types/common" -import { cleanResponseData } from "../../../../utils/clean-response-data" -import { updateInventoryAndReservations } from "./create-fulfillment" - -/** - * @oas [post] /admin/orders/{id}/claims/{claim_id}/fulfillments - * operationId: "PostOrdersOrderClaimsClaimFulfillments" - * summary: "Create a Claim Fulfillment" - * description: "Create a Fulfillment for a Claim, and change its fulfillment status to `partially_fulfilled` or `fulfilled` depending on whether all the items were fulfilled. - * It may also change the status to `requires_action` if any actions are required." - * x-authenticated: true - * externalDocs: - * description: Fulfill a claim - * url: https://docs.medusajs.com/modules/orders/claims#fulfill-a-claim - * parameters: - * - (path) id=* {string} The ID of the Order the claim is associated with. - * - (path) claim_id=* {string} The ID of the Claim. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderClaimsClaimFulfillmentsReq" - * x-codegen: - * method: fulfillClaim - * params: AdminPostOrdersOrderClaimsClaimFulfillmentsReq - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.fulfillClaim(orderId, claimId, { - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminFulfillClaim } from "medusa-react" - * - * type Props = { - * orderId: string - * claimId: string - * } - * - * const Claim = ({ orderId, claimId }: Props) => { - * const fulfillClaim = useAdminFulfillClaim(orderId) - * // ... - * - * const handleFulfill = () => { - * fulfillClaim.mutate({ - * claim_id: claimId, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.claims) - * } - * }) - * } - * - * // ... - * } - * - * export default Claim - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/claims/{claim_id}/fulfillments' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, claim_id } = req.params - - const validated = req.validatedBody - - const orderService: OrderService = req.scope.resolve("orderService") - const claimService: ClaimService = req.scope.resolve("claimService") - const entityManager: EntityManager = req.scope.resolve("manager") - const pvInventoryService: ProductVariantInventoryService = req.scope.resolve( - "productVariantInventoryService" - ) - - await entityManager.transaction(async (manager) => { - const claimServiceTx = claimService.withTransaction(manager) - - const { fulfillments: existingFulfillments } = - await claimServiceTx.retrieve(claim_id, { - relations: [ - "fulfillments", - "fulfillments.items", - "fulfillments.items.item", - ], - }) - - const existingFulfillmentSet = new Set( - existingFulfillments.map((fulfillment) => fulfillment.id) - ) - - await claimServiceTx.createFulfillment(claim_id, { - metadata: validated.metadata, - no_notification: validated.no_notification, - location_id: validated.location_id, - }) - - if (validated.location_id) { - const { fulfillments } = await claimServiceTx.retrieve(claim_id, { - relations: [ - "fulfillments", - "fulfillments.items", - "fulfillments.items.item", - ], - }) - - const pvInventoryServiceTx = pvInventoryService.withTransaction(manager) - - await updateInventoryAndReservations( - fulfillments.filter((f) => !existingFulfillmentSet.has(f.id)), - { - inventoryService: pvInventoryServiceTx, - locationId: validated.location_id, - } - ) - } - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.status(200).json({ order: cleanResponseData(order, []) }) -} - -/** - * @schema AdminPostOrdersOrderClaimsClaimFulfillmentsReq - * type: object - * properties: - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * no_notification: - * description: >- - * If set to `true`, no notification will be sent to the customer related to this Claim. - * type: boolean - * location_id: - * description: "The ID of the fulfillment's location." - * type: string - */ -export class AdminPostOrdersOrderClaimsClaimFulfillmentsReq { - @IsObject() - @IsOptional() - metadata?: Record - - @IsBoolean() - @IsOptional() - no_notification?: boolean - - @IsString() - @IsOptional() - location_id?: string -} - -// eslint-disable-next-line max-len -export class AdminPostOrdersOrderClaimsClaimFulfillmentsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/fulfill-swap.ts b/packages/medusa/src/api/routes/admin/orders/fulfill-swap.ts deleted file mode 100644 index ee5e525a92..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/fulfill-swap.ts +++ /dev/null @@ -1,214 +0,0 @@ -import { IsBoolean, IsObject, IsOptional, IsString } from "class-validator" -import { - OrderService, - ProductVariantInventoryService, - SwapService, -} from "../../../../services" - -import { EntityManager } from "typeorm" -import { FindParams } from "../../../../types/common" -import { cleanResponseData } from "../../../../utils/clean-response-data" -import { validator } from "../../../../utils/validator" -import { updateInventoryAndReservations } from "./create-fulfillment" - -/** - * @oas [post] /admin/orders/{id}/swaps/{swap_id}/fulfillments - * operationId: "PostOrdersOrderSwapsSwapFulfillments" - * summary: "Create a Swap Fulfillment" - * description: "Create a Fulfillment for a Swap and change its fulfillment status to `fulfilled`. If it requires any additional actions, - * its fulfillment status may change to `requires_action`." - * x-authenticated: true - * externalDocs: - * description: Handling a swap's fulfillment - * url: https://docs.medusajs.com/modules/orders/swaps#handling-swap-fulfillment - * parameters: - * - (path) id=* {string} The ID of the Order the swap is associated with. - * - (path) swap_id=* {string} The ID of the Swap. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderSwapsSwapFulfillmentsReq" - * x-codegen: - * method: fulfillSwap - * params: AdminPostOrdersOrderSwapsSwapFulfillmentsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.fulfillSwap(orderId, swapId, { - * - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminFulfillSwap } from "medusa-react" - * - * type Props = { - * orderId: string, - * swapId: string - * } - * - * const Swap = ({ - * orderId, - * swapId - * }: Props) => { - * const fulfillSwap = useAdminFulfillSwap( - * orderId - * ) - * // ... - * - * const handleFulfill = () => { - * fulfillSwap.mutate({ - * swap_id: swapId, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.swaps) - * } - * }) - * } - * - * // ... - * } - * - * export default Swap - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/swaps/{swap_id}/fulfillments' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, swap_id } = req.params - - const validated = await validator( - AdminPostOrdersOrderSwapsSwapFulfillmentsReq, - req.body - ) - - const orderService: OrderService = req.scope.resolve("orderService") - const swapService: SwapService = req.scope.resolve("swapService") - const entityManager: EntityManager = req.scope.resolve("manager") - const pvInventoryService: ProductVariantInventoryService = req.scope.resolve( - "productVariantInventoryService" - ) - - await entityManager.transaction(async (manager) => { - const swapServiceTx = swapService.withTransaction(manager) - - const { fulfillments: existingFulfillments } = await swapServiceTx.retrieve( - swap_id, - { - relations: [ - "fulfillments", - "fulfillments.items", - "fulfillments.items.item", - ], - } - ) - - const existingFulfillmentSet = new Set( - existingFulfillments.map((fulfillment) => fulfillment.id) - ) - - await swapServiceTx.createFulfillment(swap_id, { - metadata: validated.metadata, - no_notification: validated.no_notification, - location_id: validated.location_id, - }) - - if (validated.location_id) { - const { fulfillments } = await swapServiceTx.retrieve(swap_id, { - relations: [ - "fulfillments", - "fulfillments.items", - "fulfillments.items.item", - ], - }) - - const pvInventoryServiceTx = pvInventoryService.withTransaction(manager) - - await updateInventoryAndReservations( - fulfillments.filter((f) => !existingFulfillmentSet.has(f.id)), - { - inventoryService: pvInventoryServiceTx, - locationId: validated.location_id, - } - ) - } - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.status(200).json({ order: cleanResponseData(order, []) }) -} - -/** - * @schema AdminPostOrdersOrderSwapsSwapFulfillmentsReq - * type: object - * properties: - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * no_notification: - * description: If set to `true`, no notification will be sent to the customer related to this swap. - * type: boolean - * location_id: - * description: "The ID of the fulfillment's location." - * type: string - */ -export class AdminPostOrdersOrderSwapsSwapFulfillmentsReq { - @IsObject() - @IsOptional() - metadata?: Record - - @IsBoolean() - @IsOptional() - no_notification?: boolean - - @IsString() - @IsOptional() - location_id?: string -} - -// eslint-disable-next-line max-len -export class AdminPostOrdersOrderSwapsSwapFulfillmentsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/get-order.ts b/packages/medusa/src/api/routes/admin/orders/get-order.ts deleted file mode 100644 index 0e58a3112f..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/get-order.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { Order } from "../../../../models" -import { OrderService } from "../../../../services" -import { FindParams } from "../../../../types/common" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [get] /admin/orders/{id} - * operationId: "GetOrdersOrder" - * summary: "Get an Order" - * description: "Retrieve an Order's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * x-codegen: - * method: retrieve - * queryParams: AdminGetOrdersOrderParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.retrieve(orderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminOrder } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const { - * order, - * isLoading, - * } = useAdminOrder(orderId) - * - * return ( - *
- * {isLoading && Loading...} - * {order && {order.display_id}} - * - *
- * ) - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/orders/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const orderService: OrderService = req.scope.resolve("orderService") - - let order: Partial = await orderService.retrieveWithTotals( - id, - req.retrieveConfig, - { - includes: req.includes, - } - ) - - order = cleanResponseData(order, req.allowedProperties) - - res.json({ order: order }) -} - -export class AdminGetOrdersOrderParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/get-reservations.ts b/packages/medusa/src/api/routes/admin/orders/get-reservations.ts deleted file mode 100644 index 542bc733f3..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/get-reservations.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { IInventoryService } from "@medusajs/types" -import { Request, Response } from "express" -import { OrderService } from "../../../../services" -import { extendedFindParamsMixin } from "../../../../types/common" - -/** - * @oas [get] /admin/orders/{id}/reservations - * operationId: "GetOrdersOrderReservations" - * summary: "Get Order Reservations" - * description: "Retrieve the list of reservations of an Order" - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) offset=0 {integer} The number of reservations to skip when retrieving the reservations. - * - (query) limit=20 {integer} Limit the number of reservations returned. - * x-codeSamples: - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/orders/{id}/reservations' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReservationsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - const orderService: OrderService = req.scope.resolve("orderService") - - const order = await orderService.retrieve(id, { relations: ["items"] }) - - const [reservations, count] = await inventoryService.listReservationItems( - { - line_item_id: order.items.map((i) => i.id), - }, - req.listConfig - ) - - const { limit, offset } = req.validatedQuery - - res.json({ reservations, count, limit, offset }) -} - -// eslint-disable-next-line max-len -export class AdminGetOrdersOrderReservationsParams extends extendedFindParamsMixin( - { - limit: 20, - offset: 0, - } -) {} diff --git a/packages/medusa/src/api/routes/admin/orders/index.ts b/packages/medusa/src/api/routes/admin/orders/index.ts deleted file mode 100644 index ade9cab810..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/index.ts +++ /dev/null @@ -1,783 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { Router } from "express" -import "reflect-metadata" -import { Order } from "../../../.." -import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" -import { FindParams, PaginatedResponse } from "../../../../types/common" -import { - defaultAdminOrdersFields, - defaultAdminOrdersRelations, -} from "../../../../types/orders" -import middlewares, { - transformBody, - transformIncludesOptions, - transformQuery, -} from "../../../middlewares" -import { checkRegisteredModules } from "../../../middlewares/check-registered-modules" -import { - AdminPostOrdersOrderShippingMethodsParams, - AdminPostOrdersOrderShippingMethodsReq, -} from "./add-shipping-method" -import { AdminPostOrdersOrderArchiveParams } from "./archive-order" -import { AdminPostOrdersClaimCancel } from "./cancel-claim" -import { AdminPostOrdersOrderFulfillementsCancelParams } from "./cancel-fulfillment" -import { AdminPostOrdersClaimFulfillmentsCancelParams } from "./cancel-fulfillment-claim" -import { AdminPostOrdersOrderSwapFulfillementsCancelParams } from "./cancel-fulfillment-swap" -import { AdminPostOrdersOrderCancel } from "./cancel-order" -import { AdminPostOrdersSwapCancelParams } from "./cancel-swap" -import { AdminPostOrdersOrderCaptureParams } from "./capture-payment" -import { AdminPostOrdersOrderCompleteParams } from "./complete-order" -import { - AdminPostOrdersOrderClaimsParams, - AdminPostOrdersOrderClaimsReq, -} from "./create-claim" -import { - AdminPostOrdersOrderClaimsClaimShipmentsParams, - AdminPostOrdersOrderClaimsClaimShipmentsReq, -} from "./create-claim-shipment" -import { - AdminPostOrdersOrderFulfillmentsParams, - AdminPostOrdersOrderFulfillmentsReq, -} from "./create-fulfillment" -import { AdminOrdersOrderLineItemReservationReq } from "./create-reservation-for-line-item" -import { - AdminPostOrdersOrderShipmentParams, - AdminPostOrdersOrderShipmentReq, -} from "./create-shipment" -import { - AdminPostOrdersOrderSwapsParams, - AdminPostOrdersOrderSwapsReq, -} from "./create-swap" -import { - AdminPostOrdersOrderSwapsSwapShipmentsParams, - AdminPostOrdersOrderSwapsSwapShipmentsReq, -} from "./create-swap-shipment" -import { - AdminPostOrdersOrderClaimsClaimFulfillmentsParams, - AdminPostOrdersOrderClaimsClaimFulfillmentsReq, -} from "./fulfill-claim" -import { AdminPostOrdersOrderSwapsSwapFulfillmentsParams } from "./fulfill-swap" -import { AdminGetOrdersOrderReservationsParams } from "./get-reservations" -import { AdminGetOrdersParams } from "./list-orders" -import { AdminPostOrdersOrderSwapsSwapProcessPaymentParams } from "./process-swap-payment" -import { - AdminPostOrdersOrderRefundsParams, - AdminPostOrdersOrderRefundsReq, -} from "./refund-payment" -import { - AdminPostOrdersOrderReturnsParams, - AdminPostOrdersOrderReturnsReq, -} from "./request-return" -import { - AdminPostOrdersOrderClaimsClaimParams, - AdminPostOrdersOrderClaimsClaimReq, -} from "./update-claim" -import { - AdminPostOrdersOrderParams, - AdminPostOrdersOrderReq, -} from "./update-order" - -const route = Router() - -export default (app, featureFlagRouter: FlagRouter) => { - app.use("/orders", route) - - const relations = [...defaultAdminOrdersRelations] - const defaultFields = [...defaultAdminOrdersFields] - - if (featureFlagRouter.isFeatureEnabled(SalesChannelFeatureFlag.key)) { - relations.push("sales_channel") - defaultFields.push("sales_channel_id") - } - - /** - * List orders - */ - route.get( - "/", - transformIncludesOptions(allowedOrderIncludes), - transformQuery(AdminGetOrdersParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: true, - }), - middlewares.wrap(require("./list-orders").default) - ) - - /** - * Get an order - */ - route.get( - "/:id", - transformIncludesOptions(allowedOrderIncludes, [ - AvailableOrderIncludes.RETURNABLE_ITEMS, - ]), - transformQuery(AdminPostOrdersOrderParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./get-order").default) - ) - - /** - * Update an order - */ - route.post( - "/:id", - transformIncludesOptions(allowedOrderIncludes), - transformBody(AdminPostOrdersOrderReq), - transformQuery(FindParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./update-order").default) - ) - - /** - * Mark an order as completed - */ - route.post( - "/:id/complete", - transformIncludesOptions(allowedOrderIncludes), - transformQuery(AdminPostOrdersOrderCompleteParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./complete-order").default) - ) - - /** - * Refund an amount to the customer's card. - */ - route.post( - "/:id/refund", - transformIncludesOptions(allowedOrderIncludes), - transformBody(AdminPostOrdersOrderRefundsReq), - transformQuery(AdminPostOrdersOrderRefundsParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./refund-payment").default) - ) - - /** - * Capture the authorized amount on the customer's card. - */ - route.post( - "/:id/capture", - transformIncludesOptions(allowedOrderIncludes), - transformQuery(AdminPostOrdersOrderCaptureParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./capture-payment").default) - ) - - /** - * Create a fulfillment. - */ - route.post( - "/:id/fulfillment", - transformIncludesOptions(allowedOrderIncludes), - transformBody(AdminPostOrdersOrderFulfillmentsReq), - transformQuery(AdminPostOrdersOrderFulfillmentsParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./create-fulfillment").default) - ) - - /** - * Cancel a fulfillment related to an order. - */ - route.post( - "/:id/fulfillments/:fulfillment_id/cancel", - transformIncludesOptions(allowedOrderIncludes), - transformQuery(AdminPostOrdersOrderFulfillementsCancelParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./cancel-fulfillment").default) - ) - - /** - * Cancel a fulfillment related to a swap. - */ - route.post( - "/:id/swaps/:swap_id/fulfillments/:fulfillment_id/cancel", - transformIncludesOptions(allowedOrderIncludes), - transformQuery(AdminPostOrdersOrderSwapFulfillementsCancelParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./cancel-fulfillment-swap").default) - ) - - /** - * Cancel a fulfillment related to a claim. - */ - route.post( - "/:id/claims/:claim_id/fulfillments/:fulfillment_id/cancel", - transformIncludesOptions(allowedOrderIncludes), - transformQuery(AdminPostOrdersClaimFulfillmentsCancelParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./cancel-fulfillment-claim").default) - ) - - /** - * Create a shipment. - */ - route.post( - "/:id/shipment", - transformIncludesOptions(allowedOrderIncludes), - transformBody(AdminPostOrdersOrderShipmentReq), - transformQuery(AdminPostOrdersOrderShipmentParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./create-shipment").default) - ) - - /** - * Request a return. - */ - route.post( - "/:id/return", - transformIncludesOptions(allowedOrderIncludes), - transformBody(AdminPostOrdersOrderReturnsReq), - transformQuery(AdminPostOrdersOrderReturnsParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./request-return").default) - ) - - /** - * Cancel an order. - */ - route.post( - "/:id/cancel", - transformIncludesOptions(allowedOrderIncludes), - transformQuery(AdminPostOrdersOrderCancel, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./cancel-order").default) - ) - - /** - * Add a shipping method - */ - route.post( - "/:id/shipping-methods", - transformIncludesOptions(allowedOrderIncludes), - transformBody(AdminPostOrdersOrderShippingMethodsReq), - transformQuery(AdminPostOrdersOrderShippingMethodsParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./add-shipping-method").default) - ) - - /** - * Archive an order. - */ - route.post( - "/:id/archive", - transformIncludesOptions(allowedOrderIncludes), - transformQuery(AdminPostOrdersOrderArchiveParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./archive-order").default) - ) - - /** - * Creates a swap, requests a return and prepares a cart for payment. - */ - route.post( - "/:id/swaps", - transformIncludesOptions(allowedOrderIncludes, [ - AvailableOrderIncludes.RETURNABLE_ITEMS, - ]), - transformBody(AdminPostOrdersOrderSwapsReq), - transformQuery(AdminPostOrdersOrderSwapsParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./create-swap").default) - ) - - /** - * Cancels a swap. - */ - route.post( - "/:id/swaps/:swap_id/cancel", - transformIncludesOptions(allowedOrderIncludes), - transformQuery(AdminPostOrdersSwapCancelParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./cancel-swap").default) - ) - - /** - * Fulfills a swap. - */ - route.post( - "/:id/swaps/:swap_id/fulfillments", - transformIncludesOptions(allowedOrderIncludes), - transformQuery(AdminPostOrdersOrderSwapsSwapFulfillmentsParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./fulfill-swap").default) - ) - - /** - * Marks a swap fulfillment as shipped. - */ - route.post( - "/:id/swaps/:swap_id/shipments", - transformIncludesOptions(allowedOrderIncludes), - transformBody(AdminPostOrdersOrderSwapsSwapShipmentsReq), - transformQuery(AdminPostOrdersOrderSwapsSwapShipmentsParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./create-swap-shipment").default) - ) - - /** - * Captures the payment associated with a swap - */ - route.post( - "/:id/swaps/:swap_id/process-payment", - transformIncludesOptions(allowedOrderIncludes), - transformQuery(AdminPostOrdersOrderSwapsSwapProcessPaymentParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./process-swap-payment").default) - ) - - /** - * Creates a claim - */ - route.post( - "/:id/claims", - transformIncludesOptions(allowedOrderIncludes), - transformBody(AdminPostOrdersOrderClaimsReq), - transformQuery(AdminPostOrdersOrderClaimsParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./create-claim").default) - ) - - /** - * Cancels a claim - */ - route.post( - "/:id/claims/:claim_id/cancel", - transformIncludesOptions(allowedOrderIncludes), - transformQuery(AdminPostOrdersClaimCancel, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./cancel-claim").default) - ) - - /** - * Updates a claim - */ - route.post( - "/:id/claims/:claim_id", - transformIncludesOptions(allowedOrderIncludes), - transformBody(AdminPostOrdersOrderClaimsClaimReq), - transformQuery(AdminPostOrdersOrderClaimsClaimParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./update-claim").default) - ) - - /** - * Creates claim fulfillment - */ - route.post( - "/:id/claims/:claim_id/fulfillments", - transformIncludesOptions(allowedOrderIncludes), - transformBody(AdminPostOrdersOrderClaimsClaimFulfillmentsReq), - transformQuery(AdminPostOrdersOrderClaimsClaimFulfillmentsParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./fulfill-claim").default) - ) - - /** - * Creates claim shipment - */ - route.post( - "/:id/claims/:claim_id/shipments", - transformIncludesOptions(allowedOrderIncludes), - transformBody(AdminPostOrdersOrderClaimsClaimShipmentsReq), - transformQuery(AdminPostOrdersOrderClaimsClaimShipmentsParams, { - defaultRelations: relations, - defaultFields: defaultFields, - isList: false, - }), - middlewares.wrap(require("./create-claim-shipment").default) - ) - - route.get( - "/:id/reservations", - checkRegisteredModules({ - inventoryService: - "Inventory is not enabled. Please add an Inventory module to enable this functionality.", - }), - transformQuery(AdminGetOrdersOrderReservationsParams, { - isList: true, - }), - middlewares.wrap(require("./get-reservations").default) - ) - - route.post( - "/:id/line-items/:line_item_id/reserve", - checkRegisteredModules({ - inventoryService: - "Inventory is not enabled. Please add an Inventory module to enable this functionality.", - }), - transformBody(AdminOrdersOrderLineItemReservationReq), - middlewares.wrap(require("./create-reservation-for-line-item").default) - ) - - return app -} - -/** - * @schema AdminOrdersRes - * type: object - * description: "The order's details." - * x-expanded-relations: - * field: order - * relations: - * - billing_address - * - claims - * - claims.additional_items - * - claims.additional_items.variant - * - claims.claim_items - * - claims.claim_items.images - * - claims.claim_items.item - * - claims.fulfillments - * - claims.fulfillments.tracking_links - * - claims.return_order - * - claims.return_order.shipping_method - * - claims.return_order.shipping_method.tax_lines - * - claims.shipping_address - * - claims.shipping_methods - * - customer - * - discounts - * - discounts.rule - * - fulfillments - * - fulfillments.items - * - fulfillments.tracking_links - * - gift_card_transactions - * - gift_cards - * - items - * - payments - * - refunds - * - region - * - returns - * - returns.items - * - returns.items.reason - * - returns.shipping_method - * - returns.shipping_method.tax_lines - * - shipping_address - * - shipping_methods - * eager: - * - fulfillments.items - * - region.fulfillment_providers - * - region.payment_providers - * - returns.items - * - shipping_methods.shipping_option - * implicit: - * - claims - * - claims.additional_items - * - claims.additional_items.adjustments - * - claims.additional_items.refundable - * - claims.additional_items.tax_lines - * - discounts - * - discounts.rule - * - gift_card_transactions - * - gift_card_transactions.gift_card - * - gift_cards - * - items - * - items.adjustments - * - items.refundable - * - items.tax_lines - * - items.variant - * - items.variant.product - * - items.variant.product.profiles - * - refunds - * - region - * - shipping_methods - * - shipping_methods.tax_lines - * - swaps - * - swaps.additional_items - * - swaps.additional_items.adjustments - * - swaps.additional_items.refundable - * - swaps.additional_items.tax_lines - * totals: - * - discount_total - * - gift_card_tax_total - * - gift_card_total - * - paid_total - * - refundable_amount - * - refunded_total - * - shipping_total - * - subtotal - * - tax_total - * - total - * - claims.additional_items.discount_total - * - claims.additional_items.gift_card_total - * - claims.additional_items.original_tax_total - * - claims.additional_items.original_total - * - claims.additional_items.refundable - * - claims.additional_items.subtotal - * - claims.additional_items.tax_total - * - claims.additional_items.total - * - items.discount_total - * - items.gift_card_total - * - items.original_tax_total - * - items.original_total - * - items.refundable - * - items.subtotal - * - items.tax_total - * - items.total - * - swaps.additional_items.discount_total - * - swaps.additional_items.gift_card_total - * - swaps.additional_items.original_tax_total - * - swaps.additional_items.original_total - * - swaps.additional_items.refundable - * - swaps.additional_items.subtotal - * - swaps.additional_items.tax_total - * - swaps.additional_items.total - * required: - * - order - * properties: - * order: - * description: "Order details." - * $ref: "#/components/schemas/Order" - */ -export type AdminOrdersRes = { - order: Order -} - -/** - * @schema AdminOrdersListRes - * type: object - * description: "The list of orders with pagination fields." - * x-expanded-relations: - * field: orders - * relations: - * - billing_address - * - claims - * - claims.additional_items - * - claims.additional_items.variant - * - claims.claim_items - * - claims.claim_items.images - * - claims.claim_items.item - * - claims.fulfillments - * - claims.fulfillments.tracking_links - * - claims.return_order - * - claims.return_order.shipping_method - * - claims.return_order.shipping_method.tax_lines - * - claims.shipping_address - * - claims.shipping_methods - * - customer - * - discounts - * - discounts.rule - * - fulfillments - * - fulfillments.items - * - fulfillments.tracking_links - * - gift_card_transactions - * - gift_cards - * - items - * - payments - * - refunds - * - region - * - returns - * - returns.items - * - returns.items.reason - * - returns.shipping_method - * - returns.shipping_method.tax_lines - * - shipping_address - * - shipping_methods - * eager: - * - fulfillments.items - * - region.fulfillment_providers - * - region.payment_providers - * - returns.items - * - shipping_methods.shipping_option - * implicit: - * - claims - * - claims.additional_items - * - claims.additional_items.adjustments - * - claims.additional_items.refundable - * - claims.additional_items.tax_lines - * - discounts - * - discounts.rule - * - gift_card_transactions - * - gift_card_transactions.gift_card - * - gift_cards - * - items - * - items.adjustments - * - items.refundable - * - items.tax_lines - * - items.variant - * - items.variant.product - * - items.variant.product.profiles - * - refunds - * - region - * - shipping_methods - * - shipping_methods.tax_lines - * - swaps - * - swaps.additional_items - * - swaps.additional_items.adjustments - * - swaps.additional_items.refundable - * - swaps.additional_items.tax_lines - * totals: - * - discount_total - * - gift_card_tax_total - * - gift_card_total - * - paid_total - * - refundable_amount - * - refunded_total - * - shipping_total - * - subtotal - * - tax_total - * - total - * - claims.additional_items.discount_total - * - claims.additional_items.gift_card_total - * - claims.additional_items.original_tax_total - * - claims.additional_items.original_total - * - claims.additional_items.refundable - * - claims.additional_items.subtotal - * - claims.additional_items.tax_total - * - claims.additional_items.total - * - items.discount_total - * - items.gift_card_total - * - items.original_tax_total - * - items.original_total - * - items.refundable - * - items.subtotal - * - items.tax_total - * - items.total - * - swaps.additional_items.discount_total - * - swaps.additional_items.gift_card_total - * - swaps.additional_items.original_tax_total - * - swaps.additional_items.original_total - * - swaps.additional_items.refundable - * - swaps.additional_items.subtotal - * - swaps.additional_items.tax_total - * - swaps.additional_items.total - * required: - * - orders - * - count - * - offset - * - limit - * properties: - * orders: - * type: array - * description: "An array of order details." - * items: - * $ref: "#/components/schemas/Order" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of orders skipped when retrieving the orders. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminOrdersListRes = PaginatedResponse & { - orders: Order[] -} - -export const filterableAdminOrdersFields = [ - "id", - "status", - "fulfillment_status", - "payment_status", - "display_id", - "cart_id", - "customer_id", - "email", - "region_id", - "currency_code", - "tax_rate", - "canceled_at", - "created_at", - "updated_at", -] - -export const AvailableOrderIncludes = { - RETURNABLE_ITEMS: "returnable_items", -} - -export const allowedOrderIncludes = [AvailableOrderIncludes.RETURNABLE_ITEMS] - -export * from "./add-shipping-method" -export * from "./archive-order" -export * from "./cancel-claim" -export * from "./cancel-fulfillment" -export * from "./cancel-fulfillment-claim" -export * from "./cancel-fulfillment-swap" -export * from "./cancel-order" -export * from "./cancel-swap" -export * from "./capture-payment" -export * from "./complete-order" -export * from "./create-claim" -export * from "./create-claim-shipment" -export * from "./create-fulfillment" -export * from "./create-shipment" -export * from "./create-swap" -export * from "./create-swap-shipment" -export * from "./fulfill-claim" -export * from "./fulfill-swap" -export * from "./get-order" -export * from "./list-orders" -export * from "./process-swap-payment" -export * from "./refund-payment" -export * from "./request-return" -export * from "./update-claim" -export * from "./update-order" diff --git a/packages/medusa/src/api/routes/admin/orders/list-orders.ts b/packages/medusa/src/api/routes/admin/orders/list-orders.ts deleted file mode 100644 index d51e58d2bb..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/list-orders.ts +++ /dev/null @@ -1,289 +0,0 @@ -import { IsNumber, IsOptional, IsString } from "class-validator" - -import { Type } from "class-transformer" -import { OrderService } from "../../../../services" -import { AdminListOrdersSelector } from "../../../../types/orders" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [get] /admin/orders - * operationId: "GetOrders" - * summary: "List Orders" - * description: "Retrieve a list of Orders. The orders can be filtered by fields such as `status` or `display_id`. The order can also be paginated." - * x-authenticated: true - * parameters: - * - (query) q {string} term to search orders' shipping address, first name, email, and display ID - * - (query) id {string} Filter by ID. - * - in: query - * name: status - * style: form - * explode: false - * description: Filter by status - * schema: - * type: array - * items: - * type: string - * enum: [pending, completed, archived, canceled, requires_action] - * - in: query - * name: fulfillment_status - * style: form - * explode: false - * description: Filter by fulfillment status - * schema: - * type: array - * items: - * type: string - * enum: [not_fulfilled, fulfilled, partially_fulfilled, shipped, partially_shipped, canceled, returned, partially_returned, requires_action] - * - in: query - * name: payment_status - * style: form - * explode: false - * description: Filter by payment status - * schema: - * type: array - * items: - * type: string - * enum: [captured, awaiting, not_paid, refunded, partially_refunded, canceled, requires_action] - * - (query) display_id {string} Filter by display ID - * - (query) cart_id {string} Filter by cart ID - * - (query) customer_id {string} Filter by customer ID - * - (query) email {string} Filter by email - * - in: query - * name: region_id - * style: form - * explode: false - * description: Filter by region IDs. - * schema: - * oneOf: - * - type: string - * description: ID of a Region. - * - type: array - * items: - * type: string - * description: ID of a Region. - * - in: query - * name: currency_code - * style: form - * explode: false - * description: Filter by currency codes. - * schema: - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * - (query) tax_rate {string} Filter by tax rate. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: canceled_at - * description: Filter by a cancelation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: sales_channel_id - * style: form - * explode: false - * description: Filter by Sales Channel IDs - * schema: - * type: array - * items: - * type: string - * description: The ID of a Sales Channel - * - (query) offset=0 {integer} The number of orders to skip when retrieving the orders. - * - (query) limit=50 {integer} Limit the number of orders returned. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * - (query) order {string} Field to sort retrieved orders by. - * x-codegen: - * method: list - * queryParams: AdminGetOrdersParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.list() - * .then(({ orders, limit, offset, count }) => { - * console.log(orders.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminOrders } from "medusa-react" - * - * const Orders = () => { - * const { orders, isLoading } = useAdminOrders() - * - * return ( - *
- * {isLoading && Loading...} - * {orders && !orders.length && No Orders} - * {orders && orders.length > 0 && ( - *
    - * {orders.map((order) => ( - *
  • {order.display_id}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Orders - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/orders' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const orderService: OrderService = req.scope.resolve("orderService") - - const { skip, take } = req.listConfig - - const [orders, count] = await orderService.listAndCount( - req.filterableFields, - req.listConfig - ) - - const data = cleanResponseData(orders, req.allowedProperties) - - res.json({ - orders: cleanResponseData(data, []), - count, - offset: skip, - limit: take, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved orders. - */ -export class AdminGetOrdersParams extends AdminListOrdersSelector { - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - offset = 0 - - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 50 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit = 50 - - /** - * {@inheritDoc FindParams.expand} - */ - @IsString() - @IsOptional() - expand?: string - - /** - * {@inheritDoc FindParams.fields} - */ - @IsString() - @IsOptional() - fields?: string - - /** - * The field to sort retrieved orders by. By default, the sort order is ascending. - * To change the order to descending, prefix the field name with `-`. - */ - @IsOptional() - @IsString() - order?: string -} 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 deleted file mode 100644 index 7f28a998cc..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/process-swap-payment.ts +++ /dev/null @@ -1,118 +0,0 @@ -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 - * operationId: "PostOrdersOrderSwapsSwapProcessPayment" - * summary: "Process a Swap Payment" - * description: "Process a swap's payment either by refunding or issuing a payment. This depends on the `difference_due` of the swap. If `difference_due` is negative, the amount is refunded. - * If `difference_due` is positive, the amount is captured." - * x-authenticated: true - * externalDocs: - * description: Handling a swap's payment - * url: https://docs.medusajs.com/modules/orders/swaps#handling-swap-payment - * parameters: - * - (path) id=* {string} The ID of the order the swap is associated with. - * - (path) swap_id=* {string} The ID of the swap. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * x-codegen: - * method: processSwapPayment - * params: AdminPostOrdersOrderSwapsSwapProcessPaymentParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.processSwapPayment(orderId, swapId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminProcessSwapPayment } from "medusa-react" - * - * type Props = { - * orderId: string, - * swapId: string - * } - * - * const Swap = ({ - * orderId, - * swapId - * }: Props) => { - * const processPayment = useAdminProcessSwapPayment( - * orderId - * ) - * // ... - * - * const handleProcessPayment = () => { - * processPayment.mutate(swapId, { - * onSuccess: ({ order }) => { - * console.log(order.swaps) - * } - * }) - * } - * - * // ... - * } - * - * export default Swap - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/swaps/{swap_id}/process-payment' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, swap_id } = req.params - - const orderService: OrderService = req.scope.resolve("orderService") - const swapService: SwapService = req.scope.resolve("swapService") - const entityManager: EntityManager = req.scope.resolve("manager") - - await entityManager.transaction(async (manager) => { - await swapService.withTransaction(manager).processDifference(swap_id) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.json({ order: cleanResponseData(order, []) }) -} - -// eslint-disable-next-line max-len -export class AdminPostOrdersOrderSwapsSwapProcessPaymentParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/refund-payment.ts b/packages/medusa/src/api/routes/admin/orders/refund-payment.ts deleted file mode 100644 index 16a6d9ecdc..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/refund-payment.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { - IsBoolean, - IsInt, - IsNotEmpty, - IsOptional, - IsString, -} from "class-validator" - -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 - * operationId: "PostOrdersOrderRefunds" - * summary: "Create a Refund" - * description: "Refund an amount for an order. The amount must be less than or equal the `refundable_amount` of the order." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderRefundsReq" - * x-codegen: - * method: refundPayment - * params: AdminPostOrdersOrderRefundsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.refundPayment(orderId, { - * amount: 1000, - * reason: "Do not like it" - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminRefundPayment } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const refundPayment = useAdminRefundPayment( - * orderId - * ) - * // ... - * - * const handleRefund = ( - * amount: number, - * reason: string - * ) => { - * refundPayment.mutate({ - * amount, - * reason, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.refunds) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/adasda/refund' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "amount": 1000, - * "reason": "Do not like it" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = req.validatedBody - - const orderService: OrderService = req.scope.resolve("orderService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await orderService - .withTransaction(transactionManager) - .createRefund(id, validated.amount, validated.reason, validated.note, { - no_notification: validated.no_notification, - }) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.status(200).json({ order: cleanResponseData(order, []) }) -} - -/** - * @schema AdminPostOrdersOrderRefundsReq - * type: object - * description: "The details of the order refund." - * required: - * - amount - * - reason - * properties: - * amount: - * description: The amount to refund. It should be less than or equal the `refundable_amount` of the order. - * type: integer - * reason: - * description: The reason for the Refund. - * type: string - * note: - * description: A note with additional details about the Refund. - * type: string - * no_notification: - * description: >- - * If set to `true`, no notification will be sent to the customer related to this Refund. - * type: boolean - */ -export class AdminPostOrdersOrderRefundsReq { - @IsInt() - @IsNotEmpty() - amount: number - - @IsString() - @IsNotEmpty() - reason: string - - @IsString() - @IsOptional() - note?: string - - @IsBoolean() - @IsOptional() - no_notification?: boolean -} - -export class AdminPostOrdersOrderRefundsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/request-return.ts b/packages/medusa/src/api/routes/admin/orders/request-return.ts deleted file mode 100644 index 5677c7da3a..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/request-return.ts +++ /dev/null @@ -1,449 +0,0 @@ -import { Logger } from "@medusajs/types" -import { isDefined, MedusaError } from "@medusajs/utils" -import { Type } from "class-transformer" -import { - IsArray, - IsBoolean, - IsInt, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { EntityManager } from "typeorm" -import { Order, Return } from "../../../../models" -import { - EventBusService, - OrderService, - 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 - * operationId: "PostOrdersOrderReturns" - * summary: "Request a Return" - * description: "Request and create a Return for items in an order. If the return shipping method is specified, it will be automatically fulfilled." - * x-authenticated: true - * externalDocs: - * description: Return creation process - * url: https://docs.medusajs.com/modules/orders/returns#returns-process - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderReturnsReq" - * x-codegen: - * method: requestReturn - * params: AdminPostOrdersOrderReturnsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.requestReturn(orderId, { - * items: [ - * { - * item_id, - * quantity: 1 - * } - * ] - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminRequestReturn } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const requestReturn = useAdminRequestReturn( - * orderId - * ) - * // ... - * - * const handleRequestingReturn = ( - * itemId: string, - * quantity: number - * ) => { - * requestReturn.mutate({ - * items: [ - * { - * item_id: itemId, - * quantity - * } - * ] - * }, { - * onSuccess: ({ order }) => { - * console.log(order.returns) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/return' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "items": [ - * { - * "item_id": "{item_id}", - * "quantity": 1 - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const value = req.validatedBody as AdminPostOrdersOrderReturnsReq - - const idempotencyKeyService = req.scope.resolve("idempotencyKeyService") - const manager: EntityManager = req.scope.resolve("manager") - const logger: Logger = req.scope.resolve("logger") - - const headerKey = req.get("Idempotency-Key") || "" - - let idempotencyKey - try { - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .initializeRequest(headerKey, req.method, req.params, req.path) - }) - } catch (error) { - res.status(409).send("Failed to create idempotency key") - return - } - - res.setHeader("Access-Control-Expose-Headers", "Idempotency-Key") - res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key) - - try { - const orderService: OrderService = req.scope.resolve("orderService") - const inventoryServiceEnabled = - !!req.scope.resolve("inventoryService") && - !!req.scope.resolve("stockLocationService") - const returnService: ReturnService = req.scope.resolve("returnService") - const eventBus: EventBusService = req.scope.resolve("eventBusService") - - let inProgress = true - let err = false - - while (inProgress) { - switch (idempotencyKey.recovery_point) { - case "started": { - await manager - .transaction("SERIALIZABLE", async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .workStage(idempotencyKey.idempotency_key, async (manager) => { - const returnObj: ReturnObj = { - order_id: id, - idempotency_key: idempotencyKey.idempotency_key, - items: value.items, - } - if (isDefined(value.location_id) && inventoryServiceEnabled) { - returnObj.location_id = value.location_id - } - - if (value.return_shipping) { - returnObj.shipping_method = value.return_shipping - } - - if (isDefined(value.refund) && value.refund < 0) { - returnObj.refund_amount = 0 - } else { - if (value.refund && value.refund >= 0) { - returnObj.refund_amount = value.refund - } - } - - let evaluatedNoNotification = value.no_notification - - if (!isDefined(evaluatedNoNotification)) { - const order = await orderService - .withTransaction(manager) - .retrieve(id) - - evaluatedNoNotification = order.no_notification - } - - returnObj.no_notification = evaluatedNoNotification - - const createdReturn = await returnService - .withTransaction(manager) - .create(returnObj) - - if (value.return_shipping) { - await returnService - .withTransaction(manager) - .fulfill(createdReturn.id) - } - - await eventBus - .withTransaction(manager) - .emit(OrderService.Events.RETURN_REQUESTED, { - id, - return_id: createdReturn.id, - no_notification: evaluatedNoNotification, - }) - - return { - recovery_point: "return_requested", - } - }) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "return_requested": { - await manager - .transaction("SERIALIZABLE", async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .workStage(idempotencyKey.idempotency_key, async (manager) => { - let order: Order | Return - - /** - * If we are ready to receive immediately, we find the newly created return - * and register it as received. - */ - if (value.receive_now) { - const returns = await returnService - .withTransaction(manager) - .list({ - idempotency_key: idempotencyKey.idempotency_key, - }) - - if (!returns.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Return not found` - ) - } - - const returnOrder = returns[0] - - order = await returnService - .withTransaction(manager) - .receive(returnOrder.id, value.items, value.refund) - } - - order = await orderService - .withTransaction(manager) - .retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - return { - response_code: 200, - response_body: { - order: cleanResponseData(order, []), - }, - } - }) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "finished": { - inProgress = false - break - } - - default: - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .update(idempotencyKey.idempotency_key, { - recovery_point: "finished", - response_code: 500, - response_body: { message: "Unknown recovery point" }, - }) - }) - break - } - } - - if (err) { - throw err - } - - res.status(idempotencyKey.response_code).json(idempotencyKey.response_body) - } catch (err) { - logger.log(err) - throw err - } -} - -type ReturnObj = { - order_id: string - idempotency_key?: string - items?: OrdersReturnItem[] - shipping_method?: ReturnShipping - refund_amount?: number - no_notification?: boolean - location_id?: string -} - -/** - * The return's shipping method details. - */ -class ReturnShipping { - /** - * The ID of the shipping option used for the return. - */ - @IsString() - @IsOptional() - option_id?: string - - /** - * The shipping method's price. - */ - @IsInt() - @IsOptional() - price?: number -} - -/** - * @schema AdminPostOrdersOrderReturnsReq - * type: object - * description: "The details of the requested return." - * required: - * - items - * properties: - * items: - * description: The line items that will be returned. - * type: array - * items: - * type: object - * required: - * - item_id - * - quantity - * properties: - * item_id: - * description: The ID of the Line Item. - * type: string - * reason_id: - * description: The ID of the Return Reason to use. - * type: string - * note: - * description: An optional note with information about the Return. - * type: string - * quantity: - * description: The quantity of the Line Item. - * type: integer - * return_shipping: - * description: The Shipping Method to be used to handle the return shipment. - * type: object - * properties: - * option_id: - * type: string - * description: The ID of the Shipping Option to create the Shipping Method from. - * price: - * type: integer - * description: The price to charge for the Shipping Method. - * note: - * description: An optional note with information about the Return. - * type: string - * receive_now: - * description: A flag to indicate if the Return should be registerd as received immediately. - * type: boolean - * default: false - * no_notification: - * description: >- - * If set to `true`, no notification will be sent to the customer related to this Return. - * type: boolean - * refund: - * description: The amount to refund. - * type: integer - * location_id: - * description: "The ID of the location used for the return." - * type: string - */ -export class AdminPostOrdersOrderReturnsReq { - @IsArray() - @ValidateNested({ each: true }) - @Type(() => OrdersReturnItem) - items: OrdersReturnItem[] - - @IsOptional() - @ValidateNested() - @Type(() => ReturnShipping) - return_shipping?: ReturnShipping - - @IsString() - @IsOptional() - note?: string - - @IsBoolean() - @IsOptional() - receive_now?: boolean = false - - @IsBoolean() - @IsOptional() - no_notification?: boolean - - @IsInt() - @IsOptional() - refund?: number - - @IsOptional() - @IsString() - location_id?: string -} - -export class AdminPostOrdersOrderReturnsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/update-claim.ts b/packages/medusa/src/api/routes/admin/orders/update-claim.ts deleted file mode 100644 index db1c7f2375..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/update-claim.ts +++ /dev/null @@ -1,321 +0,0 @@ -import { - IsArray, - IsBoolean, - IsInt, - IsNotEmpty, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { ClaimService, OrderService } from "../../../../services" - -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} - * operationId: "PostOrdersOrderClaimsClaim" - * summary: "Update a Claim" - * description: "Update a Claim's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order associated with the claim. - * - (path) claim_id=* {string} The ID of the Claim. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderClaimsClaimReq" - * x-codegen: - * method: updateClaim - * params: AdminPostOrdersOrderClaimsClaimParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.updateClaim(orderId, claimId, { - * no_notification: true - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateClaim } from "medusa-react" - * - * type Props = { - * orderId: string - * claimId: string - * } - * - * const Claim = ({ orderId, claimId }: Props) => { - * const updateClaim = useAdminUpdateClaim(orderId) - * // ... - * - * const handleUpdate = () => { - * updateClaim.mutate({ - * claim_id: claimId, - * no_notification: false - * }, { - * onSuccess: ({ order }) => { - * console.log(order.claims) - * } - * }) - * } - * - * // ... - * } - * - * export default Claim - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/{id}/claims/{claim_id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "no_notification": true - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, claim_id } = req.params - - const validated = await validator( - AdminPostOrdersOrderClaimsClaimReq, - req.body - ) - - const orderService: OrderService = req.scope.resolve("orderService") - const claimService: ClaimService = req.scope.resolve("claimService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await claimService - .withTransaction(transactionManager) - .update(claim_id, validated) - }) - - const data = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.json({ order: cleanResponseData(data, []) }) -} - -/** - * @schema AdminPostOrdersOrderClaimsClaimReq - * type: object - * properties: - * claim_items: - * description: The Claim Items that the Claim will consist of. - * type: array - * items: - * type: object - * required: - * - id - * - images - * - tags - * properties: - * id: - * description: The ID of the Claim Item. - * type: string - * item_id: - * description: The ID of the Line Item that will be claimed. - * type: string - * quantity: - * description: The number of items that will be returned - * type: integer - * note: - * description: Short text describing the Claim Item in further detail. - * type: string - * reason: - * description: The reason for the Claim - * type: string - * enum: - * - missing_item - * - wrong_item - * - production_failure - * - other - * tags: - * description: A list o tags to add to the Claim Item - * type: array - * items: - * type: object - * properties: - * id: - * type: string - * description: Tag ID - * value: - * type: string - * description: Tag value - * images: - * description: A list of image URL's that will be associated with the Claim - * type: array - * items: - * type: object - * properties: - * id: - * type: string - * description: Image ID - * url: - * type: string - * description: Image URL - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * shipping_methods: - * description: The Shipping Methods to send the additional Line Items with. - * type: array - * items: - * type: object - * properties: - * id: - * description: The ID of an existing Shipping Method - * type: string - * option_id: - * description: The ID of the Shipping Option to create a Shipping Method from - * type: string - * price: - * description: The price to charge for the Shipping Method - * type: integer - * data: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * no_notification: - * description: If set to true no notification will be send related to this Swap. - * type: boolean - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostOrdersOrderClaimsClaimReq { - @IsArray() - @IsOptional() - @Type(() => Item) - @ValidateNested({ each: true }) - claim_items?: Item[] - - @IsArray() - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => ShippingMethod) - shipping_methods?: ShippingMethod[] - - @IsBoolean() - @IsOptional() - no_notification?: boolean - - @IsObject() - @IsOptional() - metadata?: Record -} - -class ShippingMethod { - @IsString() - @IsOptional() - id?: string - - @IsString() - @IsOptional() - option_id?: string - - @IsInt() - @IsOptional() - price?: number - - @IsObject() - @IsOptional() - data?: Record -} - -class Item { - @IsString() - @IsNotEmpty() - id: string - - @IsString() - @IsOptional() - note?: string - - @IsString() - @IsOptional() - reason?: string - - @IsArray() - @ValidateNested({ each: true }) - @Type(() => Image) - images: Image[] - - @IsArray() - @ValidateNested({ each: true }) - @Type(() => Tag) - tags: Tag[] - - @IsObject() - @IsOptional() - metadata?: Record -} - -class Image { - @IsString() - @IsOptional() - id?: string - - @IsString() - @IsOptional() - url?: string -} - -class Tag { - @IsString() - @IsOptional() - id?: string - - @IsString() - @IsOptional() - value?: string -} - -export class AdminPostOrdersOrderClaimsClaimParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/update-order.ts b/packages/medusa/src/api/routes/admin/orders/update-order.ts deleted file mode 100644 index 4dff85f229..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/update-order.ts +++ /dev/null @@ -1,309 +0,0 @@ -import { - IsArray, - IsBoolean, - IsEmail, - IsInt, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" - -import { Type } from "class-transformer" -import { EntityManager } from "typeorm" -import { OrderService } from "../../../../services" -import { AddressPayload, FindParams } from "../../../../types/common" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [post] /admin/orders/{id} - * operationId: "PostOrdersOrder" - * summary: "Update an Order" - * description: "Update and order's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - (query) fields {string} Comma-separated fields that should be included in the returned order. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostOrdersOrderReq" - * x-codegen: - * method: update - * params: AdminPostOrdersOrderParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.orders.update(orderId, { - * email: "user@example.com" - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateOrder } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const updateOrder = useAdminUpdateOrder( - * orderId - * ) - * - * const handleUpdate = ( - * email: string - * ) => { - * updateOrder.mutate({ - * email, - * }, { - * onSuccess: ({ order }) => { - * console.log(order.email) - * } - * }) - * } - * - * // ... - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/orders/adasda' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const { id } = req.params - - const orderService: OrderService = req.scope.resolve("orderService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await orderService - .withTransaction(transactionManager) - .update(id, req.validatedBody) - }) - - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { - includes: req.includes, - }) - - res.status(200).json({ order: cleanResponseData(order, []) }) -} - -/** - * The attributes to update in the order's payment method. - */ -class PaymentMethod { - /** - * The ID of the payment provider used in the order. - */ - @IsString() - @IsOptional() - provider_id?: string - - /** - * The data to attach to the payment. - */ - @IsObject() - @IsOptional() - data?: Record -} - -/** - * The attributes to update in the order's shipping method. - */ -class ShippingMethod { - /** - * The ID of the shipping provider used in the order. - */ - @IsString() - @IsOptional() - provider_id?: string - - /** - * The ID of the shipping profile used in the order. - */ - @IsString() - @IsOptional() - profile_id?: string - - /** - * The price of the shipping method. - */ - @IsInt() - @IsOptional() - price?: number - - /** - * The data to attach to the shipping method. - */ - @IsObject() - @IsOptional() - data?: Record - - /** - * The line items associated with this shipping methods. - */ - @IsArray() - @IsOptional() - items?: Record[] -} - -/** - * @schema AdminPostOrdersOrderReq - * type: object - * description: "The details to update of the order." - * properties: - * email: - * description: The email associated with the order - * type: string - * billing_address: - * description: The order's billing address - * $ref: "#/components/schemas/AddressPayload" - * shipping_address: - * description: The order's shipping address - * $ref: "#/components/schemas/AddressPayload" - * items: - * description: The line items of the order - * type: array - * items: - * $ref: "#/components/schemas/LineItem" - * region: - * description: ID of the region that the order is associated with. - * type: string - * discounts: - * description: The discounts applied to the order - * type: array - * items: - * $ref: "#/components/schemas/Discount" - * customer_id: - * description: The ID of the customer associated with the order. - * type: string - * payment_method: - * description: The payment method chosen for the order. - * type: object - * properties: - * provider_id: - * type: string - * description: The ID of the payment provider. - * data: - * description: Any data relevant for the given payment method. - * type: object - * shipping_method: - * description: The Shipping Method used for shipping the order. - * type: object - * properties: - * provider_id: - * type: string - * description: The ID of the shipping provider. - * profile_id: - * type: string - * description: The ID of the shipping profile. - * price: - * type: integer - * description: The price of the shipping. - * data: - * type: object - * description: Any data relevant to the specific shipping method. - * items: - * type: array - * items: - * $ref: "#/components/schemas/LineItem" - * description: Items to ship - * no_notification: - * description: >- - * If set to `true`, no notification will be sent to the customer related to this order. - * type: boolean - */ -export class AdminPostOrdersOrderReq { - @IsEmail() - @IsOptional() - email?: string - - @IsOptional() - @ValidateNested() - @Type(() => AddressPayload) - billing_address?: AddressPayload - - @IsOptional() - @ValidateNested() - @Type(() => AddressPayload) - shipping_address?: AddressPayload - - @IsArray() - @IsOptional() - items?: Record[] - - @IsString() - @IsOptional() - region?: string - - @IsArray() - @IsOptional() - discounts?: Record[] - - @IsString() - @IsOptional() - customer_id?: string - - @IsOptional() - @ValidateNested() - @Type(() => PaymentMethod) - payment_method?: PaymentMethod - - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => ShippingMethod) - shipping_method?: ShippingMethod[] - - @IsBoolean() - @IsOptional() - no_notification?: boolean -} - -/** - * Parameters used to configure the retrieved order. - */ -export class AdminPostOrdersOrderParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/payment-collections/delete-payment-collection.ts b/packages/medusa/src/api/routes/admin/payment-collections/delete-payment-collection.ts deleted file mode 100644 index 230e2ebed1..0000000000 --- a/packages/medusa/src/api/routes/admin/payment-collections/delete-payment-collection.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { PaymentCollectionService } from "../../../../services" - -/** - * @oas [delete] /admin/payment-collections/{id} - * operationId: "DeletePaymentCollectionsPaymentCollection" - * summary: "Delete a Payment Collection" - * description: "Delete a Payment Collection. Only payment collections with the statuses `canceled` or `not_paid` can be deleted." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Payment Collection. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.paymentCollections.delete(paymentCollectionId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeletePaymentCollection } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ paymentCollectionId }: Props) => { - * const deleteCollection = useAdminDeletePaymentCollection( - * paymentCollectionId - * ) - * // ... - * - * const handleDelete = () => { - * deleteCollection.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/payment-collections/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payment Collections - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPaymentCollectionDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - */ -export default async (req, res) => { - const { id } = req.params - - const paymentCollectionService: PaymentCollectionService = req.scope.resolve( - "paymentCollectionService" - ) - - await paymentCollectionService.delete(id) - - res.status(200).json({ id, deleted: true, object: "payment_collection" }) -} diff --git a/packages/medusa/src/api/routes/admin/payment-collections/get-payment-collection.ts b/packages/medusa/src/api/routes/admin/payment-collections/get-payment-collection.ts deleted file mode 100644 index 71406429b5..0000000000 --- a/packages/medusa/src/api/routes/admin/payment-collections/get-payment-collection.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { PaymentCollectionService } from "../../../../services" -import { FindParams } from "../../../../types/common" - -/** - * @oas [get] /admin/payment-collections/{id} - * operationId: "GetPaymentCollectionsPaymentCollection" - * summary: "Get a Payment Collection" - * description: "Retrieve a Payment Collection's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Payment Collection. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned payment collection. - * - (query) fields {string} Comma-separated fields that should be included in the returned payment collection. - * x-codegen: - * method: retrieve - * queryParams: AdminGetPaymentCollectionsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.paymentCollections.retrieve(paymentCollectionId) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminPaymentCollection } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ paymentCollectionId }: Props) => { - * const { - * payment_collection, - * isLoading, - * } = useAdminPaymentCollection(paymentCollectionId) - * - * return ( - *
- * {isLoading && Loading...} - * {payment_collection && ( - * {payment_collection.status} - * )} - * - *
- * ) - * } - * - * export default PaymentCollection - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/payment-collections/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payment Collections - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPaymentCollectionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const retrieveConfig = req.retrieveConfig - - const paymentCollectionService: PaymentCollectionService = req.scope.resolve( - "paymentCollectionService" - ) - - const paymentCollection = await paymentCollectionService.retrieve( - id, - retrieveConfig - ) - - res.status(200).json({ payment_collection: paymentCollection }) -} - -export class AdminGetPaymentCollectionsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/payment-collections/index.ts b/packages/medusa/src/api/routes/admin/payment-collections/index.ts deleted file mode 100644 index 84380a5975..0000000000 --- a/packages/medusa/src/api/routes/admin/payment-collections/index.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { Router } from "express" -import "reflect-metadata" -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" - -import { PaymentCollection } from "../../../../models" -import { AdminGetPaymentCollectionsParams } from "./get-payment-collection" -import { AdminUpdatePaymentCollectionsReq } from "./update-payment-collection" - -const route = Router() - -export default (app, container) => { - app.use("/payment-collections", route) - - route.get( - "/:id", - transformQuery(AdminGetPaymentCollectionsParams, { - defaultFields: defaultPaymentCollectionFields, - defaultRelations: defaulPaymentCollectionRelations, - isList: false, - }), - middlewares.wrap(require("./get-payment-collection").default) - ) - - route.post( - "/:id", - transformBody(AdminUpdatePaymentCollectionsReq), - middlewares.wrap(require("./update-payment-collection").default) - ) - - route.post( - "/:id/authorize", - middlewares.wrap(require("./mark-authorized-payment-collection").default) - ) - - route.delete( - "/:id", - middlewares.wrap(require("./delete-payment-collection").default) - ) - - return app -} - -export const defaultPaymentCollectionFields = [ - "id", - "type", - "status", - "description", - "amount", - "authorized_amount", - "region", - "currency_code", - "currency", - "metadata", -] - -export const defaulPaymentCollectionRelations = [ - "region", - "payment_sessions", - "payments", -] - -/** - * @schema AdminPaymentCollectionsRes - * type: object - * description: "The payment collection's details." - * x-expanded-relations: - * field: payment_collection - * relations: - * - payment_sessions - * - payments - * - region - * eager: - * - region.fulfillment_providers - * - region.payment_providers - * required: - * - payment_collection - * properties: - * payment_collection: - * description: Payment Collection details. - * $ref: "#/components/schemas/PaymentCollection" - */ -export type AdminPaymentCollectionsRes = { - payment_collection: PaymentCollection -} - -/** - * @schema AdminPaymentCollectionDeleteRes - * type: object - * description: "The details of deleting a payment collection." - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Payment Collection. - * object: - * type: string - * description: The type of the object that was deleted. - * default: payment_collection - * deleted: - * type: boolean - * description: Whether or not the Payment Collection was deleted. - * default: true - */ -export type AdminPaymentCollectionDeleteRes = { - id: string - object: "payment_collection" - deleted: boolean -} - -export * from "./get-payment-collection" -export * from "./update-payment-collection" diff --git a/packages/medusa/src/api/routes/admin/payment-collections/mark-authorized-payment-collection.ts b/packages/medusa/src/api/routes/admin/payment-collections/mark-authorized-payment-collection.ts deleted file mode 100644 index 1573774d01..0000000000 --- a/packages/medusa/src/api/routes/admin/payment-collections/mark-authorized-payment-collection.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { EntityManager } from "typeorm" -import { PaymentCollectionService } from "../../../../services" - -/** - * @oas [post] /admin/payment-collections/{id}/authorize - * operationId: "PostPaymentCollectionsPaymentCollectionAuthorize" - * summary: "Mark Authorized" - * description: "Set the status of a Payment Collection as `authorized`. This will also change the `authorized_amount` of the payment collection." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Payment Collection. - * x-codegen: - * method: markAsAuthorized - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.paymentCollections.markAsAuthorized(paymentCollectionId) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminMarkPaymentCollectionAsAuthorized } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ paymentCollectionId }: Props) => { - * const markAsAuthorized = useAdminMarkPaymentCollectionAsAuthorized( - * paymentCollectionId - * ) - * // ... - * - * const handleAuthorization = () => { - * markAsAuthorized.mutate(void 0, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.status) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/payment-collections/{id}/authorize' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payment Collections - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPaymentCollectionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const paymentCollectionService: PaymentCollectionService = req.scope.resolve( - "paymentCollectionService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const paymentCollection = await manager.transaction( - async (transactionManager) => { - return await paymentCollectionService - .withTransaction(transactionManager) - .markAsAuthorized(id) - } - ) - - res.status(200).json({ payment_collection: paymentCollection }) -} diff --git a/packages/medusa/src/api/routes/admin/payment-collections/update-payment-collection.ts b/packages/medusa/src/api/routes/admin/payment-collections/update-payment-collection.ts deleted file mode 100644 index 064d5a6d04..0000000000 --- a/packages/medusa/src/api/routes/admin/payment-collections/update-payment-collection.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { IsObject, IsOptional, IsString } from "class-validator" - -import { EntityManager } from "typeorm" -import { PaymentCollectionService } from "../../../../services" - -/** - * @oas [post] /admin/payment-collections/{id} - * operationId: "PostPaymentCollectionsPaymentCollection" - * summary: "Update Payment Collection" - * description: "Update a Payment Collection's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Payment Collection. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminUpdatePaymentCollectionsReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.paymentCollections.update(paymentCollectionId, { - * description - * }) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdatePaymentCollection } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ paymentCollectionId }: Props) => { - * const updateCollection = useAdminUpdatePaymentCollection( - * paymentCollectionId - * ) - * // ... - * - * const handleUpdate = ( - * description: string - * ) => { - * updateCollection.mutate({ - * description - * }, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.description) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/payment-collections/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "description": "Description of payment collection" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payment Collections - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPaymentCollectionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const data = req.validatedBody as AdminUpdatePaymentCollectionsReq - - const paymentCollectionService: PaymentCollectionService = req.scope.resolve( - "paymentCollectionService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const paymentCollection = await manager.transaction( - async (transactionManager) => { - return await paymentCollectionService - .withTransaction(transactionManager) - .update(id, data) - } - ) - - res.status(200).json({ payment_collection: paymentCollection }) -} - -/** - * @schema AdminUpdatePaymentCollectionsReq - * type: object - * description: "The details to update of the payment collection." - * properties: - * description: - * description: A description to create or update the payment collection. - * type: string - * metadata: - * description: A set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminUpdatePaymentCollectionsReq { - @IsString() - @IsOptional() - description?: string - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/payments/capture-payment.ts b/packages/medusa/src/api/routes/admin/payments/capture-payment.ts deleted file mode 100644 index 1af6f95b3d..0000000000 --- a/packages/medusa/src/api/routes/admin/payments/capture-payment.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { PaymentService } from "../../../../services" - -/** - * @oas [post] /admin/payments/{id}/capture - * operationId: "PostPaymentsPaymentCapture" - * summary: "Capture a Payment" - * description: "Capture a Payment." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Payment. - * x-codegen: - * method: capturePayment - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.payments.capturePayment(paymentId) - * .then(({ payment }) => { - * console.log(payment.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminPaymentsCapturePayment } from "medusa-react" - * - * type Props = { - * paymentId: string - * } - * - * const Payment = ({ paymentId }: Props) => { - * const capture = useAdminPaymentsCapturePayment( - * paymentId - * ) - * // ... - * - * const handleCapture = () => { - * capture.mutate(void 0, { - * onSuccess: ({ payment }) => { - * console.log(payment.amount) - * } - * }) - * } - * - * // ... - * } - * - * export default Payment - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/payments/{id}/capture' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payments - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPaymentRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const paymentService: PaymentService = req.scope.resolve("paymentService") - - const payment = await paymentService.capture(id) - - res.status(200).json({ payment }) -} diff --git a/packages/medusa/src/api/routes/admin/payments/get-payment.ts b/packages/medusa/src/api/routes/admin/payments/get-payment.ts deleted file mode 100644 index e5418db838..0000000000 --- a/packages/medusa/src/api/routes/admin/payments/get-payment.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { PaymentService } from "../../../../services" -import { FindParams } from "../../../../types/common" - -/** - * @oas [get] /admin/payments/{id} - * operationId: "GetPaymentsPayment" - * summary: "Get Payment details" - * description: "Retrieve a Payment's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Payment. - * x-codegen: - * method: retrieve - * queryParams: GetPaymentsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.payments.retrieve(paymentId) - * .then(({ payment }) => { - * console.log(payment.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminPayment } from "medusa-react" - * - * type Props = { - * paymentId: string - * } - * - * const Payment = ({ paymentId }: Props) => { - * const { - * payment, - * isLoading, - * } = useAdminPayment(paymentId) - * - * return ( - *
- * {isLoading && Loading...} - * {payment && {payment.amount}} - * - *
- * ) - * } - * - * export default Payment - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/payments/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payments - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPaymentRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const retrieveConfig = req.retrieveConfig - - const paymentService: PaymentService = req.scope.resolve("paymentService") - - const payment = await paymentService.retrieve(id, retrieveConfig) - - res.status(200).json({ payment }) -} - -export class GetPaymentsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/payments/index.ts b/packages/medusa/src/api/routes/admin/payments/index.ts deleted file mode 100644 index b1e168ca89..0000000000 --- a/packages/medusa/src/api/routes/admin/payments/index.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { Router } from "express" -import "reflect-metadata" -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" - -import { Payment, Refund } from "../../../../models" -import { GetPaymentsParams } from "./get-payment" -import { AdminPostPaymentRefundsReq } from "./refund-payment" - -const route = Router() - -export default (app, container) => { - app.use("/payments", route) - - route.get( - "/:id", - transformQuery(GetPaymentsParams, { - defaultFields: defaultPaymentFields, - isList: false, - }), - middlewares.wrap(require("./get-payment").default) - ) - - route.post( - "/:id/capture", - middlewares.wrap(require("./capture-payment").default) - ) - - route.post( - "/:id/refund", - transformBody(AdminPostPaymentRefundsReq), - middlewares.wrap(require("./refund-payment").default) - ) - - return app -} - -export const defaultPaymentFields = [ - "id", - "swap_id", - "cart_id", - "order_id", - "amount", - "currency_code", - "amount_refunded", - "provider_id", - "data", - "captured_at", - "canceled_at", - "metadata", -] - -/** - * @schema AdminPaymentRes - * type: object - * description: "The payment's details." - * required: - * - payment - * properties: - * payment: - * description: "Payment details" - * $ref: "#/components/schemas/Payment" - */ -export type AdminPaymentRes = { - payment: Payment -} - -/** - * @schema AdminRefundRes - * type: object - * description: "The refund's details." - * required: - * - refund - * properties: - * refund: - * description: "Refund details." - * $ref: "#/components/schemas/Refund" - */ -export type AdminRefundRes = { - refund: Refund -} - -export * from "./get-payment" -export * from "./refund-payment" diff --git a/packages/medusa/src/api/routes/admin/payments/refund-payment.ts b/packages/medusa/src/api/routes/admin/payments/refund-payment.ts deleted file mode 100644 index d8c451021d..0000000000 --- a/packages/medusa/src/api/routes/admin/payments/refund-payment.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { - IsEnum, - IsInt, - IsNotEmpty, - IsOptional, - IsString, -} from "class-validator" -import { RefundReason } from "../../../../models" - -import { PaymentService } from "../../../../services" - -/** - * @oas [post] /admin/payments/{id}/refund - * operationId: "PostPaymentsPaymentRefunds" - * summary: "Refund Payment" - * description: "Refund a payment. The payment must be captured first." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Payment. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostPaymentRefundsReq" - * x-codegen: - * method: refundPayment - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.payments.refundPayment(paymentId, { - * amount: 1000, - * reason: "return", - * note: "Do not like it", - * }) - * .then(({ payment }) => { - * console.log(payment.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { RefundReason } from "@medusajs/medusa" - * import { useAdminPaymentsRefundPayment } from "medusa-react" - * - * type Props = { - * paymentId: string - * } - * - * const Payment = ({ paymentId }: Props) => { - * const refund = useAdminPaymentsRefundPayment( - * paymentId - * ) - * // ... - * - * const handleRefund = ( - * amount: number, - * reason: RefundReason, - * note: string - * ) => { - * refund.mutate({ - * amount, - * reason, - * note - * }, { - * onSuccess: ({ refund }) => { - * console.log(refund.amount) - * } - * }) - * } - * - * // ... - * } - * - * export default Payment - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/payments/pay_123/refund' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "amount": 1000, - * "reason": "return", - * "note": "Do not like it" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payments - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminRefundRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const data = req.validatedBody as AdminPostPaymentRefundsReq - - const paymentService: PaymentService = req.scope.resolve("paymentService") - - const refund = await paymentService.refund( - id, - data.amount, - data.reason, - data.note - ) - - res.status(200).json({ refund }) -} - -/** - * @schema AdminPostPaymentRefundsReq - * type: object - * description: "The details of the refund to create." - * required: - * - amount - * - reason - * properties: - * amount: - * description: The amount to refund. - * type: integer - * reason: - * description: The reason for the Refund. - * type: string - * note: - * description: A note with additional details about the Refund. - * type: string - */ -export class AdminPostPaymentRefundsReq { - @IsInt() - @IsNotEmpty() - amount: number - - @IsEnum(RefundReason) - @IsNotEmpty() - reason: RefundReason - - @IsString() - @IsOptional() - note?: string -} diff --git a/packages/medusa/src/api/routes/admin/price-lists/__tests__/add-prices-batch.ts b/packages/medusa/src/api/routes/admin/price-lists/__tests__/add-prices-batch.ts deleted file mode 100644 index a24d133b56..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/__tests__/add-prices-batch.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { PriceListServiceMock } from "../../../../../services/__mocks__/price-list" - -describe("POST /price-lists/:id/prices/batch", () => { - describe("successfully adds several new prices to a price list", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/price-lists/pl_1234/prices/batch`, - { - payload: { - prices: [ - { - currency_code: "usd", - amount: 500, - min_quantity: 10, - max_quantity: 20, - variant_id: "variant_12", - }, - { - currency_code: "usd", - amount: 430, - min_quantity: 21, - max_quantity: 40, - variant_id: "variant_12", - }, - ], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls PriceListService addPrices", () => { - expect(PriceListServiceMock.addPrices).toHaveBeenCalledTimes(1) - expect(PriceListServiceMock.addPrices).toHaveBeenCalledWith( - "pl_1234", - [ - { - currency_code: "usd", - amount: 500, - min_quantity: 10, - max_quantity: 20, - variant_id: "variant_12", - }, - { - currency_code: "usd", - amount: 430, - min_quantity: 21, - max_quantity: 40, - variant_id: "variant_12", - }, - ], - undefined - ) - }) - }) - - describe("fails if no prices were provided", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/price-lists/pl_1234/prices/batch`, - { - payload: {}, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns descriptive error that name is missing", () => { - expect(subject.body.type).toEqual("invalid_data") - expect(subject.body.message).toEqual("prices must be an array") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/price-lists/__tests__/create-price-list.ts b/packages/medusa/src/api/routes/admin/price-lists/__tests__/create-price-list.ts deleted file mode 100644 index 276d7e2064..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/__tests__/create-price-list.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { PriceListServiceMock } from "../../../../../services/__mocks__/price-list" -import { request } from "../../../../../helpers/test-request" - -jest.setTimeout(10000) -describe("POST /price-lists", () => { - describe("successfully creates a price list", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/admin/price-lists`, { - payload: { - name: "My Price List", - description: "testing", - ends_at: "2022-03-14T08:28:38.551Z", - starts_at: "2022-03-14T08:28:38.551Z", - customer_groups: [ - { - id: "gc_123", - }, - ], - type: "sale", - prices: [ - { - currency_code: "usd", - amount: 500, - min_quantity: 10, - max_quantity: 20, - variant_id: "variant_12", - }, - { - currency_code: "usd", - amount: 430, - min_quantity: 21, - max_quantity: 40, - variant_id: "variant_12", - }, - ], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls PriceListService addPrices", () => { - expect(PriceListServiceMock.create).toHaveBeenCalledTimes(1) - expect(PriceListServiceMock.create).toHaveBeenCalledWith({ - name: "My Price List", - description: "testing", - ends_at: new Date("2022-03-14T08:28:38.551Z"), - starts_at: new Date("2022-03-14T08:28:38.551Z"), - customer_groups: [ - { - id: "gc_123", - }, - ], - type: "sale", - prices: [ - { - currency_code: "usd", - amount: 500, - min_quantity: 10, - max_quantity: 20, - variant_id: "variant_12", - }, - { - currency_code: "usd", - amount: 430, - min_quantity: 21, - max_quantity: 40, - variant_id: "variant_12", - }, - ], - }) - }) - }) - - describe("fails if required fields are missing", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/admin/price-lists`, { - payload: { - description: "bad payload", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns descriptive error that several fields are missing", () => { - expect(subject.body.type).toEqual("invalid_data") - expect(subject.body.message).toEqual( - "name must be a string, type must be one of the following values: sale, override, prices must be an array" - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/price-lists/__tests__/delete-price-list.ts b/packages/medusa/src/api/routes/admin/price-lists/__tests__/delete-price-list.ts deleted file mode 100644 index f78ed99c48..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/__tests__/delete-price-list.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { PriceListServiceMock } from "../../../../../services/__mocks__/price-list" - -describe("POST /price-lists/:id/prices/batch", () => { - describe("successfully adds several new prices to a price list", () => { - let subject - - beforeAll(async () => { - subject = await request("DELETE", `/admin/price-lists/pl_1234`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls PriceListService addPrices", () => { - expect(PriceListServiceMock.delete).toHaveBeenCalledTimes(1) - expect(PriceListServiceMock.delete).toHaveBeenCalledWith("pl_1234") - - expect(subject.body).toEqual({ - id: "pl_1234", - object: "price-list", - deleted: true, - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/price-lists/__tests__/delete-prices-batch.ts b/packages/medusa/src/api/routes/admin/price-lists/__tests__/delete-prices-batch.ts deleted file mode 100644 index da8c330bbd..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/__tests__/delete-prices-batch.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { PriceListServiceMock } from "../../../../../services/__mocks__/price-list" - -describe("DELETE /price-lists/:id/prices/batch", () => { - describe("successfully adds several new prices to a price list", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/price-lists/pl_1234/prices/batch`, - { - payload: { - price_ids: ["price_1234", "price_1235", "price_1236", "price_1237"], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls PriceListService addPrices", () => { - expect(PriceListServiceMock.deletePrices).toHaveBeenCalledTimes(1) - expect(PriceListServiceMock.deletePrices).toHaveBeenCalledWith( - "pl_1234", - ["price_1234", "price_1235", "price_1236", "price_1237"] - ) - }) - }) - - describe("fails if no prices were provided", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/price-lists/pl_1234/prices/batch`, - { - payload: {}, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns descriptive error that price_ids is missing", () => { - expect(subject.body.type).toEqual("invalid_data") - expect(subject.body.message).toEqual( - "each value in price_ids must be a string, price_ids should not be empty" - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/price-lists/__tests__/get-price-list.ts b/packages/medusa/src/api/routes/admin/price-lists/__tests__/get-price-list.ts deleted file mode 100644 index 44cd274120..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/__tests__/get-price-list.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { defaultAdminPriceListFields, defaultAdminPriceListRelations } from ".." -import { request } from "../../../../../helpers/test-request" -import { PriceListServiceMock } from "../../../../../services/__mocks__/price-list" - -describe("GET /price-lists/:id", () => { - describe("", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/admin/price-lists/pl_1234`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls PriceListService retrieve", () => { - expect(PriceListServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(PriceListServiceMock.retrieve).toHaveBeenCalledWith("pl_1234", { - relations: defaultAdminPriceListRelations, - select: defaultAdminPriceListFields, - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/price-lists/__tests__/list-price-lists.ts b/packages/medusa/src/api/routes/admin/price-lists/__tests__/list-price-lists.ts deleted file mode 100644 index 2cffd14636..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/__tests__/list-price-lists.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { PriceListServiceMock } from "../../../../../services/__mocks__/price-list" - -describe("GET /price-lists", () => { - describe("successfully lists price lists", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/admin/price-lists`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls PriceListService listAndCount", () => { - expect(PriceListServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(PriceListServiceMock.listAndCount).toHaveBeenCalledWith( - { - created_at: undefined, - deleted_at: undefined, - description: undefined, - id: undefined, - name: undefined, - q: undefined, - status: undefined, - type: undefined, - updated_at: undefined, - }, - { order: { created_at: "DESC" }, relations: [], skip: 0, take: 10 } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/price-lists/__tests__/update-price-list.ts b/packages/medusa/src/api/routes/admin/price-lists/__tests__/update-price-list.ts deleted file mode 100644 index 3d43fd4211..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/__tests__/update-price-list.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { PriceListServiceMock } from "../../../../../services/__mocks__/price-list" - -describe("POST /price-lists/:id", () => { - describe("successfully updates a price list", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/admin/price-lists/pl_1234`, { - payload: { - description: "new description", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls PriceListService update", () => { - expect(PriceListServiceMock.update).toHaveBeenCalledTimes(1) - expect(PriceListServiceMock.update).toHaveBeenCalledWith("pl_1234", { - description: "new description", - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/price-lists/add-prices-batch.ts b/packages/medusa/src/api/routes/admin/price-lists/add-prices-batch.ts deleted file mode 100644 index fe283d40e6..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/add-prices-batch.ts +++ /dev/null @@ -1,195 +0,0 @@ -import { Type } from "class-transformer" -import { IsArray, IsBoolean, IsOptional, ValidateNested } from "class-validator" -import { EntityManager } from "typeorm" -import { defaultAdminPriceListFields, defaultAdminPriceListRelations } from "." -import { PriceList } from "../../../.." -import PriceListService from "../../../../services/price-list" -import { AdminPriceListPricesUpdateReq } from "../../../../types/price-list" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/price-lists/{id}/prices/batch - * operationId: "PostPriceListsPriceListPricesBatch" - * summary: "Add or Update Prices" - * description: "Add or update a list of prices in a Price List." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Price List. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostPriceListPricesPricesReq" - * x-codegen: - * method: addPrices - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.addPrices(priceListId, { - * prices: [ - * { - * amount: 1000, - * variant_id, - * currency_code: "eur" - * } - * ] - * }) - * .then(({ price_list }) => { - * console.log(price_list.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreatePriceListPrices } from "medusa-react" - * - * type PriceData = { - * amount: number - * variant_id: string - * currency_code: string - * } - * - * type Props = { - * priceListId: string - * } - * - * const PriceList = ({ - * priceListId - * }: Props) => { - * const addPrices = useAdminCreatePriceListPrices(priceListId) - * // ... - * - * const handleAddPrices = (prices: PriceData[]) => { - * addPrices.mutate({ - * prices - * }, { - * onSuccess: ({ price_list }) => { - * console.log(price_list.prices) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceList - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/price-lists/{id}/prices/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "prices": [ - * { - * "amount": 100, - * "variant_id": "afasfa", - * "currency_code": "eur" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Price Lists - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPriceListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const manager: EntityManager = req.scope.resolve("manager") - const priceListService: PriceListService = - req.scope.resolve("priceListService") - - const validated = await validator(AdminPostPriceListPricesPricesReq, req.body) - - await manager.transaction(async (transactionManager) => { - await priceListService - .withTransaction(transactionManager) - .addPrices(id, validated.prices, validated.override) - }) - - const priceList = await priceListService.retrieve(id, { - select: defaultAdminPriceListFields as (keyof PriceList)[], - relations: defaultAdminPriceListRelations, - }) - - res.json({ price_list: priceList }) -} - -/** - * @schema AdminPostPriceListPricesPricesReq - * type: object - * description: "The details of the prices to add." - * properties: - * prices: - * description: The prices to update or add. - * type: array - * items: - * type: object - * required: - * - amount - * - variant_id - * properties: - * id: - * description: The ID of the price. - * type: string - * region_id: - * description: The ID of the Region for which the price is used. This is only required if `currecny_code` is not provided. - * type: string - * currency_code: - * description: The 3 character ISO currency code for which the price will be used. This is only required if `region_id` is not provided. - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * variant_id: - * description: The ID of the Variant for which the price is used. - * type: string - * amount: - * description: The amount to charge for the Product Variant. - * type: integer - * min_quantity: - * description: The minimum quantity for which the price will be used. - * type: integer - * max_quantity: - * description: The maximum quantity for which the price will be used. - * type: integer - * override: - * description: >- - * If set to `true`, the prices will replace all existing prices associated with the Price List. - * type: boolean - */ -export class AdminPostPriceListPricesPricesReq { - @IsArray() - @Type(() => AdminPriceListPricesUpdateReq) - @ValidateNested({ each: true }) - prices: AdminPriceListPricesUpdateReq[] - - @IsOptional() - @IsBoolean() - override?: boolean -} diff --git a/packages/medusa/src/api/routes/admin/price-lists/create-price-list.ts b/packages/medusa/src/api/routes/admin/price-lists/create-price-list.ts deleted file mode 100644 index 8ad0afbd3d..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/create-price-list.ts +++ /dev/null @@ -1,292 +0,0 @@ -import { PriceListStatus, PriceListType } from "@medusajs/utils" -import { Transform, Type } from "class-transformer" -import { - IsArray, - IsBoolean, - IsEnum, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { Request } from "express" -import { EntityManager } from "typeorm" -import { defaultAdminPriceListFields, defaultAdminPriceListRelations } from "." -import { featureFlagRouter } from "../../../../loaders/feature-flags" -import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" -import { PriceList } from "../../../../models" -import PriceListService from "../../../../services/price-list" -import { - AdminPriceListPricesCreateReq, - CreatePriceListInput, -} from "../../../../types/price-list" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" -import { transformOptionalDate } from "../../../../utils/validators/date-transform" - -/** - * @oas [post] /admin/price-lists - * operationId: "PostPriceListsPriceList" - * summary: "Create a Price List" - * description: "Create a Price List." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostPriceListsPriceListReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * import { PriceListType } from "@medusajs/medusa" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.create({ - * name: "New Price List", - * description: "A new price list", - * type: PriceListType.SALE, - * prices: [ - * { - * amount: 1000, - * variant_id, - * currency_code: "eur" - * } - * ] - * }) - * .then(({ price_list }) => { - * console.log(price_list.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * PriceListStatus, - * PriceListType, - * } from "@medusajs/medusa" - * import { useAdminCreatePriceList } from "medusa-react" - * - * type CreateData = { - * name: string - * description: string - * type: PriceListType - * status: PriceListStatus - * prices: { - * amount: number - * variant_id: string - * currency_code: string - * max_quantity: number - * }[] - * } - * - * const CreatePriceList = () => { - * const createPriceList = useAdminCreatePriceList() - * // ... - * - * const handleCreate = ( - * data: CreateData - * ) => { - * createPriceList.mutate(data, { - * onSuccess: ({ price_list }) => { - * console.log(price_list.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreatePriceList - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/price-lists' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "New Price List", - * "description": "A new price list", - * "type": "sale", - * "prices": [ - * { - * "amount": 1000, - * "variant_id": "afafa", - * "currency_code": "eur" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Price Lists - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPriceListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res) => { - const priceListService: PriceListService = - req.scope.resolve("priceListService") - - const manager: EntityManager = req.scope.resolve("manager") - - let priceList = await manager.transaction(async (transactionManager) => { - return await priceListService - .withTransaction(transactionManager) - .create(req.validatedBody as CreatePriceListInput) - }) - - priceList = await priceListService.retrieve(priceList.id, { - select: defaultAdminPriceListFields as (keyof PriceList)[], - relations: defaultAdminPriceListRelations, - }) - - res.json({ price_list: priceList }) -} - -class CustomerGroup { - @IsString() - id: string -} - -/** - * @schema AdminPostPriceListsPriceListReq - * type: object - * description: "The details of the price list to create." - * required: - * - name - * - description - * - type - * - prices - * properties: - * name: - * description: "The name of the Price List." - * type: string - * description: - * description: "The description of the Price List." - * type: string - * starts_at: - * description: "The date with timezone that the Price List starts being valid." - * type: string - * format: date - * ends_at: - * description: "The date with timezone that the Price List ends being valid." - * type: string - * format: date - * type: - * description: The type of the Price List. - * type: string - * enum: - * - sale - * - override - * status: - * description: >- - * The status of the Price List. If the status is set to `draft`, the prices created in the price list will not be available of the customer. - * type: string - * enum: - * - active - * - draft - * prices: - * description: The prices of the Price List. - * type: array - * items: - * type: object - * required: - * - amount - * - variant_id - * properties: - * region_id: - * description: The ID of the Region for which the price is used. This is only required if `currecny_code` is not provided. - * type: string - * currency_code: - * description: The 3 character ISO currency code for which the price will be used. This is only required if `region_id` is not provided. - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * amount: - * description: The amount to charge for the Product Variant. - * type: integer - * variant_id: - * description: The ID of the Variant for which the price is used. - * type: string - * min_quantity: - * description: The minimum quantity for which the price will be used. - * type: integer - * max_quantity: - * description: The maximum quantity for which the price will be used. - * type: integer - * customer_groups: - * type: array - * description: An array of customer groups that the Price List applies to. - * items: - * type: object - * required: - * - id - * properties: - * id: - * description: The ID of a customer group - * type: string - * includes_tax: - * description: "Tax included in prices of price list" - * x-featureFlag: "tax_inclusive_pricing" - * type: boolean - */ -export class AdminPostPriceListsPriceListReq { - @IsString() - name: string - - @IsString() - description: string - - @IsOptional() - @Transform(transformOptionalDate) - starts_at?: Date - - @IsOptional() - @Transform(transformOptionalDate) - ends_at?: Date - - @IsOptional() - @IsEnum(PriceListStatus) - status?: PriceListStatus - - @IsEnum(PriceListType) - type: PriceListType - - @IsArray() - @Type(() => AdminPriceListPricesCreateReq) - @ValidateNested({ each: true }) - prices: AdminPriceListPricesCreateReq[] - - @IsOptional() - @IsArray() - @Type(() => CustomerGroup) - @ValidateNested({ each: true }) - customer_groups?: CustomerGroup[] - - @FeatureFlagDecorators(TaxInclusivePricingFeatureFlag.key, [ - IsOptional(), - IsBoolean(), - ]) - includes_tax?: boolean -} diff --git a/packages/medusa/src/api/routes/admin/price-lists/delete-price-list.ts b/packages/medusa/src/api/routes/admin/price-lists/delete-price-list.ts deleted file mode 100644 index 1455460886..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/delete-price-list.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { EntityManager } from "typeorm" -import PriceListService from "../../../../services/price-list" - -/** - * @oas [delete] /admin/price-lists/{id} - * operationId: "DeletePriceListsPriceList" - * summary: "Delete a Price List" - * description: "Delete a Price List and its associated prices." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Price List. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.delete(priceListId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeletePriceList } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceList = ({ - * priceListId - * }: Props) => { - * const deletePriceList = useAdminDeletePriceList(priceListId) - * // ... - * - * const handleDelete = () => { - * deletePriceList.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceList - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/price-lists/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Price Lists - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPriceListDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const manager: EntityManager = req.scope.resolve("manager") - - const priceListService: PriceListService = - req.scope.resolve("priceListService") - await manager.transaction(async (transactionManager) => { - await priceListService.withTransaction(transactionManager).delete(id) - }) - - res.json({ - id, - object: "price-list", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/price-lists/delete-prices-batch.ts b/packages/medusa/src/api/routes/admin/price-lists/delete-prices-batch.ts deleted file mode 100644 index bcb9ea3a02..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/delete-prices-batch.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { ArrayNotEmpty, IsString } from "class-validator" -import { EntityManager } from "typeorm" -import PriceListService from "../../../../services/price-list" -import { validator } from "../../../../utils/validator" - -/** - * @oas [delete] /admin/price-lists/{id}/prices/batch - * operationId: "DeletePriceListsPriceListPricesBatch" - * summary: "Delete Prices" - * description: "Delete a list of prices in a Price List" - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Price List - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeletePriceListPricesPricesReq" - * x-codegen: - * method: deletePrices - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.deletePrices(priceListId, { - * price_ids: [ - * price_id - * ] - * }) - * .then(({ ids, object, deleted }) => { - * console.log(ids.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeletePriceListPrices } from "medusa-react" - * - * const PriceList = ( - * priceListId: string - * ) => { - * const deletePrices = useAdminDeletePriceListPrices(priceListId) - * // ... - * - * const handleDeletePrices = (priceIds: string[]) => { - * deletePrices.mutate({ - * price_ids: priceIds - * }, { - * onSuccess: ({ ids, deleted, object }) => { - * console.log(ids) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceList - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/price-lists/{id}/prices/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "price_ids": [ - * "adasfa" - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Price Lists - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPriceListDeleteBatchRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const validated = await validator( - AdminDeletePriceListPricesPricesReq, - req.body - ) - - const manager: EntityManager = req.scope.resolve("manager") - const priceListService: PriceListService = - req.scope.resolve("priceListService") - - await manager.transaction(async (transactionManager) => { - await priceListService - .withTransaction(transactionManager) - .deletePrices(id, validated.price_ids) - }) - - res.json({ ids: validated.price_ids, object: "money-amount", deleted: true }) -} - -/** - * @schema AdminDeletePriceListPricesPricesReq - * type: object - * description: "The details of the prices to delete." - * properties: - * price_ids: - * description: The IDs of the prices to delete. - * type: array - * items: - * type: string - */ -export class AdminDeletePriceListPricesPricesReq { - @ArrayNotEmpty() - @IsString({ each: true }) - price_ids: string[] -} diff --git a/packages/medusa/src/api/routes/admin/price-lists/delete-product-prices.ts b/packages/medusa/src/api/routes/admin/price-lists/delete-product-prices.ts deleted file mode 100644 index fa90b05a7c..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/delete-product-prices.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { EntityManager } from "typeorm" -import PriceListService from "../../../../services/price-list" - -/** - * @oas [delete] /admin/price-lists/{id}/products/{product_id}/prices - * operationId: "DeletePriceListsPriceListProductsProductPrices" - * summary: "Delete a Product's Prices" - * description: "Delete all the prices related to a specific product in a price list." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Price List. - * - (path) product_id=* {string} The ID of the product from which the prices will be deleted. - * x-codegen: - * method: deleteProductPrices - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.deleteProductPrices(priceListId, productId) - * .then(({ ids, object, deleted }) => { - * console.log(ids.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminDeletePriceListProductPrices - * } from "medusa-react" - * - * type Props = { - * priceListId: string - * productId: string - * } - * - * const PriceListProduct = ({ - * priceListId, - * productId - * }: Props) => { - * const deleteProductPrices = useAdminDeletePriceListProductPrices( - * priceListId, - * productId - * ) - * // ... - * - * const handleDeleteProductPrices = () => { - * deleteProductPrices.mutate(void 0, { - * onSuccess: ({ ids, deleted, object }) => { - * console.log(ids) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceListProduct - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/price-lists/{id}/products/{product_id}/prices' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Price Lists - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPriceListDeleteProductPricesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, product_id } = req.params - const priceListService: PriceListService = - req.scope.resolve("priceListService") - - const manager: EntityManager = req.scope.resolve("manager") - let deletedPriceIds: string[] = [] - - const [deletedIds] = await manager.transaction(async (transactionManager) => { - return await priceListService - .withTransaction(transactionManager) - .deleteProductPrices(id, [product_id]) - }) - deletedPriceIds = deletedIds - - return res.json({ - ids: deletedPriceIds, - object: "money-amount", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/price-lists/delete-products-prices-batch.ts b/packages/medusa/src/api/routes/admin/price-lists/delete-products-prices-batch.ts deleted file mode 100644 index 4732855ca3..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/delete-products-prices-batch.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { ArrayNotEmpty, IsString } from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import PriceListService from "../../../../services/price-list" -import { validator } from "../../../../utils/validator" - -/** - * @oas [delete] /admin/price-lists/{id}/products/prices/batch - * operationId: "DeletePriceListsPriceListProductsPricesBatch" - * summary: "Delete Product Prices" - * description: "Delete all the prices associated with multiple products in a price list." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Price List - * x-codegen: - * method: deleteProductsPrices - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.deleteProductsPrices(priceListId, { - * product_ids: [ - * productId1, - * productId2, - * ] - * }) - * .then(({ ids, object, deleted }) => { - * console.log(ids.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeletePriceListProductsPrices } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceList = ({ - * priceListId - * }: Props) => { - * const deleteProductsPrices = useAdminDeletePriceListProductsPrices( - * priceListId - * ) - * // ... - * - * const handleDeleteProductsPrices = (productIds: string[]) => { - * deleteProductsPrices.mutate({ - * product_ids: productIds - * }, { - * onSuccess: ({ ids, deleted, object }) => { - * console.log(ids) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceList - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/price-lists/{id}/products/prices/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "product_ids": [ - * "prod_1", - * "prod_2" - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Price Lists - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPriceListDeleteProductPricesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const validated = await validator( - AdminDeletePriceListsPriceListProductsPricesBatchReq, - req.body - ) - - const priceListService: PriceListService = - req.scope.resolve("priceListService") - - const manager: EntityManager = req.scope.resolve("manager") - let deletedPriceIds: string[] = [] - - const [deletedIds] = await manager.transaction(async (transactionManager) => { - return await priceListService - .withTransaction(transactionManager) - .deleteProductPrices(id, validated.product_ids) - }) - - deletedPriceIds = deletedIds - - return res.json({ - ids: deletedPriceIds, - object: "money-amount", - deleted: true, - }) -} - -/** - * @schema AdminDeletePriceListsPriceListProductsPricesBatchReq - * type: object - * description: "The details of the products' prices to delete." - * properties: - * product_ids: - * description: The IDs of the products to delete their associated prices. - * type: array - * items: - * type: string - */ -export class AdminDeletePriceListsPriceListProductsPricesBatchReq { - @ArrayNotEmpty() - @IsString({ each: true }) - product_ids: string[] -} diff --git a/packages/medusa/src/api/routes/admin/price-lists/delete-variant-prices.ts b/packages/medusa/src/api/routes/admin/price-lists/delete-variant-prices.ts deleted file mode 100644 index 4e3b3be5da..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/delete-variant-prices.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { EntityManager } from "typeorm" -import PriceListService from "../../../../services/price-list" - -/** - * @oas [delete] /admin/price-lists/{id}/variants/{variant_id}/prices - * operationId: "DeletePriceListsPriceListVariantsVariantPrices" - * summary: "Delete a Variant's Prices" - * description: "Delete all the prices related to a specific variant in a price list." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Price List. - * - (path) variant_id=* {string} The ID of the variant. - * x-codegen: - * method: deleteVariantPrices - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.deleteVariantPrices(priceListId, variantId) - * .then(({ ids, object, deleted }) => { - * console.log(ids); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminDeletePriceListVariantPrices - * } from "medusa-react" - * - * type Props = { - * priceListId: string - * variantId: string - * } - * - * const PriceListVariant = ({ - * priceListId, - * variantId - * }: Props) => { - * const deleteVariantPrices = useAdminDeletePriceListVariantPrices( - * priceListId, - * variantId - * ) - * // ... - * - * const handleDeleteVariantPrices = () => { - * deleteVariantPrices.mutate(void 0, { - * onSuccess: ({ ids, deleted, object }) => { - * console.log(ids) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceListVariant - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/price-lists/{id}/variants/{variant_id}/prices' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Price Lists - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPriceListDeleteVariantPricesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, variant_id } = req.params - - const priceListService: PriceListService = - req.scope.resolve("priceListService") - const manager: EntityManager = req.scope.resolve("manager") - - const [deletedIds] = await manager.transaction(async (transactionManager) => { - return await priceListService - .withTransaction(transactionManager) - .deleteVariantPrices(id, [variant_id]) - }) - - return res.json({ - ids: deletedIds, - object: "money-amount", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/price-lists/get-price-list.ts b/packages/medusa/src/api/routes/admin/price-lists/get-price-list.ts deleted file mode 100644 index 8acc178bd4..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/get-price-list.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { defaultAdminPriceListFields, defaultAdminPriceListRelations } from "." -import { PriceList } from "../../../.." -import PriceListService from "../../../../services/price-list" - -/** - * @oas [get] /admin/price-lists/{id} - * operationId: "GetPriceListsPriceList" - * summary: "Get a Price List" - * description: "Retrieve a Price List's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Price List. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.retrieve(priceListId) - * .then(({ price_list }) => { - * console.log(price_list.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminPriceList } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceList = ({ - * priceListId - * }: Props) => { - * const { - * price_list, - * isLoading, - * } = useAdminPriceList(priceListId) - * - * return ( - *
- * {isLoading && Loading...} - * {price_list && {price_list.name}} - *
- * ) - * } - * - * export default PriceList - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/price-lists/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Price Lists - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPriceListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const priceListService: PriceListService = - req.scope.resolve("priceListService") - - const priceList = await priceListService.retrieve(id, { - select: defaultAdminPriceListFields as (keyof PriceList)[], - relations: defaultAdminPriceListRelations, - }) - - res.status(200).json({ price_list: priceList }) -} diff --git a/packages/medusa/src/api/routes/admin/price-lists/index.ts b/packages/medusa/src/api/routes/admin/price-lists/index.ts deleted file mode 100644 index f4ff52921a..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/index.ts +++ /dev/null @@ -1,305 +0,0 @@ -import "reflect-metadata" - -import { PriceList, Product } from "../../../.." -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" -import { - defaultAdminProductFields, - defaultAdminProductRelations, -} from "../products" - -import { FlagRouter } from "@medusajs/utils" -import { Router } from "express" -import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" -import { AdminPostPriceListsPriceListReq } from "./create-price-list" -import { AdminGetPriceListsPriceListProductsParams } from "./list-price-list-products" -import { AdminGetPriceListPaginationParams } from "./list-price-lists" - -const route = Router() - -export default (app, featureFlagRouter: FlagRouter) => { - app.use("/price-lists", route) - - if (featureFlagRouter.isFeatureEnabled(TaxInclusivePricingFeatureFlag.key)) { - defaultAdminPriceListFields.push("includes_tax") - } - - route.get("/:id", middlewares.wrap(require("./get-price-list").default)) - - route.get( - "/", - transformQuery(AdminGetPriceListPaginationParams, { isList: true }), - middlewares.wrap(require("./list-price-lists").default) - ) - - route.get( - "/:id/products", - transformQuery(AdminGetPriceListsPriceListProductsParams, { - defaultFields: defaultAdminProductFields, - defaultRelations: defaultAdminProductRelations.filter( - (r) => r !== "variants.prices" - ), - defaultLimit: 50, - isList: true, - }), - middlewares.wrap(require("./list-price-list-products").default) - ) - - route.delete( - "/:id/products/:product_id/prices", - middlewares.wrap(require("./delete-product-prices").default) - ) - - route.delete( - "/:id/products/prices/batch", - middlewares.wrap(require("./delete-products-prices-batch").default) - ) - - route.delete( - "/:id/variants/:variant_id/prices", - middlewares.wrap(require("./delete-variant-prices").default) - ) - - route.post( - "/", - transformBody(AdminPostPriceListsPriceListReq), - middlewares.wrap(require("./create-price-list").default) - ) - - route.post("/:id", middlewares.wrap(require("./update-price-list").default)) - - route.delete("/:id", middlewares.wrap(require("./delete-price-list").default)) - - route.delete( - "/:id/prices/batch", - middlewares.wrap(require("./delete-prices-batch").default) - ) - - route.post( - "/:id/prices/batch", - middlewares.wrap(require("./add-prices-batch").default) - ) - - return app -} - -export const defaultAdminPriceListFields = [ - "id", - "name", - "description", - "type", - "status", - "starts_at", - "ends_at", - "created_at", - "updated_at", - "deleted_at", -] - -export const defaultAdminPriceListRelations = [ - "prices", - "prices.variants", - "customer_groups", -] - -/** - * @schema AdminPriceListRes - * type: object - * description: "The price list's details." - * x-expanded-relations: - * field: price_list - * relations: - * - customer_groups - * - prices - * required: - * - price_list - * properties: - * price_list: - * description: "Price List details." - * $ref: "#/components/schemas/PriceList" - */ -export type AdminPriceListRes = { - price_list: PriceList -} - -/** - * @schema AdminPriceListDeleteBatchRes - * type: object - * description: "The details of deleting a price list." - * required: - * - ids - * - object - * - deleted - * properties: - * ids: - * type: array - * description: The IDs of the deleted prices. - * items: - * type: string - * description: The ID of a deleted price. - * object: - * type: string - * description: The type of the object that was deleted. A price is also named `money-amount`. - * default: money-amount - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminPriceListDeleteBatchRes = { - ids: string[] - deleted: boolean - object: string -} - -/** - * @schema AdminPriceListDeleteProductPricesRes - * type: object - * required: - * - ids - * - object - * - deleted - * properties: - * ids: - * type: array - * description: The IDs of the deleted prices. - * items: - * type: string - * object: - * type: string - * description: The type of the object that was deleted. A price is also named `money-amount`. - * default: money-amount - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminPriceListDeleteProductPricesRes = AdminPriceListDeleteBatchRes - -/** - * @schema AdminPriceListDeleteVariantPricesRes - * type: object - * required: - * - ids - * - object - * - deleted - * properties: - * ids: - * type: array - * description: The IDs of the deleted prices. - * items: - * type: string - * object: - * type: string - * description: The type of the object that was deleted. A price is also named `money-amount`. - * default: money-amount - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminPriceListDeleteVariantPricesRes = AdminPriceListDeleteBatchRes - -/** - * @schema AdminPriceListDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Price List. - * object: - * type: string - * description: The type of the object that was deleted. - * default: price-list - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminPriceListDeleteRes = DeleteResponse - -/** - * @schema AdminPriceListsListRes - * type: object - * description: "The list of price lists with pagination fields." - * required: - * - price_lists - * - count - * - offset - * - limit - * properties: - * price_lists: - * type: array - * description: "An array of price lists details." - * items: - * $ref: "#/components/schemas/PriceList" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of price lists skipped when retrieving the price lists. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminPriceListsListRes = PaginatedResponse & { - price_lists: PriceList[] -} - -/** - * @schema AdminPriceListsProductsListRes - * type: object - * description: "The list of products with pagination fields." - * x-expanded-relations: - * field: products - * relations: - * - categories - * - collection - * - images - * - options - * - tags - * - type - * - variants - * - variants.options - * required: - * - products - * - count - * - offset - * - limit - * properties: - * products: - * type: array - * description: "An array of products details." - * items: - * $ref: "#/components/schemas/Product" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of price lists skipped when retrieving the price lists. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminPriceListsProductsListRes = PaginatedResponse & { - products: Product[] -} - -export * from "./add-prices-batch" -export * from "./create-price-list" -export * from "./delete-price-list" -export * from "./delete-prices-batch" -export * from "./delete-products-prices-batch" -export * from "./get-price-list" -export * from "./list-price-list-products" -export * from "./list-price-lists" -export * from "./update-price-list" diff --git a/packages/medusa/src/api/routes/admin/price-lists/list-price-list-products.ts b/packages/medusa/src/api/routes/admin/price-lists/list-price-list-products.ts deleted file mode 100644 index 97c68928a7..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/list-price-list-products.ts +++ /dev/null @@ -1,362 +0,0 @@ -import { - IsArray, - IsBoolean, - IsEnum, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { - DateComparisonOperator, - extendedFindParamsMixin, -} from "../../../../types/common" - -import { Type } from "class-transformer" -import { Request } from "express" -import { ProductStatus } from "../../../../models" -import PriceListService from "../../../../services/price-list" -import { FilterableProductProps } from "../../../../types/product" -import { IsType } from "../../../../utils" - -/** - * @oas [get] /admin/price-lists/{id}/products - * operationId: "GetPriceListsPriceListProducts" - * summary: "List Products" - * description: "Retrieve a price list's products. The products can be filtered by fields such as `q` or `status`. The products can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (path) id=* {string} ID of the price list. - * - (query) q {string} term used to search products' title, description, product variant's title and sku, and product collection's title. - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by product IDs. - * schema: - * oneOf: - * - type: string - * description: ID of the product. - * - type: array - * items: - * type: string - * description: ID of a product. - * - in: query - * name: status - * description: Filter by product status - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * enum: [draft, proposed, published, rejected] - * - in: query - * name: collection_id - * description: Filter by product collection ID. Only products in the specified collections are retrieved. - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * - in: query - * name: tags - * description: Filter by tag IDs. Only products having the specified tags are retrieved. - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * - (query) title {string} Filter by title - * - (query) description {string} Filter by description - * - (query) handle {string} Filter by handle - * - (query) is_giftcard {boolean} A boolean value to filter by whether the product is a gift card or not. - * - (query) type {string} Filter product type. - * - (query) order {string} A product field to sort-order the retrieved products by. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: deleted_at - * description: Filter by a deletion date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - (query) offset=0 {integer} The number of products to skip when retrieving the products. - * - (query) limit=50 {integer} Limit the number of products returned. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned products. - * - (query) fields {string} Comma-separated fields that should be included in the returned products. - * x-codegen: - * method: listProducts - * queryParams: AdminGetPriceListsPriceListProductsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.listProducts(priceListId) - * .then(({ products, limit, offset, count }) => { - * console.log(products.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminPriceListProducts } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceListProducts = ({ - * priceListId - * }: Props) => { - * const { products, isLoading } = useAdminPriceListProducts( - * priceListId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {products && !products.length && ( - * No Price Lists - * )} - * {products && products.length > 0 && ( - *
    - * {products.map((product) => ( - *
  • {product.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default PriceListProducts - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/price-lists/{id}/products' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Price Lists - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPriceListsProductsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res) => { - const { id } = req.params - const { offset, limit } = req.validatedQuery - const priceListService: PriceListService = - req.scope.resolve("priceListService") - - const filterableFields: FilterableProductProps = { - ...req.filterableFields, - price_list_id: [id], - } - - const [products, count] = await priceListService.listProducts( - id, - filterableFields, - req.listConfig - ) - - res.json({ - products, - count, - offset, - limit, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved products associated with a price list. - * - * @property {number} limit - Limit the number of products returned in the list. Default is `50`. - */ -// eslint-disable-next-line max-len -export class AdminGetPriceListsPriceListProductsParams extends extendedFindParamsMixin( - { limit: 50 } -) { - /** - * ID to filter products by. - */ - @IsOptional() - @IsType([String, [String]]) - id?: string | string[] - - /** - * Search term to search products' title, description, product variant's title and sku, and product collection's title. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Statuses to filter products by. - */ - @IsOptional() - @IsEnum(ProductStatus, { each: true }) - status?: ProductStatus[] - - /** - * Filter products by their associated collection ID. - */ - @IsArray() - @IsOptional() - collection_id?: string[] - - /** - * Tags to filter products by. - */ - @IsArray() - @IsOptional() - tags?: string[] - - /** - * Title to filter products by. - */ - @IsString() - @IsOptional() - title?: string - - /** - * Description to filter products by. - */ - @IsString() - @IsOptional() - description?: string - - /** - * Handle to filter products by. - */ - @IsString() - @IsOptional() - handle?: string - - /** - * Filter products by whether they're gift cards. - */ - @IsBoolean() - @IsOptional() - @Type(() => Boolean) - is_giftcard?: boolean - - /** - * Type to filter products by. - */ - @IsString() - @IsOptional() - type?: string - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string - - /** - * Date filters to apply on the products' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the products' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on the products' `deleted_at` date. - */ - @ValidateNested() - @IsOptional() - @Type(() => DateComparisonOperator) - deleted_at?: DateComparisonOperator -} diff --git a/packages/medusa/src/api/routes/admin/price-lists/list-price-lists.ts b/packages/medusa/src/api/routes/admin/price-lists/list-price-lists.ts deleted file mode 100644 index 1bbfcb3651..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/list-price-lists.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { Type } from "class-transformer" -import { IsNumber, IsOptional, IsString } from "class-validator" -import { Request } from "express" -import PriceListService from "../../../../services/price-list" -import { FilterablePriceListProps } from "../../../../types/price-list" - -/** - * @oas [get] /admin/price-lists - * operationId: "GetPriceLists" - * summary: "List Price Lists" - * description: "Retrieve a list of price lists. The price lists can be filtered by fields such as `q` or `status`. The price lists can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) limit=10 {number} Limit the number of price lists returned. - * - (query) offset=0 {number} The number of price lists to skip when retrieving the price lists. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned price lists. - * - (query) fields {string} Comma-separated fields that should be included in the returned price lists. - * - (query) order {string} A price-list field to sort-order the retrieved price lists by. - * - (query) id {string} Filter by ID - * - (query) q {string} term to search price lists' description, name, and customer group's name. - * - in: query - * name: status - * style: form - * explode: false - * description: Filter by status. - * schema: - * type: array - * items: - * type: string - * enum: [active, draft] - * - (query) name {string} Filter by name - * - in: query - * name: customer_groups - * style: form - * explode: false - * description: Filter by customer-group IDs. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: type - * style: form - * explode: false - * description: Filter by type. - * schema: - * type: array - * items: - * type: string - * enum: [sale, override] - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: deleted_at - * description: Filter by a deletion date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: list - * queryParams: AdminGetPriceListPaginationParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.list() - * .then(({ price_lists, limit, offset, count }) => { - * console.log(price_lists.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminPriceLists } from "medusa-react" - * - * const PriceLists = () => { - * const { price_lists, isLoading } = useAdminPriceLists() - * - * return ( - *
- * {isLoading && Loading...} - * {price_lists && !price_lists.length && ( - * No Price Lists - * )} - * {price_lists && price_lists.length > 0 && ( - *
    - * {price_lists.map((price_list) => ( - *
  • {price_list.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default PriceLists - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/price-lists' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Price Lists - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPriceListsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res) => { - const validated = req.validatedQuery - const priceListService: PriceListService = - req.scope.resolve("priceListService") - - const [priceLists, count] = await priceListService.listAndCount( - req.filterableFields, - req.listConfig - ) - - res.json({ - price_lists: priceLists, - count, - offset: validated.offset, - limit: validated.limit, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved price lists. - */ -// eslint-disable-next-line max-len -export class AdminGetPriceListPaginationParams extends FilterablePriceListProps { - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - offset?: number = 0 - - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 10 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit?: number = 10 - - /** - * {@inheritDoc FindParams.expand} - */ - @IsString() - @IsOptional() - expand?: string - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string -} diff --git a/packages/medusa/src/api/routes/admin/price-lists/update-price-list.ts b/packages/medusa/src/api/routes/admin/price-lists/update-price-list.ts deleted file mode 100644 index ad783a433e..0000000000 --- a/packages/medusa/src/api/routes/admin/price-lists/update-price-list.ts +++ /dev/null @@ -1,270 +0,0 @@ -import { PriceListStatus, PriceListType } from "@medusajs/utils" -import { - IsArray, - IsBoolean, - IsEnum, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { defaultAdminPriceListFields, defaultAdminPriceListRelations } from "." - -import { Transform, Type } from "class-transformer" -import { EntityManager } from "typeorm" -import { PriceList } from "../../../.." -import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" -import PriceListService from "../../../../services/price-list" -import { AdminPriceListPricesUpdateReq } from "../../../../types/price-list" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" -import { validator } from "../../../../utils/validator" -import { transformOptionalDate } from "../../../../utils/validators/date-transform" - -/** - * @oas [post] /admin/price-lists/{id} - * operationId: "PostPriceListsPriceListPriceList" - * summary: "Update a Price List" - * description: "Update a Price List's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Price List. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostPriceListsPriceListPriceListReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.priceLists.update(priceListId, { - * name: "New Price List" - * }) - * .then(({ price_list }) => { - * console.log(price_list.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdatePriceList } from "medusa-react" - * - * type Props = { - * priceListId: string - * } - * - * const PriceList = ({ - * priceListId - * }: Props) => { - * const updatePriceList = useAdminUpdatePriceList(priceListId) - * // ... - * - * const handleUpdate = ( - * endsAt: Date - * ) => { - * updatePriceList.mutate({ - * ends_at: endsAt, - * }, { - * onSuccess: ({ price_list }) => { - * console.log(price_list.ends_at) - * } - * }) - * } - * - * // ... - * } - * - * export default PriceList - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/price-lists/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "New Price List" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Price Lists - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPriceListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const manager: EntityManager = req.scope.resolve("manager") - const priceListService: PriceListService = - req.scope.resolve("priceListService") - - const validated = await validator( - AdminPostPriceListsPriceListPriceListReq, - req.body - ) - - await manager.transaction(async (transactionManager) => { - return await priceListService - .withTransaction(transactionManager) - .update(id, validated) - }) - - const priceList = await priceListService.retrieve(id, { - select: defaultAdminPriceListFields as (keyof PriceList)[], - relations: defaultAdminPriceListRelations, - }) - - res.json({ price_list: priceList }) -} - -class CustomerGroup { - @IsString() - id: string -} - -/** - * @schema AdminPostPriceListsPriceListPriceListReq - * type: object - * description: "The details to update of the payment collection." - * properties: - * name: - * description: "The name of the Price List" - * type: string - * description: - * description: "The description of the Price List." - * type: string - * starts_at: - * description: "The date with timezone that the Price List starts being valid." - * type: string - * format: date - * ends_at: - * description: "The date with timezone that the Price List ends being valid." - * type: string - * format: date - * type: - * description: The type of the Price List. - * type: string - * enum: - * - sale - * - override - * status: - * description: >- - * The status of the Price List. If the status is set to `draft`, the prices created in the price list will not be available of the customer. - * type: string - * enum: - * - active - * - draft - * prices: - * description: The prices of the Price List. - * type: array - * items: - * type: object - * required: - * - amount - * - variant_id - * properties: - * id: - * description: The ID of the price. - * type: string - * region_id: - * description: The ID of the Region for which the price is used. This is only required if `currecny_code` is not provided. - * type: string - * currency_code: - * description: The 3 character ISO currency code for which the price will be used. This is only required if `region_id` is not provided. - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * variant_id: - * description: The ID of the Variant for which the price is used. - * type: string - * amount: - * description: The amount to charge for the Product Variant. - * type: integer - * min_quantity: - * description: The minimum quantity for which the price will be used. - * type: integer - * max_quantity: - * description: The maximum quantity for which the price will be used. - * type: integer - * customer_groups: - * type: array - * description: An array of customer groups that the Price List applies to. - * items: - * type: object - * required: - * - id - * properties: - * id: - * description: The ID of a customer group - * type: string - * includes_tax: - * description: "Tax included in prices of price list" - * x-featureFlag: "tax_inclusive_pricing" - * type: boolean - */ -export class AdminPostPriceListsPriceListPriceListReq { - @IsString() - @IsOptional() - name?: string - - @IsString() - @IsOptional() - description?: string - - @IsOptional() - @Transform(transformOptionalDate) - starts_at?: Date | null - - @IsOptional() - @Transform(transformOptionalDate) - ends_at?: Date | null - - @IsOptional() - @IsEnum(PriceListStatus) - status?: PriceListStatus - - @IsOptional() - @IsEnum(PriceListType) - type?: PriceListType - - @IsOptional() - @IsArray() - @Type(() => AdminPriceListPricesUpdateReq) - @ValidateNested({ each: true }) - prices?: AdminPriceListPricesUpdateReq[] - - @IsOptional() - @IsArray() - @Type(() => CustomerGroup) - @ValidateNested({ each: true }) - customer_groups?: CustomerGroup[] - - @FeatureFlagDecorators(TaxInclusivePricingFeatureFlag.key, [ - IsOptional(), - IsBoolean(), - ]) - includes_tax?: boolean -} diff --git a/packages/medusa/src/api/routes/admin/product-categories/add-products-batch.ts b/packages/medusa/src/api/routes/admin/product-categories/add-products-batch.ts deleted file mode 100644 index bf39f94533..0000000000 --- a/packages/medusa/src/api/routes/admin/product-categories/add-products-batch.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { IsArray, ValidateNested } from "class-validator" -import { Request, Response } from "express" - -import { EntityManager } from "typeorm" -import { ProductBatchProductCategory } from "../../../../types/product-category" -import { ProductCategoryService } from "../../../../services" -import { Type } from "class-transformer" -import { FindParams } from "../../../../types/common" - -/** - * @oas [post] /admin/product-categories/{id}/products/batch - * operationId: "PostProductCategoriesCategoryProductsBatch" - * summary: "Add Products to a Category" - * description: "Add a list of products to a product category." - * x-authenticated: true - * x-featureFlag: "product_categories" - * parameters: - * - (path) id=* {string} The ID of the Product Category. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned product category. - * - (query) fields {string} Comma-separated fields that should be included in the returned product category. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostProductCategoriesCategoryProductsBatchReq" - * x-codegen: - * method: addProducts - * queryParams: AdminPostProductCategoriesCategoryProductsBatchParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.addProducts(productCategoryId, { - * product_ids: [ - * { - * id: productId - * } - * ] - * }) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminAddProductsToCategory } from "medusa-react" - * - * type ProductsData = { - * id: string - * } - * - * type Props = { - * productCategoryId: string - * } - * - * const Category = ({ - * productCategoryId - * }: Props) => { - * const addProducts = useAdminAddProductsToCategory( - * productCategoryId - * ) - * // ... - * - * const handleAddProducts = ( - * productIds: ProductsData[] - * ) => { - * addProducts.mutate({ - * product_ids: productIds - * }, { - * onSuccess: ({ product_category }) => { - * console.log(product_category.products) - * } - * }) - * } - * - * // ... - * } - * - * export default Category - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/product-categories/{id}/products/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "product_ids": [ - * { - * "id": "{product_id}" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Categories - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductCategoriesCategoryRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response): Promise => { - const validatedBody = - req.validatedBody as AdminPostProductCategoriesCategoryProductsBatchReq - - const { id } = req.params - - const productCategoryService: ProductCategoryService = req.scope.resolve( - "productCategoryService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await productCategoryService - .withTransaction(transactionManager) - .addProducts( - id, - validatedBody.product_ids.map((p) => p.id) - ) - }) - - const productCategory = await productCategoryService.retrieve( - id, - req.retrieveConfig - ) - - res.status(200).json({ product_category: productCategory }) -} - -/** - * @schema AdminPostProductCategoriesCategoryProductsBatchReq - * type: object - * description: "The details of the products to add to the product category." - * required: - * - product_ids - * properties: - * product_ids: - * description: The IDs of the products to add to the product category - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * type: string - * description: The ID of the product - */ -export class AdminPostProductCategoriesCategoryProductsBatchReq { - @IsArray() - @ValidateNested({ each: true }) - @Type(() => ProductBatchProductCategory) - product_ids: ProductBatchProductCategory[] -} - -// eslint-disable-next-line max-len -export class AdminPostProductCategoriesCategoryProductsBatchParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/product-categories/create-product-category.ts b/packages/medusa/src/api/routes/admin/product-categories/create-product-category.ts deleted file mode 100644 index d5b9dccfdb..0000000000 --- a/packages/medusa/src/api/routes/admin/product-categories/create-product-category.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { IsNotEmpty, IsString, IsObject, IsOptional } from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" - -import { ProductCategoryService } from "../../../../services" -import { AdminProductCategoriesReqBase } from "../../../../types/product-category" -import { FindParams } from "../../../../types/common" - -/** - * @oas [post] /admin/product-categories - * operationId: "PostProductCategories" - * summary: "Create a Product Category" - * description: "Create a Product Category." - * x-authenticated: true - * x-featureFlag: "product_categories" - * parameters: - * - (query) expand {string} Comma-separated relations that should be expanded in the returned product category. - * - (query) fields {string} Comma-separated fields that should be included in the returned product category. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostProductCategoriesReq" - * x-codegen: - * method: create - * queryParams: AdminPostProductCategoriesParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.create({ - * name: "Skinny Jeans", - * }) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateProductCategory } from "medusa-react" - * - * const CreateCategory = () => { - * const createCategory = useAdminCreateProductCategory() - * // ... - * - * const handleCreate = ( - * name: string - * ) => { - * createCategory.mutate({ - * name, - * }, { - * onSuccess: ({ product_category }) => { - * console.log(product_category.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateCategory - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/product-categories' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "Skinny Jeans" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Categories - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductCategoriesCategoryRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { validatedBody } = req as { - validatedBody: AdminPostProductCategoriesReq - } - - const productCategoryService: ProductCategoryService = req.scope.resolve( - "productCategoryService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const created = await manager.transaction(async (transactionManager) => { - return await productCategoryService - .withTransaction(transactionManager) - .create(validatedBody) - }) - - const productCategory = await productCategoryService.retrieve( - created.id, - req.retrieveConfig - ) - - res.status(200).json({ product_category: productCategory }) -} - -/** - * @schema AdminPostProductCategoriesReq - * type: object - * description: "The details of the product category to create." - * required: - * - name - * properties: - * name: - * type: string - * description: The name of the product category - * description: - * type: string - * description: The description of the product category. - * handle: - * type: string - * description: The handle of the product category. If none is provided, the kebab-case version of the name will be used. This field can be used as a slug in URLs. - * is_internal: - * type: boolean - * description: >- - * If set to `true`, the product category will only be available to admins. - * is_active: - * type: boolean - * description: >- - * If set to `false`, the product category will not be available in the storefront. - * parent_category_id: - * type: string - * description: The ID of the parent product category - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -// eslint-disable-next-line max-len -export class AdminPostProductCategoriesReq extends AdminProductCategoriesReqBase { - @IsString() - @IsNotEmpty() - name: string - - @IsObject() - @IsOptional() - metadata?: Record -} - -export class AdminPostProductCategoriesParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/product-categories/delete-product-category.ts b/packages/medusa/src/api/routes/admin/product-categories/delete-product-category.ts deleted file mode 100644 index a39e9cdfff..0000000000 --- a/packages/medusa/src/api/routes/admin/product-categories/delete-product-category.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Request, Response } from "express" -import { EntityManager } from "typeorm" - -import { ProductCategoryService } from "../../../../services" - -/** - * @oas [delete] /admin/product-categories/{id} - * operationId: "DeleteProductCategoriesCategory" - * summary: "Delete a Product Category" - * description: "Delete a Product Category. This does not delete associated products." - * x-authenticated: true - * x-featureFlag: "product_categories" - * parameters: - * - (path) id=* {string} The ID of the Product Category - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.delete(productCategoryId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteProductCategory } from "medusa-react" - * - * type Props = { - * productCategoryId: string - * } - * - * const Category = ({ - * productCategoryId - * }: Props) => { - * const deleteCategory = useAdminDeleteProductCategory( - * productCategoryId - * ) - * // ... - * - * const handleDelete = () => { - * deleteCategory.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Category - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/product-categories/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Categories - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductCategoriesCategoryDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const { id } = req.params - - const productCategoryService: ProductCategoryService = req.scope.resolve( - "productCategoryService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - - await manager.transaction(async (transactionManager) => { - return await productCategoryService - .withTransaction(transactionManager) - .delete(id) - }) - - res.json({ - id: id, - object: "product-category", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/product-categories/delete-products-batch.ts b/packages/medusa/src/api/routes/admin/product-categories/delete-products-batch.ts deleted file mode 100644 index 58246248bc..0000000000 --- a/packages/medusa/src/api/routes/admin/product-categories/delete-products-batch.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { IsArray, ValidateNested } from "class-validator" -import { Request, Response } from "express" - -import { EntityManager } from "typeorm" -import { ProductBatchProductCategory } from "../../../../types/product-category" -import { ProductCategoryService } from "../../../../services" -import { Type } from "class-transformer" -import { FindParams } from "../../../../types/common" - -/** - * @oas [delete] /admin/product-categories/{id}/products/batch - * operationId: "DeleteProductCategoriesCategoryProductsBatch" - * summary: "Remove Products from Category" - * description: "Remove a list of products from a product category." - * x-authenticated: true - * x-featureFlag: "product_categories" - * parameters: - * - (path) id=* {string} The ID of the Product Category. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned product category. - * - (query) fields {string} Comma-separated fields that should be included in the returned product category. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteProductCategoriesCategoryProductsBatchReq" - * x-codegen: - * method: removeProducts - * queryParams: AdminDeleteProductCategoriesCategoryProductsBatchParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.removeProducts(productCategoryId, { - * product_ids: [ - * { - * id: productId - * } - * ] - * }) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteProductsFromCategory } from "medusa-react" - * - * type ProductsData = { - * id: string - * } - * - * type Props = { - * productCategoryId: string - * } - * - * const Category = ({ - * productCategoryId - * }: Props) => { - * const deleteProducts = useAdminDeleteProductsFromCategory( - * productCategoryId - * ) - * // ... - * - * const handleDeleteProducts = ( - * productIds: ProductsData[] - * ) => { - * deleteProducts.mutate({ - * product_ids: productIds - * }, { - * onSuccess: ({ product_category }) => { - * console.log(product_category.products) - * } - * }) - * } - * - * // ... - * } - * - * export default Category - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/product-categories/{id}/products/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "product_ids": [ - * { - * "id": "{product_id}" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Categories - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductCategoriesCategoryRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const { id } = req.params - const validatedBody = - req.validatedBody as AdminDeleteProductCategoriesCategoryProductsBatchReq - - const productCategoryService: ProductCategoryService = req.scope.resolve( - "productCategoryService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (manager) => { - return await productCategoryService.withTransaction(manager).removeProducts( - id, - validatedBody.product_ids.map((p) => p.id) - ) - }) - - const productCategory = await productCategoryService.retrieve( - id, - req.retrieveConfig - ) - - res.status(200).json({ product_category: productCategory }) -} - -/** - * @schema AdminDeleteProductCategoriesCategoryProductsBatchReq - * type: object - * description: "The details of the products to delete from the product category." - * required: - * - product_ids - * properties: - * product_ids: - * description: The IDs of the products to delete from the product category. - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * description: The ID of a product - * type: string - */ -export class AdminDeleteProductCategoriesCategoryProductsBatchReq { - @IsArray() - @ValidateNested({ each: true }) - @Type(() => ProductBatchProductCategory) - product_ids: ProductBatchProductCategory[] -} - -// eslint-disable-next-line max-len -export class AdminDeleteProductCategoriesCategoryProductsBatchParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/product-categories/get-product-category.ts b/packages/medusa/src/api/routes/admin/product-categories/get-product-category.ts deleted file mode 100644 index 929aaa2b0c..0000000000 --- a/packages/medusa/src/api/routes/admin/product-categories/get-product-category.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Request, Response } from "express" - -import ProductCategoryService from "../../../../services/product-category" -import { FindParams } from "../../../../types/common" -import { defaultAdminProductCategoryRelations } from "." - -/** - * @oas [get] /admin/product-categories/{id} - * operationId: "GetProductCategoriesCategory" - * summary: "Get a Product Category" - * description: "Retrieve a Product Category's details." - * x-authenticated: true - * x-featureFlag: "product_categories" - * parameters: - * - (path) id=* {string} The ID of the Product Category - * - (query) expand {string} Comma-separated relations that should be expanded in the returned product category. - * - (query) fields {string} Comma-separated fields that should be included in the returned product category. - * x-codegen: - * method: retrieve - * queryParams: AdminGetProductCategoryParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.retrieve(productCategoryId) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminProductCategory } from "medusa-react" - * - * type Props = { - * productCategoryId: string - * } - * - * const Category = ({ - * productCategoryId - * }: Props) => { - * const { - * product_category, - * isLoading, - * } = useAdminProductCategory(productCategoryId) - * - * return ( - *
- * {isLoading && Loading...} - * {product_category && ( - * {product_category.name} - * )} - * - *
- * ) - * } - * - * export default Category - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/product-categories/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Categories - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductCategoriesCategoryRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const productCategoryService: ProductCategoryService = req.scope.resolve( - "productCategoryService" - ) - - const productCategory = await productCategoryService.retrieve(id, { - relations: defaultAdminProductCategoryRelations, - }) - - res.status(200).json({ product_category: productCategory }) -} - -export class AdminGetProductCategoryParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/product-categories/index.ts b/packages/medusa/src/api/routes/admin/product-categories/index.ts deleted file mode 100644 index dca28132e8..0000000000 --- a/packages/medusa/src/api/routes/admin/product-categories/index.ts +++ /dev/null @@ -1,229 +0,0 @@ -import { Router } from "express" - -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" - -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled" -import deleteProductCategory from "./delete-product-category" -import { validateProductsExist } from "../../../middlewares/validators/product-existence" - -import getProductCategory, { - AdminGetProductCategoryParams, -} from "./get-product-category" - -import listProductCategories, { - AdminGetProductCategoriesParams, -} from "./list-product-categories" - -import createProductCategory, { - AdminPostProductCategoriesParams, - AdminPostProductCategoriesReq, -} from "./create-product-category" - -import updateProductCategory, { - AdminPostProductCategoriesCategoryParams, - AdminPostProductCategoriesCategoryReq, -} from "./update-product-category" - -import addProductsBatch, { - AdminPostProductCategoriesCategoryProductsBatchParams, - AdminPostProductCategoriesCategoryProductsBatchReq, -} from "./add-products-batch" - -import deleteProductsBatch, { - AdminDeleteProductCategoriesCategoryProductsBatchParams, - AdminDeleteProductCategoriesCategoryProductsBatchReq, -} from "./delete-products-batch" - -import { ProductCategory } from "../../../../models" - -const route = Router() - -export default (app) => { - const retrieveTransformQueryConfig = { - defaultFields: defaultProductCategoryFields, - defaultRelations: defaultAdminProductCategoryRelations, - allowedRelations: allowedAdminProductCategoryRelations, - isList: false, - } - - const listTransformQueryConfig = { - ...retrieveTransformQueryConfig, - isList: true, - } - - app.use( - "/product-categories", - isFeatureFlagEnabled("product_categories"), - route - ) - - route.post( - "/", - transformQuery( - AdminPostProductCategoriesParams, - retrieveTransformQueryConfig - ), - transformBody(AdminPostProductCategoriesReq), - middlewares.wrap(createProductCategory) - ) - - route.get( - "/", - transformQuery(AdminGetProductCategoriesParams, listTransformQueryConfig), - middlewares.wrap(listProductCategories) - ) - - route.get( - "/:id", - transformQuery(AdminGetProductCategoryParams, retrieveTransformQueryConfig), - middlewares.wrap(getProductCategory) - ) - - route.post( - "/:id", - transformQuery( - AdminPostProductCategoriesCategoryParams, - retrieveTransformQueryConfig - ), - transformBody(AdminPostProductCategoriesCategoryReq), - middlewares.wrap(updateProductCategory) - ) - - route.delete("/:id", middlewares.wrap(deleteProductCategory)) - - route.post( - "/:id/products/batch", - transformQuery( - AdminPostProductCategoriesCategoryProductsBatchParams, - retrieveTransformQueryConfig - ), - transformBody(AdminPostProductCategoriesCategoryProductsBatchReq), - validateProductsExist((req) => req.body.product_ids), - middlewares.wrap(addProductsBatch) - ) - - route.delete( - "/:id/products/batch", - transformQuery( - AdminDeleteProductCategoriesCategoryProductsBatchParams, - retrieveTransformQueryConfig - ), - transformBody(AdminDeleteProductCategoriesCategoryProductsBatchReq), - validateProductsExist((req) => req.body.product_ids), - middlewares.wrap(deleteProductsBatch) - ) - - return app -} - -export * from "./get-product-category" -export * from "./delete-product-category" -export * from "./list-product-categories" -export * from "./create-product-category" -export * from "./update-product-category" -export * from "./add-products-batch" -export * from "./delete-products-batch" - -export const defaultAdminProductCategoryRelations = [ - "parent_category", - "category_children", -] - -export const allowedAdminProductCategoryRelations = [ - "parent_category", - "category_children", -] - -export const defaultProductCategoryFields = [ - "id", - "name", - "description", - "handle", - "is_active", - "is_internal", - "rank", - "parent_category_id", - "created_at", - "updated_at", - "metadata", -] - -/** - * @schema AdminProductCategoriesCategoryRes - * type: object - * description: "The product category's details." - * x-expanded-relations: - * field: product_category - * relations: - * - category_children - * - parent_category - * required: - * - product_category - * properties: - * product_category: - * description: "Product category details." - * $ref: "#/components/schemas/ProductCategory" - */ -export type AdminProductCategoriesCategoryRes = { - product_category: ProductCategory -} - -/** - * @schema AdminProductCategoriesCategoryDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted product category - * object: - * type: string - * description: The type of the object that was deleted. - * default: product-category - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminProductCategoriesCategoryDeleteRes = DeleteResponse - -/** - * @schema AdminProductCategoriesListRes - * type: object - * description: "The list of product categories with pagination fields." - * x-expanded-relations: - * field: product_categories - * relations: - * - category_children - * - parent_category - * required: - * - product_categories - * - count - * - offset - * - limit - * properties: - * product_categories: - * type: array - * description: "An array of product category details." - * items: - * $ref: "#/components/schemas/ProductCategory" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of product categories skipped when retrieving the product categories. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminProductCategoriesListRes = PaginatedResponse & { - product_categories: ProductCategory[] -} diff --git a/packages/medusa/src/api/routes/admin/product-categories/list-product-categories.ts b/packages/medusa/src/api/routes/admin/product-categories/list-product-categories.ts deleted file mode 100644 index 95fc1c14ff..0000000000 --- a/packages/medusa/src/api/routes/admin/product-categories/list-product-categories.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { IsOptional, IsString, IsBoolean } from "class-validator" -import { Request, Response } from "express" -import { Transform } from "class-transformer" - -import { ProductCategoryService } from "../../../../services" -import { extendedFindParamsMixin } from "../../../../types/common" -import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean" - -/** - * @oas [get] /admin/product-categories - * operationId: "GetProductCategories" - * summary: "List Product Categories" - * description: "Retrieve a list of product categories. The product categories can be filtered by fields such as `q` or `handle`. The product categories can also be paginated." - * x-authenticated: true - * x-featureFlag: "product_categories" - * parameters: - * - (query) q {string} term to search product categories' names and handles. - * - (query) handle {string} Filter by handle. - * - (query) is_internal {boolean} Filter by whether the category is internal or not. - * - (query) is_active {boolean} Filter by whether the category is active or not. - * - (query) include_descendants_tree {boolean} If set to `true`, all nested descendants of a category are included in the response. - * - (query) parent_category_id {string} Filter by the ID of a parent category. - * - (query) offset=0 {integer} The number of product categories to skip when retrieving the product categories. - * - (query) limit=100 {integer} Limit the number of product categories returned. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned product categories. - * - (query) fields {string} Comma-separated fields that should be included in the returned product categories. - * x-codegen: - * method: list - * queryParams: AdminGetProductCategoriesParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.list() - * .then(({ product_categories, limit, offset, count }) => { - * console.log(product_categories.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminProductCategories } from "medusa-react" - * - * function Categories() { - * const { - * product_categories, - * isLoading - * } = useAdminProductCategories() - * - * return ( - *
- * {isLoading && Loading...} - * {product_categories && !product_categories.length && ( - * No Categories - * )} - * {product_categories && product_categories.length > 0 && ( - *
    - * {product_categories.map( - * (category) => ( - *
  • {category.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Categories - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/product-categories' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Categories - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductCategoriesListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const productCategoryService: ProductCategoryService = req.scope.resolve( - "productCategoryService" - ) - - const [data, count] = await productCategoryService.listAndCount( - req.filterableFields, - req.listConfig - ) - - const { limit, offset } = req.validatedQuery - - res.json({ - count, - product_categories: data, - offset, - limit, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved product categories. - * - * @property {number} limit - Limit the number of product categories returned in the list. The default is `100`. - */ -export class AdminGetProductCategoriesParams extends extendedFindParamsMixin({ - limit: 100, - offset: 0, -}) { - /** - * Search term to search product categories' names and handles. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Handle to filter product categories by. - */ - @IsString() - @IsOptional() - handle?: string - - /** - * Whether to include child product categories in the response. - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value)) - include_descendants_tree?: boolean - - /** - * Filter product categories by whether they're internal. - */ - @IsString() - @IsOptional() - is_internal?: boolean - - /** - * Filter product categories by whether they're active. - */ - @IsString() - @IsOptional() - is_active?: boolean - - /** - * Filter product categories by their associated parent ID. - */ - @IsString() - @IsOptional() - @Transform(({ value }) => { - return value === "null" ? null : value - }) - parent_category_id?: string | null -} diff --git a/packages/medusa/src/api/routes/admin/product-categories/update-product-category.ts b/packages/medusa/src/api/routes/admin/product-categories/update-product-category.ts deleted file mode 100644 index ed1e651bd9..0000000000 --- a/packages/medusa/src/api/routes/admin/product-categories/update-product-category.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { - IsInt, - IsNotEmpty, - IsObject, - IsOptional, - IsString, - Min, -} from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" - -import { ProductCategoryService } from "../../../../services" -import { FindParams } from "../../../../types/common" -import { AdminProductCategoriesReqBase } from "../../../../types/product-category" - -/** - * @oas [post] /admin/product-categories/{id} - * operationId: "PostProductCategoriesCategory" - * summary: "Update a Product Category" - * description: "Updates a Product Category." - * x-authenticated: true - * x-featureFlag: "product_categories" - * parameters: - * - (path) id=* {string} The ID of the Product Category. - * - (query) expand {string} (Comma separated) Which fields should be expanded in each product category. - * - (query) fields {string} (Comma separated) Which fields should be retrieved in each product category. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostProductCategoriesCategoryReq" - * x-codegen: - * method: update - * queryParams: AdminPostProductCategoriesCategoryParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productCategories.update(productCategoryId, { - * name: "Skinny Jeans" - * }) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateProductCategory } from "medusa-react" - * - * type Props = { - * productCategoryId: string - * } - * - * const Category = ({ - * productCategoryId - * }: Props) => { - * const updateCategory = useAdminUpdateProductCategory( - * productCategoryId - * ) - * // ... - * - * const handleUpdate = ( - * name: string - * ) => { - * updateCategory.mutate({ - * name, - * }, { - * onSuccess: ({ product_category }) => { - * console.log(product_category.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Category - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/product-categories/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "Skinny Jeans" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Categories - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductCategoriesCategoryRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - const { validatedBody } = req as { - validatedBody: AdminPostProductCategoriesCategoryReq - } - - const productCategoryService: ProductCategoryService = req.scope.resolve( - "productCategoryService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const updated = await manager.transaction(async (transactionManager) => { - return await productCategoryService - .withTransaction(transactionManager) - .update(id, validatedBody) - }) - - const productCategory = await productCategoryService.retrieve( - updated.id, - req.retrieveConfig - ) - - res.status(200).json({ product_category: productCategory }) -} - -/** - * @schema AdminPostProductCategoriesCategoryReq - * type: object - * description: "The details to update of the product category." - * properties: - * name: - * type: string - * description: The name to identify the Product Category by. - * description: - * type: string - * description: An optional text field to describe the Product Category by. - * handle: - * type: string - * description: A handle to be used in slugs. - * is_internal: - * type: boolean - * description: A flag to make product category an internal category for admins - * is_active: - * type: boolean - * description: A flag to make product category visible/hidden in the store front - * parent_category_id: - * type: string - * description: The ID of the parent product category - * rank: - * type: number - * description: The rank of the category in the tree node (starting from 0) - * metadata: - * description: An optional set of key-value pairs to hold additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -// eslint-disable-next-line max-len -export class AdminPostProductCategoriesCategoryReq extends AdminProductCategoriesReqBase { - @IsString() - @IsOptional() - name?: string - - @IsOptional() - @IsString() - @IsNotEmpty() - handle?: string - - @IsOptional() - @IsInt() - @IsNotEmpty() - @Min(0) - rank?: number - - @IsObject() - @IsOptional() - metadata?: Record -} - -export class AdminPostProductCategoriesCategoryParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/product-tags/index.ts b/packages/medusa/src/api/routes/admin/product-tags/index.ts deleted file mode 100644 index 0ea434f5a8..0000000000 --- a/packages/medusa/src/api/routes/admin/product-tags/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Router } from "express" -import { ProductTag } from "../../../.." -import { PaginatedResponse } from "../../../../types/common" -import middlewares, { transformQuery } from "../../../middlewares" -import "reflect-metadata" -import { AdminGetProductTagsParams } from "./list-product-tags" - -const route = Router() - -export default (app) => { - app.use("/product-tags", route) - - route.get( - "/", - transformQuery(AdminGetProductTagsParams, { - defaultFields: defaultAdminProductTagsFields, - defaultRelations: defaultAdminProductTagsRelations, - isList: true, - }), - middlewares.wrap(require("./list-product-tags").default) - ) - - return app -} - -export const defaultAdminProductTagsFields = [ - "id", - "value", - "created_at", - "updated_at", -] -export const defaultAdminProductTagsRelations = [] - -/** - * @schema AdminProductTagsListRes - * type: object - * description: "The list of product tags with pagination fields." - * required: - * - product_tags - * - count - * - offset - * - limit - * properties: - * product_tags: - * type: array - * description: "An array of product tag details." - * items: - * $ref: "#/components/schemas/ProductTag" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of product tags skipped when retrieving the product tags. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminProductTagsListRes = PaginatedResponse & { - product_tags: ProductTag[] -} - -export * from "./list-product-tags" diff --git a/packages/medusa/src/api/routes/admin/product-tags/list-product-tags.ts b/packages/medusa/src/api/routes/admin/product-tags/list-product-tags.ts deleted file mode 100644 index 77327afb7b..0000000000 --- a/packages/medusa/src/api/routes/admin/product-tags/list-product-tags.ts +++ /dev/null @@ -1,256 +0,0 @@ -import { - DateComparisonOperator, - StringComparisonOperator, -} from "../../../../types/common" -import { IsNumber, IsOptional, IsString } from "class-validator" - -import { IsType } from "../../../../utils/validators/is-type" -import ProductTagService from "../../../../services/product-tag" -import { Type } from "class-transformer" -import { Request, Response } from "express" - -/** - * @oas [get] /admin/product-tags - * operationId: "GetProductTags" - * summary: "List Product Tags" - * description: "Retrieve a list of product tags. The product tags can be filtered by fields such as `q` or `value`. The product tags can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) limit=10 {integer} Limit the number of product tags returned. - * - (query) offset=0 {integer} The number of product tags to skip when retrieving the product tags. - * - (query) order {string} A product tag field to sort-order the retrieved product tags by. - * - (query) discount_condition_id {string} Filter by the ID of a discount condition. Only product tags that this discount condition is applied to will be retrieved. - * - in: query - * name: value - * style: form - * explode: false - * description: Filter by tag value. - * schema: - * type: array - * items: - * type: string - * - (query) q {string} term to search product tags' values. - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by tag IDs. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: list - * queryParams: AdminGetProductTagsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productTags.list() - * .then(({ product_tags }) => { - * console.log(product_tags.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminProductTags } from "medusa-react" - * - * function ProductTags() { - * const { - * product_tags, - * isLoading - * } = useAdminProductTags() - * - * return ( - *
- * {isLoading && Loading...} - * {product_tags && !product_tags.length && ( - * No Product Tags - * )} - * {product_tags && product_tags.length > 0 && ( - *
    - * {product_tags.map( - * (tag) => ( - *
  • {tag.value}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default ProductTags - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/product-tags' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Tags - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductTagsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const tagService: ProductTagService = req.scope.resolve("productTagService") - const { listConfig, filterableFields } = req - const { skip, take } = req.listConfig - - const [tags, count] = await tagService.listAndCount( - filterableFields, - listConfig - ) - - res.status(200).json({ - product_tags: tags, - count, - offset: skip, - limit: take, - }) -} - -/** - * {@inheritDoc FindPaginationParams} - */ -export class AdminGetProductTagsPaginationParams { - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 10 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit = 10 - - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - offset = 0 -} - -/** - * Parameters used to filter and configure the pagination of the retrieved product tags. - */ -export class AdminGetProductTagsParams extends AdminGetProductTagsPaginationParams { - /** - * IDs to filter product tags by. - */ - @IsOptional() - @IsType([String, [String], StringComparisonOperator]) - id?: string | string[] | StringComparisonOperator - - /** - * Search term to search product tags' value. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Values to search product tags by. - */ - @IsOptional() - @IsType([String, [String], StringComparisonOperator]) - value?: string | string[] | StringComparisonOperator - - /** - * Date filters to apply on the product tags' `created_at` date. - */ - @IsType([DateComparisonOperator]) - @IsOptional() - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the product tags' `updated_at` date. - */ - @IsType([DateComparisonOperator]) - @IsOptional() - updated_at?: DateComparisonOperator - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string - - /** - * Filter product tags by their associated discount condition's ID. - */ - @IsString() - @IsOptional() - discount_condition_id?: string -} diff --git a/packages/medusa/src/api/routes/admin/product-types/index.ts b/packages/medusa/src/api/routes/admin/product-types/index.ts deleted file mode 100644 index c452b5ef62..0000000000 --- a/packages/medusa/src/api/routes/admin/product-types/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Router } from "express" -import { ProductType } from "../../../.." -import { PaginatedResponse } from "../../../../types/common" -import middlewares, { transformQuery } from "../../../middlewares" -import "reflect-metadata" -import { AdminGetProductTypesParams } from "./list-product-types" - -const route = Router() - -export default (app) => { - app.use("/product-types", route) - - route.get( - "/", - transformQuery(AdminGetProductTypesParams, { - defaultFields: defaultAdminProductTypeFields, - defaultRelations: defaultAdminProductTypeRelations, - isList: true, - }), - middlewares.wrap(require("./list-product-types").default) - ) - - return app -} - -export const defaultAdminProductTypeFields = [ - "id", - "value", - "created_at", - "updated_at", -] -export const defaultAdminProductTypeRelations = [] - -/** - * @schema AdminProductTypesListRes - * type: object - * description: "The list of product types with pagination fields." - * required: - * - product_types - * - count - * - offset - * - limit - * properties: - * product_types: - * type: array - * description: An array of product types details. - * items: - * $ref: "#/components/schemas/ProductType" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of product types skipped when retrieving the product types. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminProductTypesListRes = PaginatedResponse & { - product_types: ProductType[] -} - -export * from "./list-product-types" diff --git a/packages/medusa/src/api/routes/admin/product-types/list-product-types.ts b/packages/medusa/src/api/routes/admin/product-types/list-product-types.ts deleted file mode 100644 index dc18f3c8ec..0000000000 --- a/packages/medusa/src/api/routes/admin/product-types/list-product-types.ts +++ /dev/null @@ -1,235 +0,0 @@ -import { - DateComparisonOperator, - FindPaginationParams, - StringComparisonOperator, -} from "../../../../types/common" -import { IsOptional, IsString } from "class-validator" - -import { IsType } from "../../../../utils/validators/is-type" -import ProductTypeService from "../../../../services/product-type" - -/** - * @oas [get] /admin/product-types - * operationId: "GetProductTypes" - * summary: "List Product Types" - * description: "Retrieve a list of product types. The product types can be filtered by fields such as `q` or `value`. The product types can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) limit=20 {integer} Limit the number of product types returned. - * - (query) offset=0 {integer} The number of product types to skip when retrieving the product types. - * - (query) order {string} A product type field to sort-order the retrieved product types by. - * - (query) discount_condition_id {string} Filter by the ID of a discount condition. Only product types that this discount condition is applied to will be retrieved. - * - in: query - * name: value - * style: form - * explode: false - * description: Filter by value. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by product type IDs. - * schema: - * type: array - * items: - * type: string - * - (query) q {string} term to search product types' values. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: list - * queryParams: AdminGetProductTypesParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.productTypes.list() - * .then(({ product_types }) => { - * console.log(product_types.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminProductTypes } from "medusa-react" - * - * function ProductTypes() { - * const { - * product_types, - * isLoading - * } = useAdminProductTypes() - * - * return ( - *
- * {isLoading && Loading...} - * {product_types && !product_types.length && ( - * No Product Tags - * )} - * {product_types && product_types.length > 0 && ( - *
    - * {product_types.map( - * (type) => ( - *
  • {type.value}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default ProductTypes - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/product-types' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Types - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductTypesListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const typeService: ProductTypeService = - req.scope.resolve("productTypeService") - - const { listConfig, filterableFields } = req - const { skip, take } = req.listConfig - - const [types, count] = await typeService.listAndCount( - filterableFields, - listConfig - ) - - res.status(200).json({ - product_types: types, - count, - offset: skip, - limit: take, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved product types. - */ -// eslint-disable-next-line max-len -export class AdminGetProductTypesParams extends FindPaginationParams { - /** - * IDs to filter product types by. - */ - @IsType([String, [String], StringComparisonOperator]) - @IsOptional() - id?: string | string[] | StringComparisonOperator - - /** - * Search terms to search product types' value. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Values to filter product types by. - */ - @IsType([String, [String], StringComparisonOperator]) - @IsOptional() - value?: string | string[] | StringComparisonOperator - - /** - * Date filters to apply on the product types' `created_at` date. - */ - @IsType([DateComparisonOperator]) - @IsOptional() - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the product types' `updated_at` date. - */ - @IsType([DateComparisonOperator]) - @IsOptional() - updated_at?: DateComparisonOperator - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string - - /** - * Filter product types by their associated discount condition's ID. - */ - @IsString() - @IsOptional() - discount_condition_id?: string -} diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/add-option.js b/packages/medusa/src/api/routes/admin/products/__tests__/add-option.js deleted file mode 100644 index edf3fd1f66..0000000000 --- a/packages/medusa/src/api/routes/admin/products/__tests__/add-option.js +++ /dev/null @@ -1,42 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductServiceMock } from "../../../../../services/__mocks__/product" - -describe("POST /admin/products/:id/options", () => { - describe("successful add option", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/products/${IdMap.getId("productWithOptions")}/options`, - { - payload: { - title: "Test option", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service addOption", () => { - expect(ProductServiceMock.addOption).toHaveBeenCalledTimes(1) - expect(ProductServiceMock.addOption).toHaveBeenCalledWith( - IdMap.getId("productWithOptions"), - "Test option" - ) - }) - - it("returns the updated product decorated", () => { - expect(subject.body.product.id).toEqual(IdMap.getId("productWithOptions")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/create-product.js b/packages/medusa/src/api/routes/admin/products/__tests__/create-product.js deleted file mode 100644 index a039edaa41..0000000000 --- a/packages/medusa/src/api/routes/admin/products/__tests__/create-product.js +++ /dev/null @@ -1,236 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductServiceMock } from "../../../../../services/__mocks__/product" -import { ProductVariantServiceMock } from "../../../../../services/__mocks__/product-variant" -import { ShippingProfileServiceMock } from "../../../../../services/__mocks__/shipping-profile" -import { SalesChannelServiceMock } from "../../../../../services/__mocks__/sales-channel" - -describe("POST /admin/products", () => { - describe("successful creation with variants", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/products", { - payload: { - title: "Test Product with variants", - description: "Test Description", - tags: [{ id: "test", value: "test" }], - handle: "test-product", - options: [{ title: "Test" }], - variants: [ - { - title: "Test", - prices: [ - { - currency_code: "USD", - amount: 100, - }, - ], - options: [ - { - value: "100", - }, - ], - }, - ], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(async () => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(SalesChannelServiceMock.retrieveDefault).toHaveBeenCalledTimes(1) - expect(subject.status).toEqual(200) - }) - - it("assigns invokes productVariantService with ranked variants", () => { - expect(ProductVariantServiceMock.create).toHaveBeenCalledTimes(1) - expect(ProductVariantServiceMock.create).toHaveBeenCalledWith( - IdMap.getId("productWithOptions"), - [ - { - title: "Test", - variant_rank: 0, - prices: [ - { - currency_code: "USD", - amount: 100, - }, - ], - options: [ - { - option_id: IdMap.getId("option1"), - value: "100", - }, - ], - inventory_quantity: 0, - }, - ] - ) - }) - }) - - describe("successful creation test", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/products", { - payload: { - title: "Test Product", - description: "Test Description", - tags: [{ id: "test", value: "test" }], - handle: "test-product", - options: [{ title: "Denominations" }], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns created product draft", () => { - expect(subject.body.product.id).toEqual(IdMap.getId("product1")) - }) - - it("calls service createDraft", () => { - expect(ProductServiceMock.create).toHaveBeenCalledTimes(1) - expect(ProductServiceMock.create).toHaveBeenCalledWith({ - title: "Test Product", - discountable: true, - description: "Test Description", - tags: [{ id: "test", value: "test" }], - handle: "test-product", - status: "draft", - is_giftcard: false, - options: [{ title: "Denominations" }], - profile_id: IdMap.getId("default_shipping_profile"), - sales_channels: [ - { - description: "sales channel 1 description", - is_disabled: false, - name: "sales channel 1 name", - }, - ], - }) - }) - - it("calls shipping profile default", () => { - expect(ShippingProfileServiceMock.retrieveDefault).toHaveBeenCalledTimes( - 1 - ) - expect(ShippingProfileServiceMock.retrieveDefault).toHaveBeenCalledWith() - }) - }) - - describe("successful creation of gift card product", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("POST", "/admin/products", { - payload: { - title: "Gift Card", - description: "make someone happy", - handle: "test-gift-card", - is_giftcard: true, - options: [{ title: "Denominations" }], - variants: [ - { - title: "100 USD", - prices: [ - { - currency_code: "USD", - amount: 100, - }, - ], - options: [ - { - value: "100", - }, - ], - }, - ], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("calls service createDraft", () => { - expect(ProductServiceMock.create).toHaveBeenCalledTimes(1) - expect(ProductServiceMock.create).toHaveBeenCalledWith({ - title: "Gift Card", - discountable: true, - description: "make someone happy", - options: [{ title: "Denominations" }], - handle: "test-gift-card", - is_giftcard: true, - status: "draft", - profile_id: IdMap.getId("giftCardProfile"), - sales_channels: [ - { - description: "sales channel 1 description", - is_disabled: false, - name: "sales channel 1 name", - }, - ], - }) - }) - - it("calls profile service", () => { - expect( - ShippingProfileServiceMock.retrieveGiftCardDefault - ).toHaveBeenCalledTimes(1) - expect( - ShippingProfileServiceMock.retrieveGiftCardDefault - ).toHaveBeenCalledWith() - }) - }) - - describe("invalid data returns error details", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/products", { - payload: { - description: "Test Description", - tags: "hi,med,dig", - handle: "test-product", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns error details", () => { - expect(subject.body.type).toEqual("invalid_data") - expect(subject.body.message).toEqual( - expect.stringContaining(`title must be a string`) - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/create-variant.js b/packages/medusa/src/api/routes/admin/products/__tests__/create-variant.js deleted file mode 100644 index 3d83858bd1..0000000000 --- a/packages/medusa/src/api/routes/admin/products/__tests__/create-variant.js +++ /dev/null @@ -1,61 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductVariantServiceMock } from "../../../../../services/__mocks__/product-variant" - -describe("POST /admin/products/:id/variants", () => { - describe("successful add variant", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/products/${IdMap.getId("productWithOptions")}/variants`, - { - payload: { - title: "Test Product Variant", - prices: [ - { - currency_code: "DKK", - amount: 1234, - }, - ], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service addVariant", () => { - expect(ProductVariantServiceMock.create).toHaveBeenCalledTimes(1) - expect(ProductVariantServiceMock.create).toHaveBeenCalledWith( - IdMap.getId("productWithOptions"), - [ - { - inventory_quantity: 0, - manage_inventory: true, - title: "Test Product Variant", - options: [], - prices: [ - { - currency_code: "DKK", - amount: 1234, - }, - ], - }, - ] - ) - }) - - it("returns the updated product decorated", () => { - expect(subject.body.product.id).toEqual(IdMap.getId("productWithOptions")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/delete-option.js b/packages/medusa/src/api/routes/admin/products/__tests__/delete-option.js deleted file mode 100644 index 2b11908e88..0000000000 --- a/packages/medusa/src/api/routes/admin/products/__tests__/delete-option.js +++ /dev/null @@ -1,46 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { - ProductServiceMock, - products, -} from "../../../../../services/__mocks__/product" - -describe("DELETE /admin/products/:id/options/:optionId", () => { - describe("successfully updates an option", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/products/${IdMap.getId( - "productWithOptions" - )}/options/${IdMap.getId("option1")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200 and correct delete info", () => { - expect(subject.status).toEqual(200) - expect(subject.body).toEqual({ - option_id: IdMap.getId("option1"), - object: "option", - deleted: true, - product: products.productWithOptions, - }) - }) - - it("calls update", () => { - expect(ProductServiceMock.deleteOption).toHaveBeenCalledTimes(1) - expect(ProductServiceMock.deleteOption).toHaveBeenCalledWith( - IdMap.getId("productWithOptions"), - IdMap.getId("option1") - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/delete-product.js b/packages/medusa/src/api/routes/admin/products/__tests__/delete-product.js deleted file mode 100644 index 561551d5a3..0000000000 --- a/packages/medusa/src/api/routes/admin/products/__tests__/delete-product.js +++ /dev/null @@ -1,46 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductServiceMock } from "../../../../../services/__mocks__/product" - -describe("DELETE /admin/products/:id", () => { - describe("successfully deletes a product", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/products/${IdMap.getId("product1")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls ProductService delete", () => { - expect(ProductServiceMock.delete).toHaveBeenCalledTimes(1) - expect(ProductServiceMock.delete).toHaveBeenCalledWith( - IdMap.getId("product1") - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns correct delete data", () => { - expect(subject.body).toEqual({ - id: IdMap.getId("product1"), - object: "product", - deleted: true, - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/delete-variant.js b/packages/medusa/src/api/routes/admin/products/__tests__/delete-variant.js deleted file mode 100644 index 925f17e6d4..0000000000 --- a/packages/medusa/src/api/routes/admin/products/__tests__/delete-variant.js +++ /dev/null @@ -1,45 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductVariantServiceMock } from "../../../../../services/__mocks__/product-variant" - -describe("POST /admin/products/:id/variants/:variantId", () => { - describe("successful removes variant", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/products/${IdMap.getId( - "productWithOptions" - )}/variants/${IdMap.getId("variant1")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service removeVariant", () => { - expect(ProductVariantServiceMock.delete).toHaveBeenCalledTimes(1) - expect(ProductVariantServiceMock.delete).toHaveBeenCalledWith( - IdMap.getId("variant1") - ) - }) - - it("returns delete result", () => { - expect(subject.body).toEqual({ - variant_id: IdMap.getId("variant1"), - object: "product-variant", - deleted: true, - product: expect.any(Object), - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/get-product.js b/packages/medusa/src/api/routes/admin/products/__tests__/get-product.js deleted file mode 100644 index 834ffda4d2..0000000000 --- a/packages/medusa/src/api/routes/admin/products/__tests__/get-product.js +++ /dev/null @@ -1,82 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductServiceMock } from "../../../../../services/__mocks__/product" - -describe("GET /admin/products/:id", () => { - describe("successfully gets a product", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/admin/products/${IdMap.getId("product1")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls get product from productService", () => { - expect(ProductServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect( - ProductServiceMock.retrieve.mock.calls[0][1].relations - ).toHaveLength(11) - expect(ProductServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("product1"), - { - select: [ - "id", - "title", - "subtitle", - "status", - "external_id", - "description", - "handle", - "is_giftcard", - "discountable", - "thumbnail", - "collection_id", - "type_id", - "weight", - "length", - "height", - "width", - "hs_code", - "origin_country", - "mid_code", - "material", - "created_at", - "updated_at", - "deleted_at", - "metadata", - ], - relations: expect.arrayContaining([ - "collection", - "images", - "options", - "options.values", - "profiles", - "sales_channels", - "tags", - "type", - "variants", - "variants.options", - "variants.prices", - ]), - } - ) - }) - - it("returns product decorated", () => { - expect(subject.body.product.id).toEqual(IdMap.getId("product1")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/list-products.js b/packages/medusa/src/api/routes/admin/products/__tests__/list-products.js deleted file mode 100644 index 80b4e4bcc1..0000000000 --- a/packages/medusa/src/api/routes/admin/products/__tests__/list-products.js +++ /dev/null @@ -1,32 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { - products, - ProductServiceMock, -} from "../../../../../services/__mocks__/product" - -describe("GET /admin/products", () => { - describe("successfully lists products", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/admin/products`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200 and decorated products", () => { - expect(subject.status).toEqual(200) - expect(subject.body.products[0].id).toEqual(products.product1.id) - expect(subject.body.products[1].id).toEqual(products.product2.id) - }) - - it("calls update", () => { - expect(ProductServiceMock.listAndCount).toHaveBeenCalledTimes(1) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/list-variants.js b/packages/medusa/src/api/routes/admin/products/__tests__/list-variants.js deleted file mode 100644 index a7097743ef..0000000000 --- a/packages/medusa/src/api/routes/admin/products/__tests__/list-variants.js +++ /dev/null @@ -1,74 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { - defaultAdminGetProductsVariantsFields, - defaultAdminGetProductsVariantsRelations, -} from ".." -import { request } from "../../../../../helpers/test-request" -import { ProductVariantServiceMock } from "../../../../../services/__mocks__/product-variant" - -describe("GET /admin/products/:id/variants", () => { - describe("successfully gets a product variants", () => { - afterEach(() => { - jest.clearAllMocks() - }) - - it("should call listAndCount with the default config", async () => { - await request( - "GET", - `/admin/products/${IdMap.getId("product1")}/variants`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - - expect(ProductVariantServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(ProductVariantServiceMock.listAndCount).toHaveBeenCalledWith( - { - product_id: IdMap.getId("product1"), - }, - expect.objectContaining({ - relations: defaultAdminGetProductsVariantsRelations, - select: defaultAdminGetProductsVariantsFields, - skip: 0, - take: 100, - }) - ) - }) - - it("should call listAndCount with the provided query params", async () => { - await request( - "GET", - `/admin/products/${IdMap.getId("product1")}/variants`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - query: { - expand: "product", - fields: "id", - limit: 10, - }, - } - ) - - expect(ProductVariantServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(ProductVariantServiceMock.listAndCount).toHaveBeenLastCalledWith( - { - product_id: IdMap.getId("product1"), - }, - expect.objectContaining({ - relations: ["product"], - select: ["id", "created_at"], - skip: 0, - take: 10, - }) - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/update-option.js b/packages/medusa/src/api/routes/admin/products/__tests__/update-option.js deleted file mode 100644 index 333774a0f3..0000000000 --- a/packages/medusa/src/api/routes/admin/products/__tests__/update-option.js +++ /dev/null @@ -1,43 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductServiceMock } from "../../../../../services/__mocks__/product" - -describe("POST /admin/products/:id/options/:optionId", () => { - describe("successfully updates an option", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/products/${IdMap.getId( - "productWithOptions" - )}/options/${IdMap.getId("option1")}`, - { - payload: { - title: "Updated option title", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls update", () => { - expect(ProductServiceMock.updateOption).toHaveBeenCalledTimes(1) - expect(ProductServiceMock.updateOption).toHaveBeenCalledWith( - IdMap.getId("productWithOptions"), - IdMap.getId("option1"), - { - title: "Updated option title", - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/update-product.js b/packages/medusa/src/api/routes/admin/products/__tests__/update-product.js deleted file mode 100644 index aae3c7479d..0000000000 --- a/packages/medusa/src/api/routes/admin/products/__tests__/update-product.js +++ /dev/null @@ -1,79 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductServiceMock } from "../../../../../services/__mocks__/product" -import { ProductVariantServiceMock } from "../../../../../services/__mocks__/product-variant" - -describe("POST /admin/products/:id", () => { - describe("successfully updates a product", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/products/${IdMap.getId("multipleVariants")}`, - { - payload: { - title: "Product 1", - description: "Updated test description", - handle: "handle", - variants: [ - { id: IdMap.getId("testVariant"), title: "Green" }, - { title: "Blue" }, - { title: "Yellow" }, - ], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls update", () => { - expect(ProductServiceMock.update).toHaveBeenCalledTimes(1) - expect(ProductServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("multipleVariants"), - expect.objectContaining({ - title: "Product 1", - description: "Updated test description", - handle: "handle", - }) - ) - }) - - it("successfully updates variants and create new ones", async () => { - expect(ProductVariantServiceMock.update).toHaveBeenCalledTimes(1) - expect(ProductVariantServiceMock.create).toHaveBeenCalledTimes(1) - }) - }) - - describe("handles failed update operation", () => { - it("throws on wrong variant in update", async () => { - const subject = await request( - "POST", - `/admin/products/${IdMap.getId("variantsWithPrices")}`, - { - payload: { - title: "Product 1", - variants: [{ id: "test_321", title: "Green" }], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - expect(subject.status).toEqual(404) - expect(subject.error.text).toEqual( - `{"type":"not_found","message":"Variants with id: test_321 are not associated with this product"}` - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/products/__tests__/update-variant.js b/packages/medusa/src/api/routes/admin/products/__tests__/update-variant.js deleted file mode 100644 index 5ffbdac1f4..0000000000 --- a/packages/medusa/src/api/routes/admin/products/__tests__/update-variant.js +++ /dev/null @@ -1,67 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductVariantServiceMock } from "../../../../../services/__mocks__/product-variant" - -describe("POST /admin/products/:id/variants/:variantId", () => { - describe("successful updates variant prices", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request( - "POST", - `/admin/products/${IdMap.getId( - "productWithOptions" - )}/variants/${IdMap.getId("variant1")}`, - { - payload: { - title: "hi", - prices: [ - { - region_id: IdMap.getId("region-fr"), - amount: 100, - }, - { - currency_code: "DKK", - amount: 100, - }, - ], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("filters prices", () => { - expect(ProductVariantServiceMock.update).toHaveBeenCalledTimes(1) - expect(ProductVariantServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("variant1"), - expect.objectContaining({ - title: "hi", - prices: [ - { - region_id: IdMap.getId("region-fr"), - amount: 100, - }, - { - currency_code: "DKK", - amount: 100, - }, - ], - }) - ) - }) - - it("returns decorated product with variant removed", () => { - expect(subject.body.product.id).toEqual(IdMap.getId("productWithOptions")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/products/add-option.ts b/packages/medusa/src/api/routes/admin/products/add-option.ts deleted file mode 100644 index 674ddbeaef..0000000000 --- a/packages/medusa/src/api/routes/admin/products/add-option.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { PricingService, ProductService } from "../../../../services" -import { defaultAdminProductFields, defaultAdminProductRelations } from "." - -import { EntityManager } from "typeorm" -import { IsString } from "class-validator" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/products/{id}/options - * operationId: "PostProductsProductOptions" - * summary: "Add a Product Option" - * description: "Add a Product Option to a Product." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Product. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostProductsProductOptionsReq" - * x-codegen: - * method: addOption - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.addOption(productId, { - * title: "Size" - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateProductOption } from "medusa-react" - * - * type Props = { - * productId: string - * } - * - * const CreateProductOption = ({ productId }: Props) => { - * const createOption = useAdminCreateProductOption( - * productId - * ) - * // ... - * - * const handleCreate = ( - * title: string - * ) => { - * createOption.mutate({ - * title - * }, { - * onSuccess: ({ product }) => { - * console.log(product.options) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateProductOption - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/products/{id}/options' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "title": "Size" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = await validator( - AdminPostProductsProductOptionsReq, - req.body - ) - - const productService: ProductService = req.scope.resolve("productService") - const pricingService: PricingService = req.scope.resolve("pricingService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await productService - .withTransaction(transactionManager) - .addOption(id, validated.title) - }) - - const rawProduct = await productService.retrieve(id, { - select: defaultAdminProductFields, - relations: defaultAdminProductRelations, - }) - - const [product] = await pricingService.setAdminProductPricing([rawProduct]) - - res.json({ product }) -} - -/** - * @schema AdminPostProductsProductOptionsReq - * type: object - * description: "The details of the product option to create." - * required: - * - title - * properties: - * title: - * description: "The title the Product Option." - * type: string - * example: "Size" - */ -export class AdminPostProductsProductOptionsReq { - @IsString() - title: string -} diff --git a/packages/medusa/src/api/routes/admin/products/create-product.ts b/packages/medusa/src/api/routes/admin/products/create-product.ts deleted file mode 100644 index eb6abdd881..0000000000 --- a/packages/medusa/src/api/routes/admin/products/create-product.ts +++ /dev/null @@ -1,777 +0,0 @@ -import { Workflows, createProducts } from "@medusajs/core-flows" -import { IInventoryService, WorkflowTypes } from "@medusajs/types" -import { - IsArray, - IsBoolean, - IsEnum, - IsNumber, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { - defaultAdminProductFields, - defaultAdminProductRelations, - defaultAdminProductRemoteQueryObject, -} from "." -import { featureFlagRouter } from "../../../../loaders/feature-flags" -import { - PricingService, - ProductService, - ProductVariantInventoryService, - ProductVariantService, - SalesChannelService, - ShippingProfileService, -} from "../../../../services" -import { - ProductProductCategoryReq, - ProductSalesChannelReq, - ProductTagReq, - ProductTypeReq, -} from "../../../../types/product" -import { - CreateProductVariantInput, - ProductVariantPricesCreateReq, -} from "../../../../types/product-variant" -import { - createVariantsTransaction, - revertVariantTransaction, -} from "./transaction/create-product-variant" - -import { DistributedTransaction } from "@medusajs/orchestration" -import { FlagRouter, MedusaV2Flag, promiseAll } from "@medusajs/utils" -import { Type } from "class-transformer" -import { EntityManager } from "typeorm" -import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" -import { ProductStatus } from "../../../../models" -import { Logger } from "../../../../types/global" -import { retrieveProduct, validator } from "../../../../utils" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" - -/** - * @oas [post] /admin/products - * operationId: "PostProducts" - * summary: "Create a Product" - * x-authenticated: true - * description: "Create a new Product. This API Route can also be used to create a gift card if the `is_giftcard` field is set to `true`." - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostProductsReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.create({ - * title: "Shirt", - * is_giftcard: false, - * discountable: true - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateProduct } from "medusa-react" - * - * type CreateProductData = { - * title: string - * is_giftcard: boolean - * discountable: boolean - * options: { - * title: string - * }[] - * variants: { - * title: string - * prices: { - * amount: number - * currency_code :string - * }[] - * options: { - * value: string - * }[] - * }[], - * collection_id: string - * categories: { - * id: string - * }[] - * type: { - * value: string - * } - * tags: { - * value: string - * }[] - * } - * - * const CreateProduct = () => { - * const createProduct = useAdminCreateProduct() - * // ... - * - * const handleCreate = (productData: CreateProductData) => { - * createProduct.mutate(productData, { - * onSuccess: ({ product }) => { - * console.log(product.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateProduct - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/products' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "title": "Shirt" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminPostProductsReq, req.body) - - const logger: Logger = req.scope.resolve("logger") - const productService: ProductService = req.scope.resolve("productService") - const pricingService: PricingService = req.scope.resolve("pricingService") - const productVariantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - const shippingProfileService: ShippingProfileService = req.scope.resolve( - "shippingProfileService" - ) - const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter") - - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - const inventoryService: IInventoryService | undefined = - req.scope.resolve("inventoryService") - - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - - const entityManager: EntityManager = req.scope.resolve("manager") - const productModuleService = req.scope.resolve("productModuleService") - const isMedusaV2Enabled = featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key) - - if (isMedusaV2Enabled && !productModuleService) { - logger.warn( - `Cannot run ${Workflows.CreateProducts} workflow without '@medusajs/product' installed` - ) - } - - let product - - if (isMedusaV2Enabled && !!productModuleService) { - const createProductWorkflow = createProducts(req.scope) - - const input = { - products: [ - validated, - ] as WorkflowTypes.ProductWorkflow.CreateProductInputDTO[], - } - - const { result } = await createProductWorkflow.run({ - input, - context: { - manager: entityManager, - }, - }) - product = result[0] - } else { - product = await entityManager.transaction(async (manager) => { - const { variants } = validated - delete validated.variants - - if (!validated.thumbnail && validated.images && validated.images.length) { - validated.thumbnail = validated.images[0] - } - - let shippingProfile - // Get default shipping profile - if (validated.is_giftcard) { - shippingProfile = await shippingProfileService - .withTransaction(manager) - .retrieveGiftCardDefault() - } else { - shippingProfile = await shippingProfileService - .withTransaction(manager) - .retrieveDefault() - } - - // Provided that the feature flag is enabled and - // no sales channels are available, set the default one - if ( - featureFlagRouter.isFeatureEnabled(SalesChannelFeatureFlag.key) && - !validated?.sales_channels?.length - ) { - const defaultSalesChannel = await salesChannelService - .withTransaction(manager) - .retrieveDefault() - validated.sales_channels = [defaultSalesChannel] - } - - const newProduct = await productService - .withTransaction(manager) - .create({ ...validated, profile_id: shippingProfile.id }) - - if (variants) { - for (const [index, variant] of variants.entries()) { - variant["variant_rank"] = index - } - - const optionIds = - validated?.options?.map( - (o) => newProduct.options.find((newO) => newO.title === o.title)?.id - ) || [] - - const allVariantTransactions: DistributedTransaction[] = [] - const transactionDependencies = { - manager, - inventoryService, - productVariantInventoryService, - productVariantService, - } - - try { - const variantsInputData = variants.map((variant) => { - const options = - variant?.options?.map((option, index) => ({ - ...option, - option_id: optionIds[index], - })) || [] - - return { - ...variant, - options, - } as CreateProductVariantInput - }) - - const varTransaction = await createVariantsTransaction( - transactionDependencies, - newProduct.id, - variantsInputData - ) - allVariantTransactions.push(varTransaction) - } catch (e) { - await promiseAll( - allVariantTransactions.map(async (transaction) => { - await revertVariantTransaction( - transactionDependencies, - transaction - ).catch(() => logger.warn("Transaction couldn't be reverted.")) - }) - ) - - throw e - } - } - - return newProduct - }) - } - - let rawProduct - if (isMedusaV2Enabled) { - rawProduct = await retrieveProduct( - req.scope, - product.id, - defaultAdminProductRemoteQueryObject - ) - } else { - rawProduct = await productService.retrieve(product.id, { - select: defaultAdminProductFields, - relations: defaultAdminProductRelations, - }) - } - - const [pricedProduct] = await pricingService.setAdminProductPricing([ - rawProduct, - ]) - - res.json({ product: pricedProduct }) -} - -class ProductVariantOptionReq { - @IsString() - value: string -} - -class ProductOptionReq { - @IsString() - title: string -} - -class ProductVariantReq { - @IsString() - title: string - - @IsString() - @IsOptional() - sku?: string - - @IsString() - @IsOptional() - ean?: string - - @IsString() - @IsOptional() - upc?: string - - @IsString() - @IsOptional() - barcode?: string - - @IsString() - @IsOptional() - hs_code?: string - - @IsNumber() - @IsOptional() - inventory_quantity?: number = 0 - - @IsBoolean() - @IsOptional() - allow_backorder?: boolean - - @IsBoolean() - @IsOptional() - manage_inventory?: boolean - - @IsNumber() - @IsOptional() - weight?: number - - @IsNumber() - @IsOptional() - length?: number - - @IsNumber() - @IsOptional() - height?: number - - @IsNumber() - @IsOptional() - width?: number - - @IsString() - @IsOptional() - origin_country?: string - - @IsString() - @IsOptional() - mid_code?: string - - @IsString() - @IsOptional() - material?: string - - @IsObject() - @IsOptional() - metadata?: Record - - @IsArray() - @ValidateNested({ each: true }) - @Type(() => ProductVariantPricesCreateReq) - prices: ProductVariantPricesCreateReq[] - - @IsOptional() - @Type(() => ProductVariantOptionReq) - @ValidateNested({ each: true }) - @IsArray() - options?: ProductVariantOptionReq[] = [] -} - -/** - * @schema AdminPostProductsReq - * type: object - * description: "The details of the product to create." - * required: - * - title - * properties: - * title: - * description: "The title of the Product" - * type: string - * subtitle: - * description: "The subtitle of the Product" - * type: string - * description: - * description: "The description of the Product." - * type: string - * is_giftcard: - * description: A flag to indicate if the Product represents a Gift Card. Purchasing Products with this flag set to `true` will result in a Gift Card being created. - * type: boolean - * default: false - * discountable: - * description: A flag to indicate if discounts can be applied to the Line Items generated from this Product - * type: boolean - * default: true - * images: - * description: An array of images of the Product. Each value in the array is a URL to the image. You can use the upload API Routes to upload the image and obtain a URL. - * type: array - * items: - * type: string - * thumbnail: - * description: The thumbnail to use for the Product. The value is a URL to the thumbnail. You can use the upload API Routes to upload the thumbnail and obtain a URL. - * type: string - * handle: - * description: A unique handle to identify the Product by. If not provided, the kebab-case version of the product title will be used. This can be used as a slug in URLs. - * type: string - * status: - * description: The status of the product. The product is shown to the customer only if its status is `published`. - * type: string - * enum: [draft, proposed, published, rejected] - * default: draft - * type: - * description: The Product Type to associate the Product with. - * type: object - * required: - * - value - * properties: - * id: - * description: The ID of an existing Product Type. If not provided, a new product type will be created. - * type: string - * value: - * description: The value of the Product Type. - * type: string - * collection_id: - * description: The ID of the Product Collection the Product belongs to. - * type: string - * tags: - * description: Product Tags to associate the Product with. - * type: array - * items: - * type: object - * required: - * - value - * properties: - * id: - * description: The ID of an existing Product Tag. If not provided, a new product tag will be created. - * type: string - * value: - * description: The value of the Tag. If the `id` is provided, the value of the existing tag will be updated. - * type: string - * sales_channels: - * description: "Sales channels to associate the Product with." - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * description: The ID of an existing Sales channel. - * type: string - * categories: - * description: "Product categories to add the Product to." - * x-featureFlag: "product_categories" - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * description: The ID of a Product Category. - * type: string - * options: - * description: The Options that the Product should have. A new product option will be created for every item in the array. - * type: array - * items: - * type: object - * required: - * - title - * properties: - * title: - * description: The title of the Product Option. - * type: string - * variants: - * description: An array of Product Variants to create with the Product. Each product variant must have a unique combination of Product Option values. - * type: array - * items: - * type: object - * required: - * - title - * properties: - * title: - * description: The title of the Product Variant. - * type: string - * sku: - * description: The unique SKU of the Product Variant. - * type: string - * ean: - * description: The EAN number of the item. - * type: string - * upc: - * description: The UPC number of the item. - * type: string - * barcode: - * description: A generic GTIN field of the Product Variant. - * type: string - * hs_code: - * description: The Harmonized System code of the Product Variant. - * type: string - * inventory_quantity: - * description: The amount of stock kept of the Product Variant. - * type: integer - * default: 0 - * allow_backorder: - * description: Whether the Product Variant can be purchased when out of stock. - * type: boolean - * manage_inventory: - * description: Whether Medusa should keep track of the inventory of this Product Variant. - * type: boolean - * weight: - * description: The wieght of the Product Variant. - * type: number - * length: - * description: The length of the Product Variant. - * type: number - * height: - * description: The height of the Product Variant. - * type: number - * width: - * description: The width of the Product Variant. - * type: number - * origin_country: - * description: The country of origin of the Product Variant. - * type: string - * mid_code: - * description: The Manufacturer Identification code of the Product Variant. - * type: string - * material: - * description: The material composition of the Product Variant. - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * prices: - * type: array - * description: An array of product variant prices. A product variant can have different prices for each region or currency code. - * externalDocs: - * url: https://docs.medusajs.com/modules/products/admin/manage-products#product-variant-prices - * description: Product variant pricing. - * items: - * type: object - * required: - * - amount - * properties: - * region_id: - * description: The ID of the Region the price will be used in. This is only required if `currency_code` is not provided. - * type: string - * currency_code: - * description: The 3 character ISO currency code the price will be used in. This is only required if `region_id` is not provided. - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * amount: - * description: The price amount. - * type: integer - * min_quantity: - * description: The minimum quantity required to be added to the cart for the price to be used. - * type: integer - * max_quantity: - * description: The maximum quantity required to be added to the cart for the price to be used. - * type: integer - * options: - * type: array - * description: An array of Product Option values that the variant corresponds to. The option values should be added into the array in the same index as in the `options` field of the product. - * externalDocs: - * url: https://docs.medusajs.com/modules/products/admin/manage-products#create-a-product - * description: Example of how to create a product with options and variants - * items: - * type: object - * required: - * - value - * properties: - * value: - * description: The value to give for the Product Option at the same index in the Product's `options` field. - * type: string - * weight: - * description: The weight of the Product. - * type: number - * length: - * description: The length of the Product. - * type: number - * height: - * description: The height of the Product. - * type: number - * width: - * description: The width of the Product. - * type: number - * hs_code: - * description: The Harmonized System code of the Product. - * type: string - * origin_country: - * description: The country of origin of the Product. - * type: string - * mid_code: - * description: The Manufacturer Identification code of the Product. - * type: string - * material: - * description: The material composition of the Product. - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostProductsReq { - @IsString() - title: string - - @IsString() - @IsOptional() - subtitle?: string - - @IsString() - @IsOptional() - description?: string - - @IsBoolean() - is_giftcard = false - - @IsBoolean() - discountable = true - - @IsArray() - @IsOptional() - images?: string[] - - @IsString() - @IsOptional() - thumbnail?: string - - @IsString() - @IsOptional() - handle?: string - - @IsOptional() - @IsEnum(ProductStatus) - status?: ProductStatus = ProductStatus.DRAFT - - @IsOptional() - @Type(() => ProductTypeReq) - @ValidateNested() - type?: ProductTypeReq - - @IsOptional() - @IsString() - collection_id?: string - - @IsOptional() - @Type(() => ProductTagReq) - @ValidateNested({ each: true }) - @IsArray() - tags?: ProductTagReq[] - - @FeatureFlagDecorators(SalesChannelFeatureFlag.key, [ - IsOptional(), - Type(() => ProductSalesChannelReq), - ValidateNested({ each: true }), - IsArray(), - ]) - sales_channels?: ProductSalesChannelReq[] - - @IsOptional() - @Type(() => ProductProductCategoryReq) - @ValidateNested({ each: true }) - @IsArray() - categories?: ProductProductCategoryReq[] - - @IsOptional() - @Type(() => ProductOptionReq) - @ValidateNested({ each: true }) - @IsArray() - options?: ProductOptionReq[] - - @IsOptional() - @Type(() => ProductVariantReq) - @ValidateNested({ each: true }) - @IsArray() - variants?: ProductVariantReq[] - - @IsNumber() - @IsOptional() - weight?: number - - @IsNumber() - @IsOptional() - length?: number - - @IsNumber() - @IsOptional() - height?: number - - @IsNumber() - @IsOptional() - width?: number - - @IsString() - @IsOptional() - hs_code?: string - - @IsString() - @IsOptional() - origin_country?: string - - @IsString() - @IsOptional() - mid_code?: string - - @IsString() - @IsOptional() - material?: string - - @IsObject() - @IsOptional() - metadata?: Record - - constructor() { - if (!featureFlagRouter.isFeatureEnabled(SalesChannelFeatureFlag.key)) { - delete this.sales_channels - } - } -} diff --git a/packages/medusa/src/api/routes/admin/products/create-variant.ts b/packages/medusa/src/api/routes/admin/products/create-variant.ts deleted file mode 100644 index 2caa26d68d..0000000000 --- a/packages/medusa/src/api/routes/admin/products/create-variant.ts +++ /dev/null @@ -1,433 +0,0 @@ -import { CreateProductVariants } from "@medusajs/core-flows" -import { IInventoryService, WorkflowTypes } from "@medusajs/types" -import { FlagRouter, MedusaV2Flag } from "@medusajs/utils" -import { Type } from "class-transformer" -import { - IsArray, - IsBoolean, - IsNumber, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { EntityManager } from "typeorm" -import { - defaultAdminProductFields, - defaultAdminProductRelations, - defaultAdminProductRemoteQueryObject, -} from "." -import { - PricingService, - ProductService, - ProductVariantInventoryService, - ProductVariantService, -} from "../../../../services" -import { - CreateProductVariantInput, - ProductVariantPricesCreateReq, -} from "../../../../types/product-variant" -import { retrieveProduct, validator } from "../../../../utils" -import { createVariantsTransaction } from "./transaction/create-product-variant" - -/** - * @oas [post] /admin/products/{id}/variants - * operationId: "PostProductsProductVariants" - * summary: "Create a Product Variant" - * description: "Create a Product Variant associated with a Product. Each product variant must have a unique combination of Product Option values." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Product. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostProductsProductVariantsReq" - * x-codegen: - * method: createVariant - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.createVariant(productId, { - * title: "Color", - * prices: [ - * { - * amount: 1000, - * currency_code: "eur" - * } - * ], - * options: [ - * { - * option_id, - * value: "S" - * } - * ], - * inventory_quantity: 100 - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateVariant } from "medusa-react" - * - * type CreateVariantData = { - * title: string - * prices: { - * amount: number - * currency_code: string - * }[] - * options: { - * option_id: string - * value: string - * }[] - * } - * - * type Props = { - * productId: string - * } - * - * const CreateProductVariant = ({ productId }: Props) => { - * const createVariant = useAdminCreateVariant( - * productId - * ) - * // ... - * - * const handleCreate = ( - * variantData: CreateVariantData - * ) => { - * createVariant.mutate(variantData, { - * onSuccess: ({ product }) => { - * console.log(product.variants) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateProductVariant - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/products/{id}/variants' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "title": "Color", - * "prices": [ - * { - * "amount": 1000, - * "currency_code": "eur" - * } - * ], - * "options": [ - * { - * "option_id": "asdasf", - * "value": "S" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const { id } = req.params - - const validated = await validator( - AdminPostProductsProductVariantsReq, - req.body - ) - - const manager: EntityManager = req.scope.resolve("manager") - const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter") - const inventoryService: IInventoryService | undefined = - req.scope.resolve("inventoryService") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - const productVariantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - const pricingService: PricingService = req.scope.resolve("pricingService") - let rawProduct - - if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) { - const createVariantsWorkflow = CreateProductVariants.createProductVariants( - req.scope - ) - - const input = { - productVariants: [ - { - product_id: id, - ...validated, - }, - ] as WorkflowTypes.ProductWorkflow.CreateProductVariantsInputDTO[], - } - - await createVariantsWorkflow.run({ - input, - context: { - manager, - }, - }) - - rawProduct = await retrieveProduct( - req.scope, - id, - defaultAdminProductRemoteQueryObject - ) - } else { - await manager.transaction(async (transactionManager) => { - await createVariantsTransaction( - { - manager: transactionManager, - inventoryService, - productVariantInventoryService, - productVariantService, - }, - id, - [validated as CreateProductVariantInput] - ) - }) - - const productService: ProductService = req.scope.resolve("productService") - - rawProduct = await productService.retrieve(id, { - select: defaultAdminProductFields, - relations: defaultAdminProductRelations, - }) - } - - const [product] = await pricingService.setAdminProductPricing([rawProduct]) - - res.json({ product }) -} - -class ProductVariantOptionReq { - @IsString() - value: string - - @IsString() - option_id: string -} - -/** - * @schema AdminPostProductsProductVariantsReq - * type: object - * description: "The details of the product variant to create." - * required: - * - title - * - prices - * - options - * properties: - * title: - * description: The title of the product variant. - * type: string - * sku: - * description: The unique SKU of the product variant. - * type: string - * ean: - * description: The EAN number of the product variant. - * type: string - * upc: - * description: The UPC number of the product variant. - * type: string - * barcode: - * description: A generic GTIN field of the product variant. - * type: string - * hs_code: - * description: The Harmonized System code of the product variant. - * type: string - * inventory_quantity: - * description: The amount of stock kept of the product variant. - * type: integer - * default: 0 - * allow_backorder: - * description: Whether the product variant can be purchased when out of stock. - * type: boolean - * manage_inventory: - * description: Whether Medusa should keep track of the inventory of this product variant. - * type: boolean - * default: true - * weight: - * description: The wieght of the product variant. - * type: number - * length: - * description: The length of the product variant. - * type: number - * height: - * description: The height of the product variant. - * type: number - * width: - * description: The width of the product variant. - * type: number - * origin_country: - * description: The country of origin of the product variant. - * type: string - * mid_code: - * description: The Manufacturer Identification code of the product variant. - * type: string - * material: - * description: The material composition of the product variant. - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * prices: - * type: array - * description: An array of product variant prices. A product variant can have different prices for each region or currency code. - * externalDocs: - * url: https://docs.medusajs.com/modules/products/admin/manage-products#product-variant-prices - * description: Product variant pricing. - * items: - * type: object - * required: - * - amount - * properties: - * region_id: - * description: The ID of the Region the price will be used in. This is only required if `currency_code` is not provided. - * type: string - * currency_code: - * description: The 3 character ISO currency code the price will be used in. This is only required if `region_id` is not provided. - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * amount: - * description: The price amount. - * type: integer - * min_quantity: - * description: The minimum quantity required to be added to the cart for the price to be used. - * type: integer - * max_quantity: - * description: The maximum quantity required to be added to the cart for the price to be used. - * type: integer - * options: - * type: array - * description: An array of Product Option values that the variant corresponds to. - * items: - * type: object - * required: - * - option_id - * - value - * properties: - * option_id: - * description: The ID of the Product Option. - * type: string - * value: - * description: A value to give to the Product Option. - * type: string - */ -export class AdminPostProductsProductVariantsReq { - @IsString() - title: string - - @IsString() - @IsOptional() - sku?: string - - @IsString() - @IsOptional() - ean?: string - - @IsString() - @IsOptional() - upc?: string - - @IsString() - @IsOptional() - barcode?: string - - @IsString() - @IsOptional() - hs_code?: string - - @IsNumber() - @IsOptional() - inventory_quantity?: number = 0 - - @IsBoolean() - @IsOptional() - allow_backorder?: boolean - - @IsBoolean() - @IsOptional() - manage_inventory?: boolean = true - - @IsNumber() - @IsOptional() - weight?: number - - @IsNumber() - @IsOptional() - length?: number - - @IsNumber() - @IsOptional() - height?: number - - @IsNumber() - @IsOptional() - width?: number - - @IsString() - @IsOptional() - origin_country?: string - - @IsString() - @IsOptional() - mid_code?: string - - @IsString() - @IsOptional() - material?: string - - @IsObject() - @IsOptional() - metadata?: Record - - @IsArray() - @ValidateNested({ each: true }) - @Type(() => ProductVariantPricesCreateReq) - prices: ProductVariantPricesCreateReq[] - - @IsOptional() - @Type(() => ProductVariantOptionReq) - @ValidateNested({ each: true }) - @IsArray() - options?: ProductVariantOptionReq[] = [] -} diff --git a/packages/medusa/src/api/routes/admin/products/delete-option.ts b/packages/medusa/src/api/routes/admin/products/delete-option.ts deleted file mode 100644 index aab25889f8..0000000000 --- a/packages/medusa/src/api/routes/admin/products/delete-option.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { defaultAdminProductFields, defaultAdminProductRelations } from "." - -import { EntityManager } from "typeorm" -import { ProductService } from "../../../../services" - -/** - * @oas [delete] /admin/products/{id}/options/{option_id} - * operationId: "DeleteProductsProductOptionsOption" - * summary: "Delete a Product Option" - * description: "Delete a Product Option. If there are product variants that use this product option, they must be deleted before deleting the product option." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Product. - * - (path) option_id=* {string} The ID of the Product Option. - * x-codegen: - * method: deleteOption - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.deleteOption(productId, optionId) - * .then(({ option_id, object, deleted, product }) => { - * console.log(product.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteProductOption } from "medusa-react" - * - * type Props = { - * productId: string - * optionId: string - * } - * - * const ProductOption = ({ - * productId, - * optionId - * }: Props) => { - * const deleteOption = useAdminDeleteProductOption( - * productId - * ) - * // ... - * - * const handleDelete = () => { - * deleteOption.mutate(optionId, { - * onSuccess: ({ option_id, object, deleted, product }) => { - * console.log(product.options) - * } - * }) - * } - * - * // ... - * } - * - * export default ProductOption - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/products/{id}/options/{option_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsDeleteOptionRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, option_id } = req.params - - const productService: ProductService = req.scope.resolve("productService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await productService - .withTransaction(transactionManager) - .deleteOption(id, option_id) - }) - - const data = await productService.retrieve(id, { - select: defaultAdminProductFields, - relations: defaultAdminProductRelations, - }) - - res.json({ - option_id, - object: "option", - deleted: true, - product: data, - }) -} diff --git a/packages/medusa/src/api/routes/admin/products/delete-product.ts b/packages/medusa/src/api/routes/admin/products/delete-product.ts deleted file mode 100644 index 091757e6ef..0000000000 --- a/packages/medusa/src/api/routes/admin/products/delete-product.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { EntityManager } from "typeorm" -import { ProductService } from "../../../../services" - -/** - * @oas [delete] /admin/products/{id} - * operationId: "DeleteProductsProduct" - * summary: "Delete a Product" - * description: "Delete a Product and its associated product variants and options." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Product. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.delete(productId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteProduct } from "medusa-react" - * - * type Props = { - * productId: string - * } - * - * const Product = ({ productId }: Props) => { - * const deleteProduct = useAdminDeleteProduct( - * productId - * ) - * // ... - * - * const handleDelete = () => { - * deleteProduct.mutate(void 0, { - * onSuccess: ({ id, object, deleted}) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Product - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/products/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const productService: ProductService = req.scope.resolve("productService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await productService.withTransaction(transactionManager).delete(id) - }) - - res.json({ - id, - object: "product", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/products/delete-variant.ts b/packages/medusa/src/api/routes/admin/products/delete-variant.ts deleted file mode 100644 index 32209c14f5..0000000000 --- a/packages/medusa/src/api/routes/admin/products/delete-variant.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { - PricingService, - ProductService, - ProductVariantService, -} from "../../../../services" -import { defaultAdminProductFields, defaultAdminProductRelations } from "." - -import { EntityManager } from "typeorm" - -/** - * @oas [delete] /admin/products/{id}/variants/{variant_id} - * operationId: "DeleteProductsProductVariantsVariant" - * summary: "Delete a Product Variant" - * description: "Delete a Product Variant." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Product. - * - (path) variant_id=* {string} The ID of the Product Variant. - * x-codegen: - * method: deleteVariant - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.deleteVariant(productId, variantId) - * .then(({ variant_id, object, deleted, product }) => { - * console.log(product.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteVariant } from "medusa-react" - * - * type Props = { - * productId: string - * variantId: string - * } - * - * const ProductVariant = ({ - * productId, - * variantId - * }: Props) => { - * const deleteVariant = useAdminDeleteVariant( - * productId - * ) - * // ... - * - * const handleDelete = () => { - * deleteVariant.mutate(variantId, { - * onSuccess: ({ variant_id, object, deleted, product }) => { - * console.log(product.variants) - * } - * }) - * } - * - * // ... - * } - * - * export default ProductVariant - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/products/{id}/variants/{variant_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsDeleteVariantRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, variant_id } = req.params - - const productVariantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - const productService: ProductService = req.scope.resolve("productService") - const pricingService: PricingService = req.scope.resolve("pricingService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - await productVariantService - .withTransaction(transactionManager) - .delete(variant_id) - }) - - const data = await productService.retrieve(id, { - select: defaultAdminProductFields, - relations: defaultAdminProductRelations, - }) - - const [product] = await pricingService.setAdminProductPricing([data]) - - res.json({ - variant_id, - object: "product-variant", - deleted: true, - product, - }) -} diff --git a/packages/medusa/src/api/routes/admin/products/get-product.ts b/packages/medusa/src/api/routes/admin/products/get-product.ts deleted file mode 100644 index c987b1dae2..0000000000 --- a/packages/medusa/src/api/routes/admin/products/get-product.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { - PricingService, - ProductService, - ProductVariantInventoryService, - SalesChannelService, -} from "../../../../services" - -import { MedusaV2Flag, promiseAll } from "@medusajs/utils" -import { FindParams } from "../../../../types/common" -import { retrieveProduct } from "../../../../utils" -import { defaultAdminProductRemoteQueryObject } from "./index" - -/** - * @oas [get] /admin/products/{id} - * operationId: "GetProductsProduct" - * summary: "Get a Product" - * description: "Retrieve a Product's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Product. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.retrieve(productId) - * .then(({ product }) => { - * console.log(product.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminProduct } from "medusa-react" - * - * type Props = { - * productId: string - * } - * - * const Product = ({ productId }: Props) => { - * const { - * product, - * isLoading, - * } = useAdminProduct(productId) - * - * return ( - *
- * {isLoading && Loading...} - * {product && {product.title}} - * - *
- * ) - * } - * - * export default Product - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/products/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const productService: ProductService = req.scope.resolve("productService") - const pricingService: PricingService = req.scope.resolve("pricingService") - const featureFlagRouter = req.scope.resolve("featureFlagRouter") - const isMedusaV2FlagOn = featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key) - - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - let rawProduct - if (isMedusaV2FlagOn) { - rawProduct = await retrieveProduct( - req.scope, - id, - defaultAdminProductRemoteQueryObject - ) - } else { - rawProduct = await productService.retrieve(id, req.retrieveConfig) - } - - // We only set prices if variants.prices are requested - const shouldSetPricing = ["variants", "variants.prices"].every((relation) => - req.retrieveConfig.relations?.includes(relation) - ) - - const product = rawProduct - - const decoratePromises: Promise[] = [] - if (shouldSetPricing) { - decoratePromises.push(pricingService.setAdminProductPricing([product])) - } - - const shouldSetAvailability = - req.retrieveConfig.relations?.includes("variants") - - if (shouldSetAvailability) { - let salesChannels - - if (isMedusaV2FlagOn) { - const remoteQuery = req.scope.resolve("remoteQuery") - const query = { - sales_channel: { - fields: ["id"], - }, - } - salesChannels = await remoteQuery(query) - } else { - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - ;[salesChannels] = await salesChannelService.listAndCount( - {}, - { select: ["id"] } - ) - } - - decoratePromises.push( - productVariantInventoryService.setProductAvailability( - [product], - salesChannels.map((salesChannel) => salesChannel.id) - ) - ) - } - await promiseAll(decoratePromises) - - res.json({ product }) -} - -export class AdminGetProductParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/products/index.ts b/packages/medusa/src/api/routes/admin/products/index.ts deleted file mode 100644 index 8c0c10b437..0000000000 --- a/packages/medusa/src/api/routes/admin/products/index.ts +++ /dev/null @@ -1,561 +0,0 @@ -import "reflect-metadata" - -import { Product, ProductTag, ProductType, ProductVariant } from "../../../.." -import { PaginatedResponse } from "../../../../types/common" -import middlewares, { transformQuery } from "../../../middlewares" - -import { FlagRouter } from "@medusajs/utils" -import { Router } from "express" -import { PricedProduct } from "../../../../types/pricing" -import { validateSalesChannelsExist } from "../../../middlewares/validators/sales-channel-existence" -import { AdminGetProductParams } from "./get-product" -import { AdminGetProductsParams } from "./list-products" -import { AdminGetProductsVariantsParams } from "./list-variants" - -const route = Router() - -export default (app, featureFlagRouter: FlagRouter) => { - app.use("/products", route) - - if (featureFlagRouter.isFeatureEnabled("sales_channels")) { - defaultAdminProductRelations.push("sales_channels") - } - - if (featureFlagRouter.isFeatureEnabled("product_categories")) { - defaultAdminProductRelations.push("categories") - } - - route.post( - "/", - validateSalesChannelsExist((req) => req.body?.sales_channels), - middlewares.wrap(require("./create-product").default) - ) - route.post( - "/:id", - validateSalesChannelsExist((req) => req.body?.sales_channels), - middlewares.wrap(require("./update-product").default) - ) - route.get("/types", middlewares.wrap(require("./list-types").default)) - route.get( - "/tag-usage", - middlewares.wrap(require("./list-tag-usage-count").default) - ) - - route.get( - "/:id/variants", - transformQuery(AdminGetProductsVariantsParams, { - defaultRelations: defaultAdminGetProductsVariantsRelations, - defaultFields: defaultAdminGetProductsVariantsFields, - isList: true, - }), - middlewares.wrap(require("./list-variants").default) - ) - route.post( - "/:id/variants", - middlewares.wrap(require("./create-variant").default) - ) - - route.post( - "/:id/variants/:variant_id", - middlewares.wrap(require("./update-variant").default) - ) - - route.post( - "/:id/options/:option_id", - middlewares.wrap(require("./update-option").default) - ) - route.post("/:id/options", middlewares.wrap(require("./add-option").default)) - - route.delete( - "/:id/variants/:variant_id", - middlewares.wrap(require("./delete-variant").default) - ) - route.delete("/:id", middlewares.wrap(require("./delete-product").default)) - route.delete( - "/:id/options/:option_id", - middlewares.wrap(require("./delete-option").default) - ) - - route.post( - "/:id/metadata", - middlewares.wrap(require("./set-metadata").default) - ) - route.get( - "/:id", - transformQuery(AdminGetProductParams, { - defaultRelations: defaultAdminProductRelations, - defaultFields: defaultAdminProductFields, - isList: false, - }), - middlewares.wrap(require("./get-product").default) - ) - - route.get( - "/", - transformQuery(AdminGetProductsParams, { - defaultRelations: defaultAdminProductRelations, - defaultFields: defaultAdminProductFields, - isList: true, - }), - middlewares.wrap(require("./list-products").default) - ) - - return app -} - -export const defaultAdminProductRelations = [ - "variants", - "variants.prices", - "variants.options", - "profiles", - "images", - "options", - "options.values", - "tags", - "type", - "collection", -] - -export const defaultAdminProductFields: (keyof Product)[] = [ - "id", - "title", - "subtitle", - "status", - "external_id", - "description", - "handle", - "is_giftcard", - "discountable", - "thumbnail", - "collection_id", - "type_id", - "weight", - "length", - "height", - "width", - "hs_code", - "origin_country", - "mid_code", - "material", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -export const defaultAdminGetProductsVariantsFields = [ - "id", - "product_id", - "title", - "sku", - "inventory_quantity", - "allow_backorder", - "manage_inventory", - "hs_code", - "origin_country", - "mid_code", - "material", - "weight", - "length", - "height", - "width", - "created_at", - "updated_at", - "deleted_at", - "metadata", - "variant_rank", - "ean", - "upc", - "barcode", -] - -export const defaultAdminGetProductsVariantsRelations = ["options", "prices"] - -/** - * This is temporary. - */ -export const defaultAdminProductRemoteQueryObject = { - fields: defaultAdminProductFields, - images: { - fields: ["id", "created_at", "updated_at", "deleted_at", "url", "metadata"], - }, - tags: { - fields: ["id", "created_at", "updated_at", "deleted_at", "value"], - }, - - type: { - fields: ["id", "created_at", "updated_at", "deleted_at", "value"], - }, - - collection: { - fields: ["title", "handle", "id", "created_at", "updated_at", "deleted_at"], - }, - - categories: { - fields: [ - "id", - "name", - "description", - "handle", - "is_active", - "is_internal", - "parent_category_id", - ], - }, - - options: { - fields: [ - "id", - "created_at", - "updated_at", - "deleted_at", - "title", - "product_id", - "metadata", - ], - values: { - fields: [ - "id", - "created_at", - "updated_at", - "deleted_at", - "value", - "option_id", - "variant_id", - "metadata", - ], - }, - }, - - variants: { - fields: [ - "id", - "created_at", - "updated_at", - "deleted_at", - "title", - "product_id", - "sku", - "barcode", - "ean", - "upc", - "variant_rank", - "inventory_quantity", - "allow_backorder", - "manage_inventory", - "hs_code", - "origin_country", - "mid_code", - "material", - "weight", - "length", - "height", - "width", - "metadata", - ], - - options: { - fields: [ - "id", - "created_at", - "updated_at", - "deleted_at", - "value", - "option_id", - "variant_id", - "metadata", - ], - }, - }, - profile: { - fields: ["id", "created_at", "updated_at", "deleted_at", "name", "type"], - }, - sales_channels: { - fields: [ - "id", - "name", - "description", - "is_disabled", - "created_at", - "updated_at", - "deleted_at", - "metadata", - ], - }, -} - -/** - * @schema AdminProductsDeleteOptionRes - * type: object - * description: "The details of deleting a product's option." - * x-expanded-relations: - * field: product - * relations: - * - collection - * - images - * - options - * - tags - * - type - * - variants - * - variants.options - * - variants.prices - * required: - * - option_id - * - object - * - deleted - * - product - * properties: - * option_id: - * type: string - * description: The ID of the deleted Product Option - * object: - * type: string - * description: The type of the object that was deleted. - * default: option - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - * product: - * description: Product details. - * $ref: "#/components/schemas/PricedProduct" - */ -export type AdminProductsDeleteOptionRes = { - option_id: string - object: "option" - deleted: boolean - product: Product -} - -/** - * @schema AdminProductsDeleteVariantRes - * type: object - * description: "The details of deleting a product's variant." - * x-expanded-relations: - * field: product - * relations: - * - collection - * - images - * - options - * - tags - * - type - * - variants - * - variants.options - * - variants.prices - * required: - * - variant_id - * - object - * - deleted - * - product - * properties: - * variant_id: - * type: string - * description: The ID of the deleted Product Variant. - * object: - * type: string - * description: The type of the object that was deleted. - * default: product-variant - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - * product: - * description: Product details. - * $ref: "#/components/schemas/PricedProduct" - */ -export type AdminProductsDeleteVariantRes = { - variant_id: string - object: "product-variant" - deleted: boolean - product: Product -} - -/** - * @schema AdminProductsDeleteRes - * type: object - * description: "The details of deleting a product." - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Product. - * object: - * type: string - * description: The type of the object that was deleted. - * default: product - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminProductsDeleteRes = { - id: string - object: "product" - deleted: boolean -} - -/** - * @schema AdminProductsListRes - * type: object - * description: "The list of products with pagination fields." - * x-expanded-relations: - * field: products - * relations: - * - collection - * - images - * - options - * - tags - * - type - * - variants - * - variants.options - * - variants.prices - * totals: - * - variants.purchasable - * required: - * - products - * - count - * - offset - * - limit - * properties: - * products: - * type: array - * description: An array of products details. - * items: - * $ref: "#/components/schemas/PricedProduct" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of products skipped when retrieving the products. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminProductsListRes = PaginatedResponse & { - products: (PricedProduct | Product)[] -} - -/** - * @schema AdminProductsListVariantsRes - * type: object - * required: - * - variants - * - count - * - offset - * - limit - * properties: - * variants: - * type: array - * description: An array of product variants details. - * items: - * $ref: "#/components/schemas/ProductVariant" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of product variants skipped when retrieving the product variants. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminProductsListVariantsRes = PaginatedResponse & { - variants: ProductVariant[] -} - -/** - * @schema AdminProductsListTypesRes - * type: object - * required: - * - types - * properties: - * types: - * type: array - * description: An array of product types details. - * items: - * $ref: "#/components/schemas/ProductType" - */ -export type AdminProductsListTypesRes = { - types: ProductType[] -} - -/** - * @schema AdminProductsListTagsRes - * type: object - * description: "The usage details of product tags." - * required: - * - tags - * properties: - * tags: - * description: An array of product tags details. - * type: array - * items: - * type: object - * required: - * - id - * - usage_count - * - value - * properties: - * id: - * description: The ID of the tag. - * type: string - * usage_count: - * description: The number of products that use this tag. - * type: string - * value: - * description: The value of the tag. - * type: string - */ -export type AdminProductsListTagsRes = { - tags: Array< - Pick & { - usage_count: number - } - > -} - -/** - * @schema AdminProductsRes - * type: object - * description: "The product's details." - * x-expanded-relations: - * field: product - * relations: - * - collection - * - images - * - options - * - tags - * - type - * - variants - * - variants.options - * - variants.prices - * required: - * - product - * properties: - * product: - * description: Product details. - * $ref: "#/components/schemas/PricedProduct" - */ -export type AdminProductsRes = { - product: Product -} - -export * from "./add-option" -export * from "./create-product" -export * from "./create-variant" -export * from "./delete-option" -export * from "./delete-product" -export * from "./delete-variant" -export * from "./get-product" -export * from "./list-products" -export * from "./list-tag-usage-count" -export * from "./list-types" -export * from "./list-variants" -export * from "./set-metadata" -export * from "./update-option" -export * from "./update-product" -export * from "./update-variant" diff --git a/packages/medusa/src/api/routes/admin/products/list-products.ts b/packages/medusa/src/api/routes/admin/products/list-products.ts deleted file mode 100644 index f1d9200090..0000000000 --- a/packages/medusa/src/api/routes/admin/products/list-products.ts +++ /dev/null @@ -1,370 +0,0 @@ -import { IsNumber, IsOptional, IsString } from "class-validator" -import { - PricingService, - ProductService, - ProductVariantInventoryService, - SalesChannelService, -} from "../../../../services" - -import { listProducts } from "../../../../utils" - -import { IInventoryService } from "@medusajs/types" -import { MedusaV2Flag } from "@medusajs/utils" -import { Type } from "class-transformer" -import { Product } from "../../../../models" -import { PricedProduct } from "../../../../types/pricing" -import { FilterableProductProps } from "../../../../types/product" - -/** - * @oas [get] /admin/products - * operationId: "GetProducts" - * summary: "List Products" - * description: "Retrieve a list of products. The products can be filtered by fields such as `q` or `status`. The products can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) q {string} term to search products' title, description, variants' title and sku, and collections' title. - * - (query) discount_condition_id {string} Filter by the ID of a discount condition. Only products that this discount condition is applied to will be retrieved. - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by product IDs. - * schema: - * oneOf: - * - type: string - * description: ID of the product. - * - type: array - * items: - * type: string - * description: ID of a product. - * - in: query - * name: status - * style: form - * explode: false - * description: Filter by status. - * schema: - * type: array - * items: - * type: string - * enum: [draft, proposed, published, rejected] - * - in: query - * name: collection_id - * style: form - * explode: false - * description: Filter by product collection IDs. Only products that are associated with the specified collections will be retrieved. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: tags - * style: form - * explode: false - * description: Filter by product tag IDs. Only products that are associated with the specified tags will be retrieved. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: price_list_id - * style: form - * explode: false - * description: Filter by IDs of price lists. Only products that these price lists are applied to will be retrieved. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: sales_channel_id - * style: form - * explode: false - * description: Filter by sales channel IDs. Only products that are available in the specified sales channels will be retrieved. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: type_id - * style: form - * explode: false - * description: Filter by product type IDs. Only products that are associated with the specified types will be retrieved. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: category_id - * style: form - * explode: false - * description: Filter by product category IDs. Only products that are associated with the specified categories will be retrieved. - * schema: - * type: array - * x-featureFlag: "product_categories" - * items: - * type: string - * - in: query - * name: include_category_children - * style: form - * explode: false - * description: whether to include product category children when filtering by `category_id` - * schema: - * type: boolean - * x-featureFlag: "product_categories" - * - (query) title {string} Filter by title. - * - (query) description {string} Filter by description. - * - (query) handle {string} Filter by handle. - * - (query) is_giftcard {boolean} Whether to retrieve gift cards or regular products. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: deleted_at - * description: Filter by a deletion date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - (query) offset=0 {integer} The number of products to skip when retrieving the products. - * - (query) limit=50 {integer} Limit the number of products returned. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned products. - * - (query) fields {string} Comma-separated fields that should be included in the returned products. - * - (query) order {string} A product field to sort-order the retrieved products by. - * x-codegen: - * method: list - * queryParams: AdminGetProductsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.list() - * .then(({ products, limit, offset, count }) => { - * console.log(products.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminProducts } from "medusa-react" - * - * const Products = () => { - * const { products, isLoading } = useAdminProducts() - * - * return ( - *
- * {isLoading && Loading...} - * {products && !products.length && No Products} - * {products && products.length > 0 && ( - *
    - * {products.map((product) => ( - *
  • {product.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Products - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/products' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const productService: ProductService = req.scope.resolve("productService") - const inventoryService: IInventoryService | undefined = - req.scope.resolve("inventoryService") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - const featureFlagRouter = req.scope.resolve("featureFlagRouter") - const pricingService: PricingService = req.scope.resolve("pricingService") - - const { skip, take, relations } = req.listConfig - - let rawProducts - let count - - if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) { - const [products, count_] = await listProducts( - req.scope, - req.filterableFields, - req.listConfig - ) - - rawProducts = products - count = count_ - } else { - const [products, count_] = await productService.listAndCount( - req.filterableFields, - req.listConfig - ) - - rawProducts = products - count = count_ - } - - let products: (Product | PricedProduct)[] = rawProducts - - // We only set prices if variants.prices are requested - const shouldSetPricing = ["variants", "variants.prices"].every((relation) => - relations?.includes(relation) - ) - - if (shouldSetPricing) { - products = await pricingService.setAdminProductPricing(rawProducts) - } - - // We only set availability if variants are requested - const shouldSetAvailability = relations?.includes("variants") - - if (inventoryService && shouldSetAvailability) { - const [salesChannelsIds] = await salesChannelService.listAndCount( - {}, - { select: ["id"] } - ) - - products = await productVariantInventoryService.setProductAvailability( - products, - salesChannelsIds.map((salesChannel) => salesChannel.id) - ) - } - - res.json({ - products, - count, - offset: skip, - limit: take, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved products. - */ -export class AdminGetProductsParams extends FilterableProductProps { - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - offset?: number = 0 - - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 50 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit?: number = 50 - - /** - * {@inheritDoc FindParams.expand} - */ - @IsString() - @IsOptional() - expand?: string - - /** - * {@inheritDoc FindParams.fields} - */ - @IsString() - @IsOptional() - fields?: string - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string -} diff --git a/packages/medusa/src/api/routes/admin/products/list-tag-usage-count.ts b/packages/medusa/src/api/routes/admin/products/list-tag-usage-count.ts deleted file mode 100644 index 6ab9c08499..0000000000 --- a/packages/medusa/src/api/routes/admin/products/list-tag-usage-count.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { ProductService } from "../../../../services" - -/** - * @oas [get] /admin/products/tag-usage - * operationId: "GetProductsTagUsage" - * summary: "List Tags Usage Number" - * description: "Retrieve a list of Product Tags with how many times each is used in products." - * x-authenticated: true - * x-codegen: - * method: listTags - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.listTags() - * .then(({ tags }) => { - * console.log(tags.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminProductTagUsage } from "medusa-react" - * - * const ProductTags = (productId: string) => { - * const { tags, isLoading } = useAdminProductTagUsage() - * - * return ( - *
- * {isLoading && Loading...} - * {tags && !tags.length && No Product Tags} - * {tags && tags.length > 0 && ( - *
    - * {tags.map((tag) => ( - *
  • {tag.value} - {tag.usage_count}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ProductTags - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/products/tag-usage' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsListTagsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const productService: ProductService = req.scope.resolve("productService") - - const tags = await productService.listTagsByUsage() - - res.json({ tags }) -} diff --git a/packages/medusa/src/api/routes/admin/products/list-types.ts b/packages/medusa/src/api/routes/admin/products/list-types.ts deleted file mode 100644 index 42d8778c7f..0000000000 --- a/packages/medusa/src/api/routes/admin/products/list-types.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { ProductService } from "../../../../services" - -/** - * @oas [get] /admin/products/types - * deprecated: true - * operationId: "GetProductsTypes" - * summary: "List Product Types" - * description: "Retrieve a list of Product Types." - * x-authenticated: true - * x-codegen: - * method: listTypes - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.listTypes() - * .then(({ types }) => { - * console.log(types.length); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/products/types' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsListTypesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const productService: ProductService = req.scope.resolve("productService") - - const types = await productService.listTypes() - - res.json({ types }) -} diff --git a/packages/medusa/src/api/routes/admin/products/list-variants.ts b/packages/medusa/src/api/routes/admin/products/list-variants.ts deleted file mode 100644 index bf41b65077..0000000000 --- a/packages/medusa/src/api/routes/admin/products/list-variants.ts +++ /dev/null @@ -1,255 +0,0 @@ -import { - IsBoolean, - IsNumber, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { Request, Response } from "express" - -import { Transform, Type } from "class-transformer" -import { ProductVariantService } from "../../../../services" -import { - DateComparisonOperator, - NumericalComparisonOperator, -} from "../../../../types/common" -import { IsType } from "../../../../utils" -import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean" - -/** - * @oas [get] /admin/products/{id}/variants - * operationId: "GetProductsProductVariants" - * summary: "List a Product's Variants" - * description: | - * Retrieve a list of Product Variants associated with a Product. The variants can be paginated. - * x-authenticated: true - * parameters: - * - (path) id=* {string} ID of the product. - * - (query) id {string} IDs to filter product variants by. - * - (query) fields {string} Comma-separated fields that should be included in the returned product variants. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned product variants. - * - (query) offset=0 {integer} The number of product variants to skip when retrieving the product variants. - * - (query) limit=100 {integer} Limit the number of product variants returned. - * - (query) q {string} Search term to search product variants' title, sku, and products' title. - * - (query) order {string} The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - * - (query) manage_inventory {boolean} Filter product variants by whether their inventory is managed or not. - * - (query) allow_backorder {boolean} Filter product variants by whether they are allowed to be backordered or not. - * - in: query - * name: inventory_quantity - * description: Filter by available inventory quantity - * schema: - * oneOf: - * - type: number - * description: a specific number to filter by. - * - type: object - * description: filter using less and greater than comparisons. - * properties: - * lt: - * type: number - * description: filter by inventory quantity less than this number - * gt: - * type: number - * description: filter by inventory quantity greater than this number - * lte: - * type: number - * description: filter by inventory quantity less than or equal to this number - * gte: - * type: number - * description: filter by inventory quantity greater than or equal to this number - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: listVariants - * queryParams: AdminGetProductsVariantsParams - * x-codeSamples: - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/products/{id}/variants' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsListVariantsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const productVariantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - - const { skip, take } = req.listConfig - - const [variants, count] = await productVariantService.listAndCount( - { - product_id: id, - ...req.filterableFields, - }, - req.listConfig - ) - - res.json({ - count, - variants, - offset: skip, - limit: take, - }) -} - -export class AdminGetProductsVariantsParams { - /** - * IDs to filter product variants by. - */ - @IsOptional() - @IsType([String, [String]]) - id?: string | string[] - - /** - * {@inheritDoc FindParams.fields} - */ - @IsString() - @IsOptional() - fields?: string - - /** - * {@inheritDoc FindParams.expand} - */ - @IsString() - @IsOptional() - expand?: string - - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - offset?: number = 0 - - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 100 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit?: number = 100 - - /** - * Search term to search product variants' title, sku, and products' title. - */ - @IsString() - @IsOptional() - q?: string - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string - - /** - * Number filters to apply on product variants' `inventory_quantity` field. - */ - @IsOptional() - @IsType([Number, NumericalComparisonOperator]) - inventory_quantity?: number | NumericalComparisonOperator - - /** - * Filter product variants by whether their inventory is managed or not. - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value.toLowerCase())) - manage_inventory?: boolean - - /** - * Filter product variants by whether they are allowed to be backordered or not. - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value.toLowerCase())) - allow_backorder?: boolean - - /** - * Date filters to apply on the product variants' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the product variants' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator -} diff --git a/packages/medusa/src/api/routes/admin/products/set-metadata.ts b/packages/medusa/src/api/routes/admin/products/set-metadata.ts deleted file mode 100644 index e99554bf34..0000000000 --- a/packages/medusa/src/api/routes/admin/products/set-metadata.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { defaultAdminProductFields, defaultAdminProductRelations } from "." - -import { EntityManager } from "typeorm" -import { IsString } from "class-validator" -import { PricingService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/products/{id}/metadata - * operationId: "PostProductsProductMetadata" - * summary: "Set Metadata" - * description: "Set the metadata of a Product. It can be any key-value pair, which allows adding custom data to a product." - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Product. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostProductsProductMetadataReq" - * x-codegen: - * method: setMetadata - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.setMetadata(productId, { - * key: "test", - * value: "true" - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/products/{id}/metadata' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "key": "test", - * "value": "true" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = await validator( - AdminPostProductsProductMetadataReq, - req.body - ) - - const productService = req.scope.resolve("productService") - const pricingService: PricingService = req.scope.resolve("pricingService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await productService.withTransaction(transactionManager).update(id, { - metadata: { [validated.key]: validated.value }, - }) - }) - - const rawProduct = await productService.retrieve(id, { - select: defaultAdminProductFields, - relations: defaultAdminProductRelations, - }) - - const [product] = await pricingService.setAdminProductPricing([rawProduct]) - - res.status(200).json({ product }) -} - -/** - * @schema AdminPostProductsProductMetadataReq - * type: object - * required: - * - key - * - value - * properties: - * key: - * description: The metadata key - * type: string - * value: - * description: The metadata value - * type: string - */ -export class AdminPostProductsProductMetadataReq { - @IsString() - key: string - - @IsString() - value: string -} diff --git a/packages/medusa/src/api/routes/admin/products/transaction/create-product-variant.ts b/packages/medusa/src/api/routes/admin/products/transaction/create-product-variant.ts deleted file mode 100644 index b392455156..0000000000 --- a/packages/medusa/src/api/routes/admin/products/transaction/create-product-variant.ts +++ /dev/null @@ -1,246 +0,0 @@ -import { - DistributedTransaction, - TransactionHandlerType, - TransactionOrchestrator, - TransactionPayload, - TransactionState, - TransactionStepsDefinition, -} from "@medusajs/orchestration" -import { IInventoryService, InventoryItemDTO } from "@medusajs/types" -import { - ProductVariantInventoryService, - ProductVariantService, -} from "../../../../../services" - -import { CreateProductVariantInput } from "../../../../../types/product-variant" -import { EntityManager } from "typeorm" -import { MedusaError, promiseAll } from "@medusajs/utils" -import { ProductVariant } from "../../../../../models" -import { ulid } from "ulid" - -enum actions { - createVariants = "createVariants", - createInventoryItems = "createInventoryItems", - attachInventoryItems = "attachInventoryItems", -} - -const simpleFlow: TransactionStepsDefinition = { - next: { - action: actions.createVariants, - }, -} - -const flowWithInventory: TransactionStepsDefinition = { - next: { - action: actions.createVariants, - saveResponse: true, - next: { - action: actions.createInventoryItems, - saveResponse: true, - next: { - action: actions.attachInventoryItems, - noCompensation: true, - }, - }, - }, -} - -const createSimpleVariantStrategy = new TransactionOrchestrator( - "create-variant", - simpleFlow -) - -const createVariantStrategyWithInventory = new TransactionOrchestrator( - "create-variant-with-inventory", - flowWithInventory -) - -type InjectedDependencies = { - manager: EntityManager - productVariantService: ProductVariantService - productVariantInventoryService: ProductVariantInventoryService - inventoryService?: IInventoryService -} - -export const createVariantsTransaction = async ( - dependencies: InjectedDependencies, - productId: string, - input: CreateProductVariantInput[] -): Promise => { - const { - manager, - productVariantService, - inventoryService, - productVariantInventoryService, - } = dependencies - - const productVariantInventoryServiceTx = - productVariantInventoryService.withTransaction(manager) - - const productVariantServiceTx = productVariantService.withTransaction(manager) - - async function createVariants(variantInput: CreateProductVariantInput[]) { - return await productVariantServiceTx.create(productId, variantInput) - } - - async function removeVariants(variants: ProductVariant[]) { - if (variants.length) { - await productVariantServiceTx.delete(variants.map((v) => v.id)) - } - } - - async function createInventoryItems(variants: ProductVariant[] = []) { - const context = { transactionManager: manager } - - return await promiseAll( - variants.map(async (variant) => { - if (!variant.manage_inventory) { - return - } - - const inventoryItem = await inventoryService!.createInventoryItem( - { - sku: variant.sku, - origin_country: variant.origin_country, - hs_code: variant.hs_code, - mid_code: variant.mid_code, - material: variant.material, - weight: variant.weight, - length: variant.length, - height: variant.height, - width: variant.width, - }, - context - ) - - return { variant, inventoryItem } - }) - ) - } - - async function removeInventoryItems( - data: { - variant: ProductVariant - inventoryItem: InventoryItemDTO - }[] = [] - ) { - const context = { transactionManager: manager } - - return await promiseAll( - data.map(async ({ inventoryItem }) => { - return await inventoryService!.deleteInventoryItem( - inventoryItem.id, - context - ) - }) - ) - } - - async function attachInventoryItems( - data: { - variant: ProductVariant - inventoryItem: InventoryItemDTO - }[] - ) { - return await promiseAll( - data - .filter((d) => d) - .map(async ({ variant, inventoryItem }) => { - return productVariantInventoryServiceTx.attachInventoryItem( - variant.id, - inventoryItem.id - ) - }) - ) - } - - async function transactionHandler( - actionId: string, - type: TransactionHandlerType, - payload: TransactionPayload - ) { - const command = { - [actions.createVariants]: { - [TransactionHandlerType.INVOKE]: async ( - data: CreateProductVariantInput[] - ) => { - return await createVariants(data) - }, - [TransactionHandlerType.COMPENSATE]: async ( - data: CreateProductVariantInput[], - { invoke } - ) => { - await removeVariants(invoke[actions.createVariants]) - }, - }, - [actions.createInventoryItems]: { - [TransactionHandlerType.INVOKE]: async ( - data: CreateProductVariantInput[], - { invoke } - ) => { - const { [actions.createVariants]: variants } = invoke - - return await createInventoryItems(variants) - }, - [TransactionHandlerType.COMPENSATE]: async ( - data: { - variant: ProductVariant - inventoryItem: InventoryItemDTO - }[], - { invoke } - ) => { - await removeInventoryItems(invoke[actions.createInventoryItems]) - }, - }, - [actions.attachInventoryItems]: { - [TransactionHandlerType.INVOKE]: async ( - data: CreateProductVariantInput[], - { invoke } - ) => { - const { - [actions.createVariants]: variants, - [actions.createInventoryItems]: inventoryItemsResult, - } = invoke - - return await attachInventoryItems(inventoryItemsResult) - }, - }, - } - return command[actionId][type](payload.data, payload.context) - } - - const strategy = inventoryService - ? createVariantStrategyWithInventory - : createSimpleVariantStrategy - - const transaction = await strategy.beginTransaction( - ulid(), - transactionHandler, - input - ) - await strategy.resume(transaction) - - if (transaction.getState() !== TransactionState.DONE) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - transaction - .getErrors() - .map((err) => err.error?.message) - .join("\n") - ) - } - - return transaction -} - -export const revertVariantTransaction = async ( - dependencies: InjectedDependencies, - transaction: DistributedTransaction -) => { - const { inventoryService } = dependencies - const strategy = inventoryService - ? createVariantStrategyWithInventory - : createSimpleVariantStrategy - - await strategy.cancelTransaction(transaction) -} diff --git a/packages/medusa/src/api/routes/admin/products/update-option.ts b/packages/medusa/src/api/routes/admin/products/update-option.ts deleted file mode 100644 index f419282d99..0000000000 --- a/packages/medusa/src/api/routes/admin/products/update-option.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { PricingService, ProductService } from "../../../../services" -import { defaultAdminProductFields, defaultAdminProductRelations } from "." - -import { EntityManager } from "typeorm" -import { IsString } from "class-validator" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/products/{id}/options/{option_id} - * operationId: "PostProductsProductOptionsOption" - * summary: "Update a Product Option" - * description: "Update a Product Option's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Product. - * - (path) option_id=* {string} The ID of the Product Option. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostProductsProductOptionsOption" - * x-codegen: - * method: updateOption - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.updateOption(productId, optionId, { - * title: "Size" - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateProductOption } from "medusa-react" - * - * type Props = { - * productId: string - * optionId: string - * } - * - * const ProductOption = ({ - * productId, - * optionId - * }: Props) => { - * const updateOption = useAdminUpdateProductOption( - * productId - * ) - * // ... - * - * const handleUpdate = ( - * title: string - * ) => { - * updateOption.mutate({ - * option_id: optionId, - * title, - * }, { - * onSuccess: ({ product }) => { - * console.log(product.options) - * } - * }) - * } - * - * // ... - * } - * - * export default ProductOption - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/products/{id}/options/{option_id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "title": "Size" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, option_id } = req.params - - const validated = await validator( - AdminPostProductsProductOptionsOption, - req.body - ) - - const productService: ProductService = req.scope.resolve("productService") - const pricingService: PricingService = req.scope.resolve("pricingService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await productService - .withTransaction(transactionManager) - .updateOption(id, option_id, validated) - }) - - const rawProduct = await productService.retrieve(id, { - select: defaultAdminProductFields, - relations: defaultAdminProductRelations, - }) - - const [product] = await pricingService.setAdminProductPricing([rawProduct]) - - res.json({ product }) -} - -/** - * @schema AdminPostProductsProductOptionsOption - * type: object - * required: - * - title - * properties: - * title: - * description: "The title of the Product Option" - * type: string - */ -export class AdminPostProductsProductOptionsOption { - @IsString() - title: string -} diff --git a/packages/medusa/src/api/routes/admin/products/update-product.ts b/packages/medusa/src/api/routes/admin/products/update-product.ts deleted file mode 100644 index df9751885c..0000000000 --- a/packages/medusa/src/api/routes/admin/products/update-product.ts +++ /dev/null @@ -1,767 +0,0 @@ -import { Workflows, updateProducts } from "@medusajs/core-flows" -import { DistributedTransaction } from "@medusajs/orchestration" -import { - FlagRouter, - MedusaError, - MedusaV2Flag, - promiseAll, -} from "@medusajs/utils" -import { Type } from "class-transformer" -import { - IsArray, - IsBoolean, - IsEnum, - IsInt, - IsNumber, - IsObject, - IsOptional, - IsString, - NotEquals, - ValidateIf, - ValidateNested, -} from "class-validator" -import { EntityManager } from "typeorm" - -import { - defaultAdminProductFields, - defaultAdminProductRelations, - defaultAdminProductRemoteQueryObject, -} from "." -import { ProductStatus, ProductVariant } from "../../../../models" -import { - PricingService, - ProductService, - ProductVariantInventoryService, - ProductVariantService, -} from "../../../../services" -import { - ProductProductCategoryReq, - ProductSalesChannelReq, - ProductTagReq, - ProductTypeReq, -} from "../../../../types/product" -import { - CreateProductVariantInput, - ProductVariantPricesUpdateReq, - UpdateProductVariantInput, -} from "../../../../types/product-variant" -import { retrieveProduct } from "../../../../utils" -import { - createVariantsTransaction, - revertVariantTransaction, -} from "./transaction/create-product-variant" - -import { IInventoryService, WorkflowTypes } from "@medusajs/types" -import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" -import { ProductVariantRepository } from "../../../../repositories/product-variant" -import { Logger } from "../../../../types/global" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" - -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/products/{id} - * operationId: "PostProductsProduct" - * summary: "Update a Product" - * description: "Update a Product's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Product. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostProductsProductReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.update(productId, { - * title: "Shirt", - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateProduct } from "medusa-react" - * - * type Props = { - * productId: string - * } - * - * const Product = ({ productId }: Props) => { - * const updateProduct = useAdminUpdateProduct( - * productId - * ) - * // ... - * - * const handleUpdate = ( - * title: string - * ) => { - * updateProduct.mutate({ - * title, - * }, { - * onSuccess: ({ product }) => { - * console.log(product.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Product - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/products/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "title": "Size" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = await validator(AdminPostProductsProductReq, req.body) - - const logger: Logger = req.scope.resolve("logger") - const productVariantRepo: typeof ProductVariantRepository = req.scope.resolve( - "productVariantRepository" - ) - const productService: ProductService = req.scope.resolve("productService") - const pricingService: PricingService = req.scope.resolve("pricingService") - const productVariantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - const inventoryService: IInventoryService | undefined = - req.scope.resolve("inventoryService") - - const manager: EntityManager = req.scope.resolve("manager") - const productModuleService = req.scope.resolve("productModuleService") - - const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter") - const isMedusaV2Enabled = featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key) - - if (isMedusaV2Enabled && !productModuleService) { - logger.warn( - `Cannot run ${Workflows.UpdateProducts} workflow without '@medusajs/product' installed` - ) - } - - if (isMedusaV2Enabled) { - const updateProductWorkflow = updateProducts(req.scope) - - const input = { - products: [ - { id, ...validated }, - ] as WorkflowTypes.ProductWorkflow.UpdateProductInputDTO[], - } - - const { result } = await updateProductWorkflow.run({ - input, - context: { - manager: manager, - }, - }) - } else { - await manager.transaction(async (transactionManager) => { - const productServiceTx = - productService.withTransaction(transactionManager) - - const { variants } = validated - delete validated.variants - - const product = await productServiceTx.update(id, validated) - - if (!variants) { - return - } - - const variantRepo = manager.withRepository(productVariantRepo) - const productVariants = await productVariantService - .withTransaction(transactionManager) - .list( - { product_id: id }, - { - select: variantRepo.metadata.columns.map( - (c) => c.propertyName - ) as (keyof ProductVariant)[], - } - ) - - const productVariantMap = new Map(productVariants.map((v) => [v.id, v])) - const variantWithIdSet = new Set() - - const variantIdsNotBelongingToProduct: string[] = [] - const variantsToUpdate: { - variant: ProductVariant - updateData: UpdateProductVariantInput - }[] = [] - const variantsToCreate: ProductVariantReq[] = [] - - // Preparing the data step - for (const [variantRank, variant] of variants.entries()) { - if (!variant.id) { - Object.assign(variant, { - variant_rank: variantRank, - options: variant.options || [], - prices: variant.prices || [], - }) - variantsToCreate.push(variant) - - continue - } - - // Will be used to find the variants that should be removed during the next steps - variantWithIdSet.add(variant.id) - - if (!productVariantMap.has(variant.id)) { - variantIdsNotBelongingToProduct.push(variant.id) - continue - } - - const productVariant = productVariantMap.get(variant.id)! - Object.assign(variant, { - variant_rank: variantRank, - product_id: productVariant.product_id, - }) - variantsToUpdate.push({ variant: productVariant, updateData: variant }) - } - - if (variantIdsNotBelongingToProduct.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Variants with id: ${variantIdsNotBelongingToProduct.join( - ", " - )} are not associated with this product` - ) - } - - const allVariantTransactions: DistributedTransaction[] = [] - const transactionDependencies = { - manager: transactionManager, - inventoryService, - productVariantInventoryService, - productVariantService, - } - - const productVariantServiceTx = - productVariantService.withTransaction(transactionManager) - - // Delete the variant that does not exist anymore from the provided variants - const variantIdsToDelete = [...productVariantMap.keys()].filter( - (variantId) => !variantWithIdSet.has(variantId) - ) - - if (variantIdsToDelete) { - await productVariantServiceTx.delete(variantIdsToDelete) - } - - if (variantsToUpdate.length) { - await productVariantServiceTx.update(variantsToUpdate) - } - - if (variantsToCreate.length) { - try { - const varTransaction = await createVariantsTransaction( - transactionDependencies, - product.id, - variantsToCreate as CreateProductVariantInput[] - ) - allVariantTransactions.push(varTransaction) - } catch (e) { - await promiseAll( - allVariantTransactions.map(async (transaction) => { - await revertVariantTransaction( - transactionDependencies, - transaction - ).catch(() => logger.warn("Transaction couldn't be reverted.")) - }) - ) - - throw e - } - } - }) - } - - let rawProduct - - if (isMedusaV2Enabled) { - rawProduct = await retrieveProduct( - req.scope, - id, - defaultAdminProductRemoteQueryObject - ) - } else { - rawProduct = await productService.retrieve(id, { - select: defaultAdminProductFields, - relations: defaultAdminProductRelations, - }) - } - - const [product] = await pricingService.setAdminProductPricing([rawProduct]) - - res.json({ product }) -} - -class ProductVariantOptionReq { - @IsString() - value: string - - @IsString() - option_id: string -} - -class ProductVariantReq { - @IsString() - @IsOptional() - id?: string - - @IsString() - @IsOptional() - title?: string - - @IsString() - @IsOptional() - sku?: string - - @IsString() - @IsOptional() - ean?: string - - @IsString() - @IsOptional() - upc?: string - - @IsString() - @IsOptional() - barcode?: string - - @IsString() - @IsOptional() - hs_code?: string - - @IsInt() - @IsOptional() - inventory_quantity?: number - - @IsBoolean() - @IsOptional() - allow_backorder?: boolean - - @IsBoolean() - @IsOptional() - manage_inventory?: boolean - - @IsNumber() - @IsOptional() - weight?: number - - @IsNumber() - @IsOptional() - length?: number - - @IsNumber() - @IsOptional() - height?: number - - @IsNumber() - @IsOptional() - width?: number - - @IsString() - @IsOptional() - origin_country?: string - - @IsString() - @IsOptional() - mid_code?: string - - @IsString() - @IsOptional() - material?: string - - @IsObject() - @IsOptional() - metadata?: Record - - @IsArray() - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => ProductVariantPricesUpdateReq) - prices?: ProductVariantPricesUpdateReq[] - - @IsOptional() - @Type(() => ProductVariantOptionReq) - @ValidateNested({ each: true }) - @IsArray() - options?: ProductVariantOptionReq[] = [] -} - -/** - * @schema AdminPostProductsProductReq - * type: object - * description: "The details to update of the product." - * properties: - * title: - * description: "The title of the Product" - * type: string - * subtitle: - * description: "The subtitle of the Product" - * type: string - * description: - * description: "The description of the Product." - * type: string - * discountable: - * description: A flag to indicate if discounts can be applied to the Line Items generated from this Product - * type: boolean - * images: - * description: An array of images of the Product. Each value in the array is a URL to the image. You can use the upload API Routes to upload the image and obtain a URL. - * type: array - * items: - * type: string - * thumbnail: - * description: The thumbnail to use for the Product. The value is a URL to the thumbnail. You can use the upload API Routes to upload the thumbnail and obtain a URL. - * type: string - * handle: - * description: A unique handle to identify the Product by. If not provided, the kebab-case version of the product title will be used. This can be used as a slug in URLs. - * type: string - * status: - * description: The status of the product. The product is shown to the customer only if its status is `published`. - * type: string - * enum: [draft, proposed, published, rejected] - * type: - * description: The Product Type to associate the Product with. - * type: object - * required: - * - value - * properties: - * id: - * description: The ID of an existing Product Type. If not provided, a new product type will be created. - * type: string - * value: - * description: The value of the Product Type. - * type: string - * collection_id: - * description: The ID of the Product Collection the Product belongs to. - * type: string - * tags: - * description: Product Tags to associate the Product with. - * type: array - * items: - * type: object - * required: - * - value - * properties: - * id: - * description: The ID of an existing Product Tag. If not provided, a new product tag will be created. - * type: string - * value: - * description: The value of the Tag. If the `id` is provided, the value of the existing tag will be updated. - * type: string - * sales_channels: - * description: "Sales channels to associate the Product with." - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * description: The ID of an existing Sales channel. - * type: string - * categories: - * description: "Product categories to add the Product to." - * x-featureFlag: "product_categories" - * type: array - * items: - * required: - * - id - * properties: - * id: - * description: The ID of a Product Category. - * type: string - * variants: - * description: An array of Product Variants to create with the Product. Each product variant must have a unique combination of Product Option values. - * type: array - * items: - * type: object - * properties: - * id: - * description: The id of an existing product variant. If provided, the details of the product variant will be updated. If not, a new product variant will be created. - * type: string - * title: - * description: The title of the product variant. - * type: string - * sku: - * description: The unique SKU of the product variant. - * type: string - * ean: - * description: The EAN number of the product variant. - * type: string - * upc: - * description: The UPC number of the product variant. - * type: string - * barcode: - * description: A generic GTIN field of the product variant. - * type: string - * hs_code: - * description: The Harmonized System code of the product variant. - * type: string - * inventory_quantity: - * description: The amount of stock kept of the product variant. - * type: integer - * allow_backorder: - * description: Whether the product variant can be purchased when out of stock. - * type: boolean - * manage_inventory: - * description: Whether Medusa should keep track of the inventory of this product variant. - * type: boolean - * weight: - * description: The weight of the product variant. - * type: number - * length: - * description: The length of the product variant. - * type: number - * height: - * description: The height of the product variant. - * type: number - * width: - * description: The width of the product variant. - * type: number - * origin_country: - * description: The country of origin of the product variant. - * type: string - * mid_code: - * description: The Manufacturer Identification code of the product variant. - * type: string - * material: - * description: The material composition of the product variant. - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * prices: - * type: array - * description: An array of product variant prices. A product variant can have different prices for each region or currency code. - * externalDocs: - * url: https://docs.medusajs.com/modules/products/admin/manage-products#product-variant-prices - * description: Product variant pricing. - * items: - * type: object - * required: - * - amount - * properties: - * id: - * description: The ID of the Price. If provided, the existing price will be updated. Otherwise, a new price will be created. - * type: string - * region_id: - * description: The ID of the Region the price will be used in. This is only required if `currency_code` is not provided. - * type: string - * currency_code: - * description: The 3 character ISO currency code the price will be used in. This is only required if `region_id` is not provided. - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * amount: - * description: The price amount. - * type: integer - * min_quantity: - * description: The minimum quantity required to be added to the cart for the price to be used. - * type: integer - * max_quantity: - * description: The maximum quantity required to be added to the cart for the price to be used. - * type: integer - * options: - * type: array - * description: An array of Product Option values that the variant corresponds to. - * items: - * type: object - * required: - * - option_id - * - value - * properties: - * option_id: - * description: The ID of the Option. - * type: string - * value: - * description: The value of the Product Option. - * type: string - * weight: - * description: The weight of the Product. - * type: number - * length: - * description: The length of the Product. - * type: number - * height: - * description: The height of the Product. - * type: number - * width: - * description: The width of the Product. - * type: number - * hs_code: - * description: The Harmonized System code of the product variant. - * type: string - * origin_country: - * description: The country of origin of the Product. - * type: string - * mid_code: - * description: The Manufacturer Identification code of the Product. - * type: string - * material: - * description: The material composition of the Product. - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostProductsProductReq { - @IsString() - @IsOptional() - title?: string - - @IsString() - @IsOptional() - subtitle?: string - - @IsString() - @IsOptional() - description?: string - - @IsBoolean() - @IsOptional() - discountable?: boolean - - @IsArray() - @IsOptional() - images?: string[] - - @IsString() - @IsOptional() - thumbnail?: string - - @IsString() - @IsOptional() - handle?: string - - @IsEnum(ProductStatus) - @NotEquals(null) - @ValidateIf((object, value) => value !== undefined) - status?: ProductStatus - - @IsOptional() - @Type(() => ProductTypeReq) - @ValidateNested() - type?: ProductTypeReq - - @IsOptional() - @IsString() - collection_id?: string - - @IsOptional() - @Type(() => ProductTagReq) - @ValidateNested({ each: true }) - @IsArray() - tags?: ProductTagReq[] - - @FeatureFlagDecorators(SalesChannelFeatureFlag.key, [ - IsOptional(), - Type(() => ProductSalesChannelReq), - ValidateNested({ each: true }), - IsArray(), - ]) - sales_channels?: ProductSalesChannelReq[] | null - - @IsOptional() - @Type(() => ProductProductCategoryReq) - @ValidateNested({ each: true }) - @IsArray() - categories?: ProductProductCategoryReq[] - - @IsOptional() - @Type(() => ProductVariantReq) - @ValidateNested({ each: true }) - @IsArray() - variants?: ProductVariantReq[] - - @IsNumber() - @IsOptional() - weight?: number - - @IsNumber() - @IsOptional() - length?: number - - @IsNumber() - @IsOptional() - height?: number - - @IsNumber() - @IsOptional() - width?: number - - @IsString() - @IsOptional() - hs_code?: string - - @IsString() - @IsOptional() - origin_country?: string - - @IsString() - @IsOptional() - mid_code?: string - - @IsString() - @IsOptional() - material?: string - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/products/update-variant.ts b/packages/medusa/src/api/routes/admin/products/update-variant.ts deleted file mode 100644 index 83f7630fdb..0000000000 --- a/packages/medusa/src/api/routes/admin/products/update-variant.ts +++ /dev/null @@ -1,396 +0,0 @@ -import { WorkflowTypes } from "@medusajs/types" -import { FlagRouter, MedusaV2Flag } from "@medusajs/utils" -import { UpdateProductVariants } from "@medusajs/core-flows" -import { Type } from "class-transformer" -import { - IsArray, - IsBoolean, - IsNumber, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { EntityManager } from "typeorm" -import { defaultAdminProductFields, defaultAdminProductRelations } from "." -import { - PricingService, - ProductService, - ProductVariantService, -} from "../../../../services" -import { PriceSelectionParams } from "../../../../types/price-selection" -import { ProductVariantPricesUpdateReq } from "../../../../types/product-variant" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/products/{id}/variants/{variant_id} - * operationId: "PostProductsProductVariantsVariant" - * summary: "Update a Product Variant" - * description: "Update a Product Variant's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Product. - * - (path) variant_id=* {string} The ID of the Product Variant. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostProductsProductVariantsVariantReq" - * x-codegen: - * method: updateVariant - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.products.updateVariant(productId, variantId, { - * title: "Color", - * prices: [ - * { - * amount: 1000, - * currency_code: "eur" - * } - * ], - * options: [ - * { - * option_id, - * value: "S" - * } - * ], - * inventory_quantity: 100 - * }) - * .then(({ product }) => { - * console.log(product.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateVariant } from "medusa-react" - * - * type Props = { - * productId: string - * variantId: string - * } - * - * const ProductVariant = ({ - * productId, - * variantId - * }: Props) => { - * const updateVariant = useAdminUpdateVariant( - * productId - * ) - * // ... - * - * const handleUpdate = (title: string) => { - * updateVariant.mutate({ - * variant_id: variantId, - * title, - * }, { - * onSuccess: ({ product }) => { - * console.log(product.variants) - * } - * }) - * } - * - * // ... - * } - * - * export default ProductVariant - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/products/{id}/variants/{variant_id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "title": "Color", - * "prices": [ - * { - * "amount": 1000, - * "currency_code": "eur" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminProductsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, variant_id } = req.params - - const manager: EntityManager = req.scope.resolve("manager") - const productService: ProductService = req.scope.resolve("productService") - const pricingService: PricingService = req.scope.resolve("pricingService") - const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter") - const productVariantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - const validated = await validator( - AdminPostProductsProductVariantsVariantReq, - req.body - ) - - const validatedQueryParams = await validator(PriceSelectionParams, req.query) - - if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) { - const updateVariantsWorkflow = UpdateProductVariants.updateProductVariants( - req.scope - ) - - const input = { - productVariants: [ - { - id: variant_id, - ...validated, - }, - ] as WorkflowTypes.ProductWorkflow.UpdateProductVariantsInputDTO[], - } - - await updateVariantsWorkflow.run({ - input, - context: { - manager, - }, - }) - } else { - await manager.transaction(async (transactionManager) => { - await productVariantService - .withTransaction(transactionManager) - .update(variant_id, { - product_id: id, - ...validated, - }) - }) - } - - const rawProduct = await productService.retrieve(id, { - select: defaultAdminProductFields, - relations: defaultAdminProductRelations, - ...validatedQueryParams, - }) - - const [product] = await pricingService.setProductPrices([rawProduct]) - - res.json({ product }) -} - -class ProductVariantOptionReq { - @IsString() - value: string - - @IsString() - option_id: string -} - -/** - * @schema AdminPostProductsProductVariantsVariantReq - * type: object - * properties: - * title: - * description: The title of the product variant. - * type: string - * sku: - * description: The unique SKU of the product variant. - * type: string - * ean: - * description: The EAN number of the item. - * type: string - * upc: - * description: The UPC number of the item. - * type: string - * barcode: - * description: A generic GTIN field of the product variant. - * type: string - * hs_code: - * description: The Harmonized System code of the product variant. - * type: string - * inventory_quantity: - * description: The amount of stock kept of the product variant. - * type: integer - * allow_backorder: - * description: Whether the product variant can be purchased when out of stock. - * type: boolean - * manage_inventory: - * description: Whether Medusa should keep track of the inventory of this product variant. - * type: boolean - * weight: - * description: The weight of the product variant. - * type: number - * length: - * description: The length of the product variant. - * type: number - * height: - * description: The height of the product variant. - * type: number - * width: - * description: The width of the product variant. - * type: number - * origin_country: - * description: The country of origin of the product variant. - * type: string - * mid_code: - * description: The Manufacturer Identification code of the product variant. - * type: string - * material: - * description: The material composition of the product variant. - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * prices: - * type: array - * description: An array of product variant prices. A product variant can have different prices for each region or currency code. - * externalDocs: - * url: https://docs.medusajs.com/modules/products/admin/manage-products#product-variant-prices - * description: Product variant pricing. - * items: - * type: object - * required: - * - amount - * properties: - * id: - * description: The ID of the price. If provided, the existing price will be updated. Otherwise, a new price will be created. - * type: string - * region_id: - * description: The ID of the Region the price will be used in. This is only required if `currency_code` is not provided. - * type: string - * currency_code: - * description: The 3 character ISO currency code the price will be used in. This is only required if `region_id` is not provided. - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * amount: - * description: The price amount. - * type: integer - * min_quantity: - * description: The minimum quantity required to be added to the cart for the price to be used. - * type: integer - * max_quantity: - * description: The maximum quantity required to be added to the cart for the price to be used. - * type: integer - * options: - * type: array - * description: An array of Product Option values that the variant corresponds to. - * items: - * type: object - * required: - * - option_id - * - value - * properties: - * option_id: - * description: The ID of the Product Option. - * type: string - * value: - * description: The value of the Product Option. - * type: string - */ -export class AdminPostProductsProductVariantsVariantReq { - @IsString() - @IsOptional() - title?: string - - @IsString() - @IsOptional() - sku?: string - - @IsString() - @IsOptional() - ean?: string - - @IsString() - @IsOptional() - upc?: string - - @IsString() - @IsOptional() - barcode?: string - - @IsString() - @IsOptional() - hs_code?: string - - @IsNumber() - @IsOptional() - inventory_quantity?: number - - @IsBoolean() - @IsOptional() - allow_backorder?: boolean - - @IsBoolean() - @IsOptional() - manage_inventory?: boolean - - @IsNumber() - @IsOptional() - weight?: number - - @IsNumber() - @IsOptional() - length?: number - - @IsNumber() - @IsOptional() - height?: number - - @IsNumber() - @IsOptional() - width?: number - - @IsString() - @IsOptional() - origin_country?: string - - @IsString() - @IsOptional() - mid_code?: string - - @IsString() - @IsOptional() - material?: string - - @IsObject() - @IsOptional() - metadata?: Record - - @IsArray() - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => ProductVariantPricesUpdateReq) - prices?: ProductVariantPricesUpdateReq[] - - @Type(() => ProductVariantOptionReq) - @ValidateNested({ each: true }) - @IsOptional() - @IsArray() - options?: ProductVariantOptionReq[] = [] -} diff --git a/packages/medusa/src/api/routes/admin/publishable-api-keys/add-channels-batch.ts b/packages/medusa/src/api/routes/admin/publishable-api-keys/add-channels-batch.ts deleted file mode 100644 index 998f235259..0000000000 --- a/packages/medusa/src/api/routes/admin/publishable-api-keys/add-channels-batch.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { IsArray, ValidateNested } from "class-validator" -import { Request, Response } from "express" -import { Type } from "class-transformer" -import { EntityManager } from "typeorm" - -import { ProductBatchSalesChannel } from "../../../../types/sales-channels" -import PublishableApiKeyService from "../../../../services/publishable-api-key" - -/** - * @oas [post] /admin/publishable-api-keys/{id}/sales-channels/batch - * operationId: "PostPublishableApiKeySalesChannelsChannelsBatch" - * summary: "Add Sales Channels" - * description: "Add a list of sales channels to a publishable API key." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Publishable Api Key. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostPublishableApiKeySalesChannelsBatchReq" - * x-codegen: - * method: addSalesChannelsBatch - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.addSalesChannelsBatch(publishableApiKeyId, { - * sales_channel_ids: [ - * { - * id: channelId - * } - * ] - * }) - * .then(({ publishable_api_key }) => { - * console.log(publishable_api_key.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminAddPublishableKeySalesChannelsBatch, - * } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const PublishableApiKey = ({ - * publishableApiKeyId - * }: Props) => { - * const addSalesChannels = - * useAdminAddPublishableKeySalesChannelsBatch( - * publishableApiKeyId - * ) - * // ... - * - * const handleAdd = (salesChannelId: string) => { - * addSalesChannels.mutate({ - * sales_channel_ids: [ - * { - * id: salesChannelId, - * }, - * ], - * }, { - * onSuccess: ({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * } - * }) - * } - * - * // ... - * } - * - * export default PublishableApiKey - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/publishable-api-keys/{pak_id}/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "sales_channel_ids": [ - * { - * "id": "{sales_channel_id}" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Publishable Api Keys - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPublishableApiKeysRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response): Promise => { - const validatedBody = - req.validatedBody as AdminPostPublishableApiKeySalesChannelsBatchReq - - const { id } = req.params - - const publishableApiKeyService: PublishableApiKeyService = req.scope.resolve( - "publishableApiKeyService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const publishableApiKey = await manager.transaction( - async (transactionManager) => { - await publishableApiKeyService - .withTransaction(transactionManager) - .addSalesChannels( - id, - validatedBody.sales_channel_ids.map((p) => p.id) - ) - - return await publishableApiKeyService.retrieve(id) - } - ) - - res.status(200).json({ publishable_api_key: publishableApiKey }) -} - -/** - * @schema AdminPostPublishableApiKeySalesChannelsBatchReq - * type: object - * description: "The details of the sales channels to add to the publishable API key." - * required: - * - sales_channel_ids - * properties: - * sales_channel_ids: - * description: The IDs of the sales channels to add to the publishable API key - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * type: string - * description: The ID of the sales channel - */ -export class AdminPostPublishableApiKeySalesChannelsBatchReq { - @IsArray() - @ValidateNested({ each: true }) - @Type(() => ProductBatchSalesChannel) - sales_channel_ids: ProductBatchSalesChannel[] -} diff --git a/packages/medusa/src/api/routes/admin/publishable-api-keys/create-publishable-api-key.ts b/packages/medusa/src/api/routes/admin/publishable-api-keys/create-publishable-api-key.ts deleted file mode 100644 index 7e11a76f16..0000000000 --- a/packages/medusa/src/api/routes/admin/publishable-api-keys/create-publishable-api-key.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { IsString } from "class-validator" - -import PublishableApiKeyService from "../../../../services/publishable-api-key" - -/** - * @oas [post] /admin/publishable-api-keys - * operationId: "PostPublishableApiKeys" - * summary: "Create Publishable API Key" - * description: "Create a Publishable API Key." - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostPublishableApiKeysReq" - * x-authenticated: true - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.create({ - * title - * }) - * .then(({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreatePublishableApiKey } from "medusa-react" - * - * const CreatePublishableApiKey = () => { - * const createKey = useAdminCreatePublishableApiKey() - * // ... - * - * const handleCreate = (title: string) => { - * createKey.mutate({ - * title, - * }, { - * onSuccess: ({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreatePublishableApiKey - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/publishable-api-keys' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "title": "Web API Key" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Publishable Api Keys - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPublishableApiKeysRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const publishableApiKeyService = req.scope.resolve( - "publishableApiKeyService" - ) as PublishableApiKeyService - - const manager = req.scope.resolve("manager") as EntityManager - const data = req.validatedBody as AdminPostPublishableApiKeysReq - - const loggedInUserId = (req.user?.id ?? req.user?.userId) as string - - const pubKey = await manager.transaction(async (transactionManager) => { - return await publishableApiKeyService - .withTransaction(transactionManager) - .create(data, { loggedInUserId }) - }) - - return res.status(200).json({ publishable_api_key: pubKey }) -} - -/** - * @schema AdminPostPublishableApiKeysReq - * type: object - * description: "The details of the publishable API key to create." - * required: - * - title - * properties: - * title: - * description: The title of the publishable API key - * type: string - */ -export class AdminPostPublishableApiKeysReq { - @IsString() - title: string -} diff --git a/packages/medusa/src/api/routes/admin/publishable-api-keys/delete-channels-batch.ts b/packages/medusa/src/api/routes/admin/publishable-api-keys/delete-channels-batch.ts deleted file mode 100644 index cf67916134..0000000000 --- a/packages/medusa/src/api/routes/admin/publishable-api-keys/delete-channels-batch.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { IsArray, ValidateNested } from "class-validator" -import { Request, Response } from "express" -import { Type } from "class-transformer" -import { EntityManager } from "typeorm" - -import { ProductBatchSalesChannel } from "../../../../types/sales-channels" -import PublishableApiKeyService from "../../../../services/publishable-api-key" - -/** - * @oas [delete] /admin/publishable-api-keys/{id}/sales-channels/batch - * operationId: "DeletePublishableApiKeySalesChannelsChannelsBatch" - * summary: "Remove Sales Channels" - * description: "Remove a list of sales channels from a publishable API key. This doesn't delete the sales channels and only removes the association between them and the publishable API key." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Publishable API Key. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeletePublishableApiKeySalesChannelsBatchReq" - * x-codegen: - * method: deleteSalesChannelsBatch - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.deleteSalesChannelsBatch(publishableApiKeyId, { - * sales_channel_ids: [ - * { - * id: channelId - * } - * ] - * }) - * .then(({ publishable_api_key }) => { - * console.log(publishable_api_key.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminRemovePublishableKeySalesChannelsBatch, - * } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const PublishableApiKey = ({ - * publishableApiKeyId - * }: Props) => { - * const deleteSalesChannels = - * useAdminRemovePublishableKeySalesChannelsBatch( - * publishableApiKeyId - * ) - * // ... - * - * const handleDelete = (salesChannelId: string) => { - * deleteSalesChannels.mutate({ - * sales_channel_ids: [ - * { - * id: salesChannelId, - * }, - * ], - * }, { - * onSuccess: ({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * } - * }) - * } - * - * // ... - * } - * - * export default PublishableApiKey - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/publishable-api-keys/{id}/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "sales_channel_ids": [ - * { - * "id": "{sales_channel_id}" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Publishable Api Keys - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPublishableApiKeysRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response): Promise => { - const validatedBody = - req.validatedBody as AdminDeletePublishableApiKeySalesChannelsBatchReq - - const { id } = req.params - - const publishableApiKeyService: PublishableApiKeyService = req.scope.resolve( - "publishableApiKeyService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const publishableApiKey = await manager.transaction( - async (transactionManager) => { - await publishableApiKeyService - .withTransaction(transactionManager) - .removeSalesChannels( - id, - validatedBody.sales_channel_ids.map((p) => p.id) - ) - - return await publishableApiKeyService.retrieve(id) - } - ) - - res.status(200).json({ publishable_api_key: publishableApiKey }) -} - -/** - * @schema AdminDeletePublishableApiKeySalesChannelsBatchReq - * type: object - * description: "The details of the sales channels to remove from the publishable API key." - * required: - * - sales_channel_ids - * properties: - * sales_channel_ids: - * description: The IDs of the sales channels to remove from the publishable API key - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * type: string - * description: The ID of the sales channel - */ -export class AdminDeletePublishableApiKeySalesChannelsBatchReq { - @IsArray() - @ValidateNested({ each: true }) - @Type(() => ProductBatchSalesChannel) - sales_channel_ids: ProductBatchSalesChannel[] -} diff --git a/packages/medusa/src/api/routes/admin/publishable-api-keys/delete-publishable-api-key.ts b/packages/medusa/src/api/routes/admin/publishable-api-keys/delete-publishable-api-key.ts deleted file mode 100644 index 16e20bc7f7..0000000000 --- a/packages/medusa/src/api/routes/admin/publishable-api-keys/delete-publishable-api-key.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { EntityManager } from "typeorm" - -import PublishableApiKeyService from "../../../../services/publishable-api-key" - -/** - * @oas [delete] /admin/publishable-api-keys/{id} - * operationId: "DeletePublishableApiKeysPublishableApiKey" - * summary: "Delete Publishable API Key" - * description: "Delete a Publishable API Key. Associated resources, such as sales channels, are not deleted." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Publishable API Key to delete. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.delete(publishableApiKeyId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeletePublishableApiKey } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const PublishableApiKey = ({ - * publishableApiKeyId - * }: Props) => { - * const deleteKey = useAdminDeletePublishableApiKey( - * publishableApiKeyId - * ) - * // ... - * - * const handleDelete = () => { - * deleteKey.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default PublishableApiKey - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/publishable-api-key/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Publishable Api Keys - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPublishableApiKeyDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - */ - -export default async (req, res) => { - const { id } = req.params - - const publishableApiKeyService: PublishableApiKeyService = req.scope.resolve( - "publishableApiKeyService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - - await manager.transaction(async (transactionManager) => { - await publishableApiKeyService - .withTransaction(transactionManager) - .delete(id) - }) - - res.status(200).send({ - id, - object: "publishable_api_key", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/publishable-api-keys/get-publishable-api-key.ts b/packages/medusa/src/api/routes/admin/publishable-api-keys/get-publishable-api-key.ts deleted file mode 100644 index 7ac3d20251..0000000000 --- a/packages/medusa/src/api/routes/admin/publishable-api-keys/get-publishable-api-key.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { Request, Response } from "express" - -import PublishableApiKeyService from "../../../../services/publishable-api-key" - -/** - * @oas [get] /admin/publishable-api-keys/{id} - * operationId: "GetPublishableApiKeysPublishableApiKey" - * summary: "Get a Publishable API Key" - * description: "Retrieve a publishable API key's details." - * parameters: - * - (path) id=* {string} The ID of the Publishable API Key. - * x-authenticated: true - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.retrieve(publishableApiKeyId) - * .then(({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminPublishableApiKey, - * } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const PublishableApiKey = ({ - * publishableApiKeyId - * }: Props) => { - * const { publishable_api_key, isLoading } = - * useAdminPublishableApiKey( - * publishableApiKeyId - * ) - * - * - * return ( - *
- * {isLoading && Loading...} - * {publishable_api_key && {publishable_api_key.title}} - *
- * ) - * } - * - * export default PublishableApiKey - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/publishable-api-keys/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Publishable Api Keys - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPublishableApiKeysRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const publishableApiKeyService = req.scope.resolve( - "publishableApiKeyService" - ) as PublishableApiKeyService - - const pubKey = await publishableApiKeyService.retrieve(id) - - return res.json({ publishable_api_key: pubKey }) -} diff --git a/packages/medusa/src/api/routes/admin/publishable-api-keys/index.ts b/packages/medusa/src/api/routes/admin/publishable-api-keys/index.ts deleted file mode 100644 index 1616f6564e..0000000000 --- a/packages/medusa/src/api/routes/admin/publishable-api-keys/index.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { Router } from "express" - -import { PublishableApiKey, SalesChannel } from "../../../../models" -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" -import { AdminPostPublishableApiKeySalesChannelsBatchReq } from "./add-channels-batch" -import { AdminPostPublishableApiKeysReq } from "./create-publishable-api-key" -import { AdminDeletePublishableApiKeySalesChannelsBatchReq } from "./delete-channels-batch" -import { GetPublishableApiKeysParams } from "./list-publishable-api-keys" -import { AdminPostPublishableApiKeysPublishableApiKeyReq } from "./update-publishable-api-key" - -const route = Router() - -export default (app) => { - app.use("/publishable-api-keys", route) - - route.post( - "/", - transformBody(AdminPostPublishableApiKeysReq), - middlewares.wrap(require("./create-publishable-api-key").default) - ) - - route.get( - "/:id", - middlewares.wrap(require("./get-publishable-api-key").default) - ) - - route.post( - "/:id", - transformBody(AdminPostPublishableApiKeysPublishableApiKeyReq), - middlewares.wrap(require("./update-publishable-api-key").default) - ) - - route.delete( - "/:id", - middlewares.wrap(require("./delete-publishable-api-key").default) - ) - - route.post( - "/:id/revoke", - middlewares.wrap(require("./revoke-publishable-api-key").default) - ) - - route.get( - "/", - transformQuery(GetPublishableApiKeysParams, { - isList: true, - }), - middlewares.wrap(require("./list-publishable-api-keys").default) - ) - - route.get( - "/:id/sales-channels", - middlewares.wrap( - require("./list-publishable-api-key-sales-channels").default - ) - ) - - route.post( - "/:id/sales-channels/batch", - transformBody(AdminPostPublishableApiKeySalesChannelsBatchReq), - middlewares.wrap(require("./add-channels-batch").default) - ) - - route.delete( - "/:id/sales-channels/batch", - transformBody(AdminDeletePublishableApiKeySalesChannelsBatchReq), - middlewares.wrap(require("./delete-channels-batch").default) - ) -} - -/** - * @schema AdminPublishableApiKeysRes - * type: object - * description: "The publishable API key's details." - * required: - * - publishable_api_key - * properties: - * publishable_api_key: - * description: "Publishable API key details." - * $ref: "#/components/schemas/PublishableApiKey" - */ -export type AdminPublishableApiKeysRes = { - publishable_api_key: PublishableApiKey -} - -/** - * @schema AdminPublishableApiKeysListRes - * type: object - * description: The list of publishable API keys with pagination fields. - * required: - * - publishable_api_keys - * - count - * - offset - * - limit - * properties: - * publishable_api_keys: - * type: array - * description: "An array of publishable API keys details." - * items: - * $ref: "#/components/schemas/PublishableApiKey" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of publishable API keys skipped when retrieving the publishable API keys. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminPublishableApiKeysListRes = PaginatedResponse & { - publishable_api_keys: PublishableApiKey[] -} - -/** - * @schema AdminPublishableApiKeyDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted publishable API key. - * object: - * type: string - * description: The type of the object that was deleted. - * default: publishable_api_key - * deleted: - * type: boolean - * description: Whether the publishable API key was deleted. - * default: true - */ -export type AdminPublishableApiKeyDeleteRes = DeleteResponse - -/** - * @schema AdminPublishableApiKeysListSalesChannelsRes - * type: object - * description: "The list of sales channel." - * required: - * - sales_channels - * properties: - * sales_channels: - * description: "An array of sales channels details." - * type: array - * items: - * $ref: "#/components/schemas/SalesChannel" - */ -export type AdminPublishableApiKeysListSalesChannelsRes = { - sales_channels: SalesChannel[] -} - -export * from "./add-channels-batch" -export * from "./create-publishable-api-key" -export * from "./delete-channels-batch" -export * from "./list-publishable-api-key-sales-channels" -export * from "./list-publishable-api-keys" -export * from "./update-publishable-api-key" diff --git a/packages/medusa/src/api/routes/admin/publishable-api-keys/list-publishable-api-key-sales-channels.ts b/packages/medusa/src/api/routes/admin/publishable-api-keys/list-publishable-api-key-sales-channels.ts deleted file mode 100644 index 8ee0395309..0000000000 --- a/packages/medusa/src/api/routes/admin/publishable-api-keys/list-publishable-api-key-sales-channels.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" - -import PublishableApiKeyService from "../../../../services/publishable-api-key" -import { validator } from "../../../../utils/validator" - -/** - * @oas [get] /admin/publishable-api-keys/{id}/sales-channels - * operationId: "GetPublishableApiKeySalesChannels" - * summary: "List Sales Channels" - * description: "List the sales channels associated with a publishable API key. The sales channels can be filtered by fields such as `q`." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the publishable API key. - * - (query) q {string} query to search sales channels' names and descriptions. - * x-codegen: - * method: listSalesChannels - * queryParams: GetPublishableApiKeySalesChannelsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.listSalesChannels() - * .then(({ sales_channels }) => { - * console.log(sales_channels.length) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminPublishableApiKeySalesChannels, - * } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const SalesChannels = ({ - * publishableApiKeyId - * }: Props) => { - * const { sales_channels, isLoading } = - * useAdminPublishableApiKeySalesChannels( - * publishableApiKeyId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {sales_channels && !sales_channels.length && ( - * No Sales Channels - * )} - * {sales_channels && sales_channels.length > 0 && ( - *
    - * {sales_channels.map((salesChannel) => ( - *
  • {salesChannel.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default SalesChannels - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/publishable-api-keys/{id}/sales-channels' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Publishable Api Keys - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPublishableApiKeysListSalesChannelsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - const publishableApiKeyService: PublishableApiKeyService = req.scope.resolve( - "publishableApiKeyService" - ) - - const validated = await validator( - GetPublishableApiKeySalesChannelsParams, - req.query - ) - - const salesChannels = await publishableApiKeyService.listSalesChannels(id, { - q: validated.q, - }) - - return res.json({ - sales_channels: salesChannels, - }) -} - -/** - * Parameters used to filter the sales channels. - */ -export class GetPublishableApiKeySalesChannelsParams { - /** - * Search term to search sales channels' names and descriptions. - */ - @IsOptional() - @IsString() - q?: string -} diff --git a/packages/medusa/src/api/routes/admin/publishable-api-keys/list-publishable-api-keys.ts b/packages/medusa/src/api/routes/admin/publishable-api-keys/list-publishable-api-keys.ts deleted file mode 100644 index 9fc6d3e40f..0000000000 --- a/packages/medusa/src/api/routes/admin/publishable-api-keys/list-publishable-api-keys.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { IsOptional, IsString, ValidateNested } from "class-validator" -import { Request, Response } from "express" - -import { Type } from "class-transformer" -import PublishableApiKeyService from "../../../../services/publishable-api-key" -import { - DateComparisonOperator, - extendedFindParamsMixin, -} from "../../../../types/common" - -/** - * @oas [get] /admin/publishable-api-keys - * operationId: "GetPublishableApiKeys" - * summary: "List Publishable API keys" - * description: "Retrieve a list of publishable API keys. The publishable API keys can be filtered by fields such as `q`. The publishable API keys can also be paginated." - * x-authenticated: true - * parameters: - * - (query) q {string} term to search publishable API keys' titles. - * - (query) limit=20 {number} Limit the number of publishable API keys returned. - * - (query) offset=0 {number} The number of publishable API keys to skip when retrieving the publishable API keys. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned publishable API keys. - * - (query) fields {string} Comma-separated fields that should be included in the returned publishable API keys. - * - (query) order {string} A field to sort-order the retrieved publishable API keys by. - * - in: query - * name: created_at - * required: false - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * required: false - * description: Filter by a update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: revoked_at - * required: false - * description: Filter by a revocation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: list - * queryParams: GetPublishableApiKeysParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.list() - * .then(({ publishable_api_keys, count, limit, offset }) => { - * console.log(publishable_api_keys) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { PublishableApiKey } from "@medusajs/medusa" - * import { useAdminPublishableApiKeys } from "medusa-react" - * - * const PublishableApiKeys = () => { - * const { publishable_api_keys, isLoading } = - * useAdminPublishableApiKeys() - * - * return ( - *
- * {isLoading && Loading...} - * {publishable_api_keys && !publishable_api_keys.length && ( - * No Publishable API Keys - * )} - * {publishable_api_keys && - * publishable_api_keys.length > 0 && ( - *
    - * {publishable_api_keys.map( - * (publishableApiKey: PublishableApiKey) => ( - *
  • - * {publishableApiKey.title} - *
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default PublishableApiKeys - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/publishable-api-keys' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Publishable Api Keys - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPublishableApiKeysListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const publishableApiKeyService: PublishableApiKeyService = req.scope.resolve( - "publishableApiKeyService" - ) - - const { filterableFields, listConfig } = req - const { skip, take } = listConfig - - const [pubKeys, count] = await publishableApiKeyService.listAndCount( - filterableFields, - listConfig - ) - - return res.json({ - publishable_api_keys: pubKeys, - count, - limit: take, - offset: skip, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved publishable API keys. - */ -export class GetPublishableApiKeysParams extends extendedFindParamsMixin({ - limit: 20, - offset: 0, -}) { - /** - * Search term to search publishable API keys' titles. - */ - @IsString() - @IsOptional() - q?: string - - /** - * A field to sort-order the retrieved publishable API keys by. - */ - @IsString() - @IsOptional() - order?: string - - /** - * Date filters to apply on the publishable API keys' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the publishable API keys' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on the publishable API keys' `revoked_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - revoked_at?: DateComparisonOperator -} diff --git a/packages/medusa/src/api/routes/admin/publishable-api-keys/revoke-publishable-api-key.ts b/packages/medusa/src/api/routes/admin/publishable-api-keys/revoke-publishable-api-key.ts deleted file mode 100644 index 66f26336c7..0000000000 --- a/packages/medusa/src/api/routes/admin/publishable-api-keys/revoke-publishable-api-key.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Request, Response } from "express" -import { EntityManager } from "typeorm" - -import PublishableApiKeyService from "../../../../services/publishable-api-key" - -/** - * @oas [post] /admin/publishable-api-keys/{id}/revoke - * operationId: "PostPublishableApiKeysPublishableApiKeyRevoke" - * summary: "Revoke a Publishable API Key" - * description: "Revoke a Publishable API Key. Revoking the publishable API Key can't be undone, and the key can't be used in future requests." - * parameters: - * - (path) id=* {string} The ID of the Publishable API Key. - * x-authenticated: true - * x-codegen: - * method: revoke - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.revoke(publishableApiKeyId) - * .then(({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminRevokePublishableApiKey } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const PublishableApiKey = ({ - * publishableApiKeyId - * }: Props) => { - * const revokeKey = useAdminRevokePublishableApiKey( - * publishableApiKeyId - * ) - * // ... - * - * const handleRevoke = () => { - * revokeKey.mutate(void 0, { - * onSuccess: ({ publishable_api_key }) => { - * console.log(publishable_api_key.revoked_at) - * } - * }) - * } - * - * // ... - * } - * - * export default PublishableApiKey - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/publishable-api-keys/{id}/revoke' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Publishable Api Keys - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPublishableApiKeysRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const publishableApiKeyService = req.scope.resolve( - "publishableApiKeyService" - ) as PublishableApiKeyService - - const manager = req.scope.resolve("manager") as EntityManager - - const loggedInUserId = (req.user?.id ?? req.user?.userId) as string - - const pubKey = await manager.transaction(async (transactionManager) => { - const publishableApiKeyServiceTx = - publishableApiKeyService.withTransaction(transactionManager) - - await publishableApiKeyServiceTx.revoke(id, { loggedInUserId }) - return await publishableApiKeyServiceTx.retrieve(id) - }) - - return res.json({ publishable_api_key: pubKey }) -} diff --git a/packages/medusa/src/api/routes/admin/publishable-api-keys/update-publishable-api-key.ts b/packages/medusa/src/api/routes/admin/publishable-api-keys/update-publishable-api-key.ts deleted file mode 100644 index ca405db7d9..0000000000 --- a/packages/medusa/src/api/routes/admin/publishable-api-keys/update-publishable-api-key.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { Request, Response } from "express" -import { IsOptional, IsString } from "class-validator" -import { EntityManager } from "typeorm" - -import PublishableApiKeyService from "../../../../services/publishable-api-key" - -/** - * @oas [post] /admin/publishable-api-keys/{id} - * operationId: "PostPublishableApiKysPublishableApiKey" - * summary: "Update Publishable API Key" - * description: "Update a Publishable API Key's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Publishable API Key. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostPublishableApiKeysPublishableApiKeyReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.publishableApiKeys.update(publishableApiKeyId, { - * title: "new title" - * }) - * .then(({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdatePublishableApiKey } from "medusa-react" - * - * type Props = { - * publishableApiKeyId: string - * } - * - * const PublishableApiKey = ({ - * publishableApiKeyId - * }: Props) => { - * const updateKey = useAdminUpdatePublishableApiKey( - * publishableApiKeyId - * ) - * // ... - * - * const handleUpdate = (title: string) => { - * updateKey.mutate({ - * title, - * }, { - * onSuccess: ({ publishable_api_key }) => { - * console.log(publishable_api_key.id) - * } - * }) - * } - * - * // ... - * } - * - * export default PublishableApiKey - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/publishable-api-key/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "title": "new title" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Publishable Api Keys - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPublishableApiKeysRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - const { validatedBody } = req as { - validatedBody: AdminPostPublishableApiKeysPublishableApiKeyReq - } - - const publishableApiKeysService: PublishableApiKeyService = req.scope.resolve( - "publishableApiKeyService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - - const updatedKey = await manager.transaction(async (transactionManager) => { - return await publishableApiKeysService - .withTransaction(transactionManager) - .update(id, validatedBody) - }) - - res.status(200).json({ publishable_api_key: updatedKey }) -} - -/** - * @schema AdminPostPublishableApiKeysPublishableApiKeyReq - * type: object - * description: "The details to update of the publishable API key." - * properties: - * title: - * description: The title of the Publishable API Key. - * type: string - */ -export class AdminPostPublishableApiKeysPublishableApiKeyReq { - @IsString() - @IsOptional() - title?: string -} diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/add-country.js b/packages/medusa/src/api/routes/admin/regions/__tests__/add-country.js deleted file mode 100644 index cb7bdaab39..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/add-country.js +++ /dev/null @@ -1,35 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -describe("POST /admin/regions/:region_id/countries", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - const id = IdMap.getId("testRegion") - subject = await request("POST", `/admin/regions/${id}/countries`, { - payload: { - country_code: "se", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service addCountry", () => { - expect(RegionServiceMock.addCountry).toHaveBeenCalledTimes(1) - expect(RegionServiceMock.addCountry).toHaveBeenCalledWith( - IdMap.getId("testRegion"), - "se" - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/add-fulfillment-provider.js b/packages/medusa/src/api/routes/admin/regions/__tests__/add-fulfillment-provider.js deleted file mode 100644 index 74b9df9f9f..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/add-fulfillment-provider.js +++ /dev/null @@ -1,39 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -describe("POST /admin/regions/:region_id/fulfillment-providers", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - const id = IdMap.getId("testRegion") - subject = await request( - "POST", - `/admin/regions/${id}/fulfillment-providers`, - { - payload: { - provider_id: "default_provider", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service addCountry", () => { - expect(RegionServiceMock.addFulfillmentProvider).toHaveBeenCalledTimes(1) - expect(RegionServiceMock.addFulfillmentProvider).toHaveBeenCalledWith( - IdMap.getId("testRegion"), - "default_provider" - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/add-payment-provider.js b/packages/medusa/src/api/routes/admin/regions/__tests__/add-payment-provider.js deleted file mode 100644 index 4f8417d746..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/add-payment-provider.js +++ /dev/null @@ -1,39 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -describe("POST /admin/regions/:region_id/payment-providers", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - const id = IdMap.getId("testRegion") - subject = await request( - "POST", - `/admin/regions/${id}/payment-providers`, - { - payload: { - provider_id: "default_provider", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service addCountry", () => { - expect(RegionServiceMock.addPaymentProvider).toHaveBeenCalledTimes(1) - expect(RegionServiceMock.addPaymentProvider).toHaveBeenCalledWith( - IdMap.getId("testRegion"), - "default_provider" - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/create-region.js b/packages/medusa/src/api/routes/admin/regions/__tests__/create-region.js deleted file mode 100644 index d009b81b9b..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/create-region.js +++ /dev/null @@ -1,43 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -describe("POST /admin/regions", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/regions", { - payload: { - name: "New Region", - currency_code: "dkk", - countries: ["dk"], - tax_rate: 0.3, - payment_providers: ["default_provider"], - fulfillment_providers: ["default_provider"], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service create", () => { - expect(RegionServiceMock.create).toHaveBeenCalledTimes(1) - expect(RegionServiceMock.create).toHaveBeenCalledWith({ - name: "New Region", - currency_code: "dkk", - countries: ["dk"], - tax_rate: 0.3, - payment_providers: ["default_provider"], - fulfillment_providers: ["default_provider"], - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/delete-region.js b/packages/medusa/src/api/routes/admin/regions/__tests__/delete-region.js deleted file mode 100644 index 1031d00917..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/delete-region.js +++ /dev/null @@ -1,31 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -describe("DELETE /admin/regions/:region_id", () => { - describe("successful deletion", () => { - let subject - - beforeAll(async () => { - const id = IdMap.getId("region") - subject = await request("DELETE", `/admin/regions/${id}`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service addCountry", () => { - expect(RegionServiceMock.delete).toHaveBeenCalledTimes(1) - expect(RegionServiceMock.delete).toHaveBeenCalledWith( - IdMap.getId("region") - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/get-region.js b/packages/medusa/src/api/routes/admin/regions/__tests__/get-region.js deleted file mode 100644 index 072434e933..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/get-region.js +++ /dev/null @@ -1,60 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -const defaultFields = [ - "id", - "name", - "automatic_taxes", - "gift_cards_taxable", - "tax_provider_id", - "currency_code", - "tax_rate", - "tax_code", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -const defaultRelations = [ - "countries", - "currency", - "fulfillment_providers", - "payment_providers", -] - -describe("GET /admin/regions/:region_id", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - const id = IdMap.getId("testRegion") - subject = await request("GET", `/admin/regions/${id}`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service addCountry", () => { - expect(RegionServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect( - RegionServiceMock.retrieve.mock.calls[0][1].relations - ).toHaveLength(defaultRelations.length) - expect(RegionServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("testRegion"), - { - select: defaultFields, - relations: expect.arrayContaining(defaultRelations), - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/list-regions.js b/packages/medusa/src/api/routes/admin/regions/__tests__/list-regions.js deleted file mode 100644 index d3591fe21b..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/list-regions.js +++ /dev/null @@ -1,105 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -const defaultFields = [ - "id", - "name", - "automatic_taxes", - "gift_cards_taxable", - "tax_provider_id", - "currency_code", - "tax_rate", - "tax_code", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -const defaultRelations = [ - "countries", - "currency", - "fulfillment_providers", - "payment_providers", -] - -describe("GET /admin/regions", () => { - describe("successfully lists regions", () => { - let subject - - afterAll(() => { - jest.clearAllMocks() - }) - - beforeAll(async () => { - subject = await request("GET", `/admin/regions`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service list", () => { - expect(RegionServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect( - RegionServiceMock.listAndCount.mock.calls[0][1].relations - ).toHaveLength(defaultRelations.length) - expect(RegionServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - { - select: defaultFields, - relations: expect.arrayContaining(defaultRelations), - take: 50, - skip: 0, - order: { created_at: "DESC" }, - } - ) - }) - }) - - describe("successfully lists regions with limit and offset", () => { - let subject - - afterAll(() => { - jest.clearAllMocks() - }) - - beforeAll(async () => { - subject = await request("GET", `/admin/regions?offset=10&limit=20`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service list", () => { - expect(RegionServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect( - RegionServiceMock.listAndCount.mock.calls[0][1].relations - ).toHaveLength(defaultRelations.length) - expect(RegionServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - { - select: defaultFields, - relations: expect.arrayContaining(defaultRelations), - take: 20, - skip: 10, - order: { created_at: "DESC" }, - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/remove-country.js b/packages/medusa/src/api/routes/admin/regions/__tests__/remove-country.js deleted file mode 100644 index b82efa0385..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/remove-country.js +++ /dev/null @@ -1,32 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -describe("DELETE /admin/regions/:region_id/countries/:country_code", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - const id = IdMap.getId("region") - subject = await request("DELETE", `/admin/regions/${id}/countries/DK`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service addCountry", () => { - expect(RegionServiceMock.removeCountry).toHaveBeenCalledTimes(1) - expect(RegionServiceMock.removeCountry).toHaveBeenCalledWith( - IdMap.getId("region"), - "DK" - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/remove-fulfillment-provider.js b/packages/medusa/src/api/routes/admin/regions/__tests__/remove-fulfillment-provider.js deleted file mode 100644 index 7829d8d5f2..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/remove-fulfillment-provider.js +++ /dev/null @@ -1,38 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -describe("DELETE /admin/regions/:region_id/fulfillment-providers/:provider_id", () => { - describe("successful deletion", () => { - let subject - - beforeAll(async () => { - const id = IdMap.getId("region") - subject = await request( - "DELETE", - `/admin/regions/${id}/fulfillment-providers/default_provider`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service addCountry", () => { - expect(RegionServiceMock.removeFulfillmentProvider).toHaveBeenCalledTimes( - 1 - ) - expect(RegionServiceMock.removeFulfillmentProvider).toHaveBeenCalledWith( - IdMap.getId("region"), - "default_provider" - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/remove-payment-provider.js b/packages/medusa/src/api/routes/admin/regions/__tests__/remove-payment-provider.js deleted file mode 100644 index de9cdec282..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/remove-payment-provider.js +++ /dev/null @@ -1,36 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -describe("DELETE /admin/regions/:region_id/payment-providers/:provider_id", () => { - describe("successful deletion", () => { - let subject - - beforeAll(async () => { - const id = IdMap.getId("region") - subject = await request( - "DELETE", - `/admin/regions/${id}/payment-providers/default_provider`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service addCountry", () => { - expect(RegionServiceMock.removePaymentProvider).toHaveBeenCalledTimes(1) - expect(RegionServiceMock.removePaymentProvider).toHaveBeenCalledWith( - IdMap.getId("region"), - "default_provider" - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/update-region.js b/packages/medusa/src/api/routes/admin/regions/__tests__/update-region.js deleted file mode 100644 index 23de8a3821..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/update-region.js +++ /dev/null @@ -1,47 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -describe("POST /admin/regions/:region_id", () => { - describe("successful deletion", () => { - let subject - - beforeAll(async () => { - const id = IdMap.getId("region") - subject = await request("POST", `/admin/regions/${id}`, { - payload: { - name: "Updated Region", - currency_code: "dkk", - countries: ["dk"], - tax_rate: 0.3, - payment_providers: ["default_provider"], - fulfillment_providers: ["default_provider"], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service addCountry", () => { - expect(RegionServiceMock.update).toHaveBeenCalledTimes(1) - expect(RegionServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("region"), - { - name: "Updated Region", - currency_code: "dkk", - countries: ["dk"], - tax_rate: 0.3, - payment_providers: ["default_provider"], - fulfillment_providers: ["default_provider"], - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/regions/add-country.ts b/packages/medusa/src/api/routes/admin/regions/add-country.ts deleted file mode 100644 index 9462eb8a8b..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/add-country.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { defaultAdminRegionFields, defaultAdminRegionRelations } from "." - -import { EntityManager } from "typeorm" -import { IsString } from "class-validator" -import { Region } from "../../../.." -import RegionService from "../../../../services/region" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/regions/{id}/countries - * operationId: "PostRegionsRegionCountries" - * summary: "Add Country" - * description: "Add a Country to the list of Countries in a Region." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Region. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostRegionsRegionCountriesReq" - * x-codegen: - * method: addCountry - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.addCountry(regionId, { - * country_code: "dk" - * }) - * .then(({ region }) => { - * console.log(region.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminRegionAddCountry } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const addCountry = useAdminRegionAddCountry(regionId) - * // ... - * - * const handleAddCountry = ( - * countryCode: string - * ) => { - * addCountry.mutate({ - * country_code: countryCode - * }, { - * onSuccess: ({ region }) => { - * console.log(region.countries) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/regions/{region_id}/countries' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "country_code": "dk" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminRegionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { region_id } = req.params - const validated = await validator( - AdminPostRegionsRegionCountriesReq, - req.body - ) - - const regionService: RegionService = req.scope.resolve("regionService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await regionService - .withTransaction(transactionManager) - .addCountry(region_id, validated.country_code) - }) - - const region: Region = await regionService.retrieve(region_id, { - select: defaultAdminRegionFields, - relations: defaultAdminRegionRelations, - }) - - res.status(200).json({ region }) -} - -/** - * @schema AdminPostRegionsRegionCountriesReq - * type: object - * description: "The details of the country to add to the region." - * required: - * - country_code - * properties: - * country_code: - * description: "The 2 character ISO code for the Country." - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements - * description: See a list of codes. - */ -export class AdminPostRegionsRegionCountriesReq { - @IsString() - country_code: string -} diff --git a/packages/medusa/src/api/routes/admin/regions/add-fulfillment-provider.ts b/packages/medusa/src/api/routes/admin/regions/add-fulfillment-provider.ts deleted file mode 100644 index 4f63d4d4e6..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/add-fulfillment-provider.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { defaultAdminRegionFields, defaultAdminRegionRelations } from "." - -import { EntityManager } from "typeorm" -import { IsString } from "class-validator" -import { Region } from "../../../.." -import RegionService from "../../../../services/region" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/regions/{id}/fulfillment-providers - * operationId: "PostRegionsRegionFulfillmentProviders" - * summary: "Add Fulfillment Provider" - * description: "Add a Fulfillment Provider to the list of fulfullment providers in a Region." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Region. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostRegionsRegionFulfillmentProvidersReq" - * x-codegen: - * method: addFulfillmentProvider - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.addFulfillmentProvider(regionId, { - * provider_id: "manual" - * }) - * .then(({ region }) => { - * console.log(region.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminRegionAddFulfillmentProvider - * } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const addFulfillmentProvider = - * useAdminRegionAddFulfillmentProvider(regionId) - * // ... - * - * const handleAddFulfillmentProvider = ( - * providerId: string - * ) => { - * addFulfillmentProvider.mutate({ - * provider_id: providerId - * }, { - * onSuccess: ({ region }) => { - * console.log(region.fulfillment_providers) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/regions/{id}/fulfillment-providers' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "provider_id": "manual" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminRegionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { region_id } = req.params - const validated = await validator( - AdminPostRegionsRegionFulfillmentProvidersReq, - req.body - ) - - const regionService: RegionService = req.scope.resolve("regionService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await regionService - .withTransaction(transactionManager) - .addFulfillmentProvider(region_id, validated.provider_id) - }) - - const region: Region = await regionService.retrieve(region_id, { - select: defaultAdminRegionFields, - relations: defaultAdminRegionRelations, - }) - res.status(200).json({ region }) -} - -/** - * @schema AdminPostRegionsRegionFulfillmentProvidersReq - * type: object - * description: "The details of the fulfillment provider to add to the region." - * required: - * - provider_id - * properties: - * provider_id: - * description: "The ID of the Fulfillment Provider." - * type: string - */ -export class AdminPostRegionsRegionFulfillmentProvidersReq { - @IsString() - provider_id: string -} diff --git a/packages/medusa/src/api/routes/admin/regions/add-payment-provider.ts b/packages/medusa/src/api/routes/admin/regions/add-payment-provider.ts deleted file mode 100644 index 8808bd059e..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/add-payment-provider.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { defaultAdminRegionFields, defaultAdminRegionRelations } from "." - -import { EntityManager } from "typeorm" -import { IsString } from "class-validator" -import { Region } from "../../../.." -import RegionService from "../../../../services/region" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/regions/{id}/payment-providers - * operationId: "PostRegionsRegionPaymentProviders" - * summary: "Add Payment Provider" - * description: "Add a Payment Provider to the list of payment providers in a Region." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Region. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostRegionsRegionPaymentProvidersReq" - * x-codegen: - * method: addPaymentProvider - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.addPaymentProvider(regionId, { - * provider_id: "manual" - * }) - * .then(({ region }) => { - * console.log(region.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminRegionAddPaymentProvider - * } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const addPaymentProvider = - * useAdminRegionAddPaymentProvider(regionId) - * // ... - * - * const handleAddPaymentProvider = ( - * providerId: string - * ) => { - * addPaymentProvider.mutate({ - * provider_id: providerId - * }, { - * onSuccess: ({ region }) => { - * console.log(region.payment_providers) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/regions/{id}/payment-providers' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "provider_id": "manual" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminRegionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { region_id } = req.params - const validated = await validator( - AdminPostRegionsRegionPaymentProvidersReq, - req.body - ) - - const regionService: RegionService = req.scope.resolve("regionService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await regionService - .withTransaction(transactionManager) - .addPaymentProvider(region_id, validated.provider_id) - }) - - const region: Region = await regionService.retrieve(region_id, { - select: defaultAdminRegionFields, - relations: defaultAdminRegionRelations, - }) - res.status(200).json({ region }) -} - -/** - * @schema AdminPostRegionsRegionPaymentProvidersReq - * type: object - * description: "The details of the payment provider to add to the region." - * required: - * - provider_id - * properties: - * provider_id: - * description: "The ID of the Payment Provider." - * type: string - */ -export class AdminPostRegionsRegionPaymentProvidersReq { - @IsString() - provider_id: string -} diff --git a/packages/medusa/src/api/routes/admin/regions/create-region.ts b/packages/medusa/src/api/routes/admin/regions/create-region.ts deleted file mode 100644 index aec64cc919..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/create-region.ts +++ /dev/null @@ -1,235 +0,0 @@ -import { - IsArray, - IsBoolean, - IsNumber, - IsObject, - IsOptional, - IsString, -} from "class-validator" -import { EntityManager } from "typeorm" -import { defaultAdminRegionFields, defaultAdminRegionRelations } from "." -import { Region } from "../../../.." -import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" -import RegionService from "../../../../services/region" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/regions - * operationId: "PostRegions" - * summary: "Create a Region" - * description: "Create a Region." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostRegionsReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.create({ - * name: "Europe", - * currency_code: "eur", - * tax_rate: 0, - * payment_providers: [ - * "manual" - * ], - * fulfillment_providers: [ - * "manual" - * ], - * countries: [ - * "DK" - * ] - * }) - * .then(({ region }) => { - * console.log(region.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateRegion } from "medusa-react" - * - * type CreateData = { - * name: string - * currency_code: string - * tax_rate: number - * payment_providers: string[] - * fulfillment_providers: string[] - * countries: string[] - * } - * - * const CreateRegion = () => { - * const createRegion = useAdminCreateRegion() - * // ... - * - * const handleCreate = (regionData: CreateData) => { - * createRegion.mutate(regionData, { - * onSuccess: ({ region }) => { - * console.log(region.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateRegion - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/regions' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "Europe", - * "currency_code": "eur", - * "tax_rate": 0, - * "payment_providers": [ - * "manual" - * ], - * "fulfillment_providers": [ - * "manual" - * ], - * "countries": [ - * "DK" - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminRegionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminPostRegionsReq, req.body) - - const regionService: RegionService = req.scope.resolve("regionService") - const manager: EntityManager = req.scope.resolve("manager") - const result: Region = await manager.transaction( - async (transactionManager) => { - return await regionService - .withTransaction(transactionManager) - .create(validated) - } - ) - - const region: Region = await regionService.retrieve(result.id, { - select: defaultAdminRegionFields, - relations: defaultAdminRegionRelations, - }) - - res.status(200).json({ region }) -} - -/** - * @schema AdminPostRegionsReq - * type: object - * description: "The details of the region to create." - * required: - * - name - * - currency_code - * - tax_rate - * - payment_providers - * - fulfillment_providers - * - countries - * properties: - * name: - * description: "The name of the Region" - * type: string - * currency_code: - * description: "The 3 character ISO currency code to use in the Region." - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * tax_code: - * description: "The tax code of the Region." - * type: string - * tax_rate: - * description: "The tax rate to use in the Region." - * type: number - * payment_providers: - * description: "A list of Payment Provider IDs that can be used in the Region" - * type: array - * items: - * type: string - * fulfillment_providers: - * description: "A list of Fulfillment Provider IDs that can be used in the Region" - * type: array - * items: - * type: string - * countries: - * description: "A list of countries' 2 ISO characters that should be included in the Region." - * example: ["US"] - * type: array - * items: - * type: string - * includes_tax: - * x-featureFlag: "tax_inclusive_pricing" - * description: "Whether taxes are included in the prices of the region." - * type: boolean - */ -export class AdminPostRegionsReq { - @IsString() - name: string - - @IsString() - currency_code: string - - @IsString() - @IsOptional() - tax_code?: string - - @IsNumber() - tax_rate: number - - @IsArray() - @IsString({ each: true }) - payment_providers: string[] - - @IsArray() - @IsString({ each: true }) - fulfillment_providers: string[] - - @IsArray() - @IsString({ each: true }) - countries: string[] - - @FeatureFlagDecorators(TaxInclusivePricingFeatureFlag.key, [ - IsOptional(), - IsBoolean(), - ]) - includes_tax?: boolean - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/regions/delete-region.ts b/packages/medusa/src/api/routes/admin/regions/delete-region.ts deleted file mode 100644 index 19dacc199b..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/delete-region.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { EntityManager } from "typeorm" -import RegionService from "../../../../services/region" - -/** - * @oas [delete] /admin/regions/{id} - * operationId: "DeleteRegionsRegion" - * summary: "Delete a Region" - * description: "Delete a Region. Associated resources, such as providers or currencies are not deleted. Associated tax rates are deleted." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Region. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.delete(regionId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteRegion } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const deleteRegion = useAdminDeleteRegion(regionId) - * // ... - * - * const handleDelete = () => { - * deleteRegion.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/regions/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminRegionsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { region_id } = req.params - - const regionService: RegionService = req.scope.resolve("regionService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await regionService - .withTransaction(transactionManager) - .delete(region_id) - }) - - res.status(200).json({ - id: region_id, - object: "region", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/regions/get-fulfillment-options.ts b/packages/medusa/src/api/routes/admin/regions/get-fulfillment-options.ts deleted file mode 100644 index 9d30d4f8a6..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/get-fulfillment-options.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { FulfillmentOption } from "." -import FulfillmentProviderService from "../../../../services/fulfillment-provider" -import RegionService from "../../../../services/region" - -/** - * @oas [get] /admin/regions/{id}/fulfillment-options - * operationId: "GetRegionsRegionFulfillmentOptions" - * summary: "List Fulfillment Options" - * description: "Retrieve a list of fulfillment options available in a Region." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Region. - * x-codegen: - * method: retrieveFulfillmentOptions - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.retrieveFulfillmentOptions(regionId) - * .then(({ fulfillment_options }) => { - * console.log(fulfillment_options.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminRegionFulfillmentOptions } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const { - * fulfillment_options, - * isLoading - * } = useAdminRegionFulfillmentOptions( - * regionId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {fulfillment_options && !fulfillment_options.length && ( - * No Regions - * )} - * {fulfillment_options && - * fulfillment_options.length > 0 && ( - *
    - * {fulfillment_options.map((option) => ( - *
  • - * {option.provider_id} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Region - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/regions/{id}/fulfillment-options' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminGetRegionsRegionFulfillmentOptionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { region_id } = req.params - - const fulfillmentProviderService: FulfillmentProviderService = - req.scope.resolve("fulfillmentProviderService") - - const regionService: RegionService = req.scope.resolve("regionService") - const region = await regionService.retrieve(region_id, { - relations: ["fulfillment_providers"], - }) - - const fpsIds = region.fulfillment_providers.map((fp) => fp.id) || [] - - const options: FulfillmentOption[] = - await fulfillmentProviderService.listFulfillmentOptions(fpsIds) - - res.status(200).json({ - fulfillment_options: options, - }) -} diff --git a/packages/medusa/src/api/routes/admin/regions/get-region.ts b/packages/medusa/src/api/routes/admin/regions/get-region.ts deleted file mode 100644 index 5ff251c29f..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/get-region.ts +++ /dev/null @@ -1,91 +0,0 @@ -import RegionService from "../../../../services/region" -import { FindParams } from "../../../../types/common" - -/** - * @oas [get] /admin/regions/{id} - * operationId: "GetRegionsRegion" - * summary: "Get a Region" - * description: "Retrieve a Region's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Region. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.retrieve(regionId) - * .then(({ region }) => { - * console.log(region.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminRegion } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const { region, isLoading } = useAdminRegion( - * regionId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {region && {region.name}} - *
- * ) - * } - * - * export default Region - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/regions/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminRegionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { region_id } = req.params - const regionService: RegionService = req.scope.resolve("regionService") - - const region = await regionService.retrieve(region_id, req.retrieveConfig) - - res.status(200).json({ region }) -} - -export class AdminGetRegionsRegionParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/regions/index.ts b/packages/medusa/src/api/routes/admin/regions/index.ts deleted file mode 100644 index c564b3e224..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/index.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { FlagRouter, wrapHandler } from "@medusajs/utils" -import { Router } from "express" -import "reflect-metadata" -import { Region } from "../../../.." -import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import { transformQuery } from "../../../middlewares" -import getRegion, { AdminGetRegionsRegionParams } from "./get-region" -import listRegions, { AdminGetRegionsParams } from "./list-regions" - -const route = Router() - -export default (app, featureFlagRouter: FlagRouter) => { - app.use("/regions", route) - - if (featureFlagRouter.isFeatureEnabled(TaxInclusivePricingFeatureFlag.key)) { - defaultAdminRegionFields.push("includes_tax") - } - - const retrieveTransformQueryConfig = { - defaultFields: defaultAdminRegionFields, - defaultRelations: defaultAdminRegionRelations, - allowedRelations: defaultAdminRegionRelations, - isList: false, - } - - const listTransformQueryConfig = { - ...retrieveTransformQueryConfig, - isList: true, - } - - route.get( - "/", - transformQuery(AdminGetRegionsParams, listTransformQueryConfig), - wrapHandler(listRegions) - ) - - route.get( - "/:region_id", - transformQuery(AdminGetRegionsRegionParams, retrieveTransformQueryConfig), - wrapHandler(getRegion) - ) - - route.get( - "/:region_id/fulfillment-options", - wrapHandler(require("./get-fulfillment-options").default) - ) - - route.post("/", wrapHandler(require("./create-region").default)) - route.post("/:region_id", wrapHandler(require("./update-region").default)) - - route.delete("/:region_id", wrapHandler(require("./delete-region").default)) - - route.post( - "/:region_id/countries", - wrapHandler(require("./add-country").default) - ) - route.delete( - "/:region_id/countries/:country_code", - wrapHandler(require("./remove-country").default) - ) - - route.post( - "/:region_id/payment-providers", - wrapHandler(require("./add-payment-provider").default) - ) - route.delete( - "/:region_id/payment-providers/:provider_id", - wrapHandler(require("./remove-payment-provider").default) - ) - - route.post( - "/:region_id/fulfillment-providers", - wrapHandler(require("./add-fulfillment-provider").default) - ) - route.delete( - "/:region_id/fulfillment-providers/:provider_id", - wrapHandler(require("./remove-fulfillment-provider").default) - ) - - return app -} - -export const defaultAdminRegionFields: (keyof Region)[] = [ - "id", - "name", - "automatic_taxes", - "gift_cards_taxable", - "tax_provider_id", - "currency_code", - "tax_rate", - "tax_code", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -export const defaultAdminRegionRelations = [ - "countries", - "payment_providers", - "fulfillment_providers", - "currency", -] - -/** - * @schema AdminRegionsRes - * type: object - * description: "The region's details." - * x-expanded-relations: - * field: region - * relations: - * - countries - * - fulfillment_providers - * - payment_providers - * eager: - * - fulfillment_providers - * - payment_providers - * required: - * - region - * properties: - * region: - * description: "Region details." - * $ref: "#/components/schemas/Region" - */ -export type AdminRegionsRes = { - region: Region -} - -/** - * @schema AdminRegionsListRes - * type: object - * description: "The list of regions with pagination fields." - * x-expanded-relations: - * field: regions - * relations: - * - countries - * - fulfillment_providers - * - payment_providers - * eager: - * - fulfillment_providers - * - payment_providers - * required: - * - regions - * - count - * - offset - * - limit - * properties: - * regions: - * type: array - * description: "An array of regions details." - * items: - * $ref: "#/components/schemas/Region" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of regions skipped when retrieving the regions. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminRegionsListRes = PaginatedResponse & { - regions: Region[] -} - -/** - * @schema AdminRegionsDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Region. - * object: - * type: string - * description: The type of the object that was deleted. - * default: region - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminRegionsDeleteRes = DeleteResponse - -export class FulfillmentOption { - provider_id: string - options: unknown[] -} - -/** - * @schema AdminGetRegionsRegionFulfillmentOptionsRes - * type: object - * description: "The list of fulfillment options in a region." - * required: - * - fulfillment_options - * properties: - * fulfillment_options: - * type: array - * description: Fulfillment providers details. - * items: - * type: object - * required: - * - provider_id - * - options - * properties: - * provider_id: - * description: ID of the fulfillment provider - * type: string - * options: - * description: fulfillment provider options - * type: array - * items: - * type: object - * example: - * - id: "manual-fulfillment" - * - id: "manual-fulfillment-return" - * is_return: true - */ -export class AdminGetRegionsRegionFulfillmentOptionsRes { - fulfillment_options: FulfillmentOption[] -} - -export * from "./add-country" -export * from "./add-fulfillment-provider" -export * from "./add-payment-provider" -export * from "./create-region" -export * from "./list-regions" -export * from "./update-region" -export * from "./get-region" diff --git a/packages/medusa/src/api/routes/admin/regions/list-regions.ts b/packages/medusa/src/api/routes/admin/regions/list-regions.ts deleted file mode 100644 index 22a0e28b44..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/list-regions.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { Type } from "class-transformer" -import { IsOptional, IsString, ValidateNested } from "class-validator" -import RegionService from "../../../../services/region" -import { - DateComparisonOperator, - extendedFindParamsMixin, -} from "../../../../types/common" - -/** - * @oas [get] /admin/regions - * operationId: "GetRegions" - * summary: "List Regions" - * description: "Retrieve a list of Regions. The regions can be filtered by fields such as `created_at`. The regions can also be paginated." - * x-authenticated: true - * parameters: - * - (query) q {string} Term used to search regions' name. - * - (query) order {string} A field to sort-order the retrieved regions by. - * - in: query - * name: limit - * schema: - * type: integer - * default: 50 - * required: false - * description: Limit the number of regions returned. - * - in: query - * name: offset - * schema: - * type: integer - * default: 0 - * required: false - * description: The number of regions to skip when retrieving the regions. - * - in: query - * name: created_at - * required: false - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * required: false - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: deleted_at - * required: false - * description: Filter by a deletion date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: list - * queryParams: AdminGetRegionsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.list() - * .then(({ regions, limit, offset, count }) => { - * console.log(regions.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminRegions } from "medusa-react" - * - * const Regions = () => { - * const { regions, isLoading } = useAdminRegions() - * - * return ( - *
- * {isLoading && Loading...} - * {regions && !regions.length && No Regions} - * {regions && regions.length > 0 && ( - *
    - * {regions.map((region) => ( - *
  • {region.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Regions - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/regions' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminRegionsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const regionService: RegionService = req.scope.resolve("regionService") - const { limit, offset } = req.validatedQuery - - const [regions, count] = await regionService.listAndCount( - req.filterableFields, - req.listConfig - ) - - res.json({ - regions, - count, - offset, - limit, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved regions. - */ -export class AdminGetRegionsParams extends extendedFindParamsMixin({ - limit: 50, - offset: 0, -}) { - /** - * Search parameter for regions. - */ - @IsString() - @IsOptional() - q?: string - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string - - /** - * Date filters to apply on the regions' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the regions' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on the regions' `deleted_at` date. - */ - @ValidateNested() - @IsOptional() - @Type(() => DateComparisonOperator) - deleted_at?: DateComparisonOperator -} diff --git a/packages/medusa/src/api/routes/admin/regions/remove-country.ts b/packages/medusa/src/api/routes/admin/regions/remove-country.ts deleted file mode 100644 index 727c3b453d..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/remove-country.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { defaultAdminRegionFields, defaultAdminRegionRelations } from "." - -import { EntityManager } from "typeorm" -import RegionService from "../../../../services/region" - -/** - * @oas [delete] /admin/regions/{id}/countries/{country_code} - * operationId: "PostRegionsRegionCountriesCountry" - * summary: "Remove Country" - * x-authenticated: true - * description: "Remove a Country from the list of Countries in a Region. The country will still be available in the system, and it can be used in other regions." - * parameters: - * - (path) id=* {string} The ID of the Region. - * - in: path - * name: country_code - * description: The 2 character ISO code for the Country. - * required: true - * schema: - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * x-codegen: - * method: deleteCountry - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.deleteCountry(regionId, "dk") - * .then(({ region }) => { - * console.log(region.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminRegionRemoveCountry } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const removeCountry = useAdminRegionRemoveCountry(regionId) - * // ... - * - * const handleRemoveCountry = ( - * countryCode: string - * ) => { - * removeCountry.mutate(countryCode, { - * onSuccess: ({ region }) => { - * console.log(region.countries) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/regions/{id}/countries/{country_code}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminRegionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { region_id, country_code } = req.params - - const regionService: RegionService = req.scope.resolve("regionService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await regionService - .withTransaction(transactionManager) - .removeCountry(region_id, country_code) - }) - - const region = await regionService.retrieve(region_id, { - select: defaultAdminRegionFields, - relations: defaultAdminRegionRelations, - }) - - res.json({ region }) -} diff --git a/packages/medusa/src/api/routes/admin/regions/remove-fulfillment-provider.ts b/packages/medusa/src/api/routes/admin/regions/remove-fulfillment-provider.ts deleted file mode 100644 index 64ad50a5ce..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/remove-fulfillment-provider.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { defaultAdminRegionFields, defaultAdminRegionRelations } from "." - -import { EntityManager } from "typeorm" -import RegionService from "../../../../services/region" - -/** - * @oas [delete] /admin/regions/{id}/fulfillment-providers/{provider_id} - * operationId: "PostRegionsRegionFulfillmentProvidersProvider" - * summary: "Remove Fulfillment Provider" - * description: "Remove a Fulfillment Provider from a Region. The fulfillment provider will still be available for usage in other regions." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Region. - * - (path) provider_id=* {string} The ID of the Fulfillment Provider. - * x-codegen: - * method: deleteFulfillmentProvider - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.deleteFulfillmentProvider(regionId, "manual") - * .then(({ region }) => { - * console.log(region.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminRegionDeleteFulfillmentProvider - * } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const removeFulfillmentProvider = - * useAdminRegionDeleteFulfillmentProvider(regionId) - * // ... - * - * const handleRemoveFulfillmentProvider = ( - * providerId: string - * ) => { - * removeFulfillmentProvider.mutate(providerId, { - * onSuccess: ({ region }) => { - * console.log(region.fulfillment_providers) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/regions/{id}/fulfillment-providers/{provider_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminRegionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { region_id, provider_id } = req.params - const regionService: RegionService = req.scope.resolve("regionService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await regionService - .withTransaction(transactionManager) - .removeFulfillmentProvider(region_id, provider_id) - }) - - const region = await regionService.retrieve(region_id, { - select: defaultAdminRegionFields, - relations: defaultAdminRegionRelations, - }) - - res.json({ region }) -} diff --git a/packages/medusa/src/api/routes/admin/regions/remove-payment-provider.ts b/packages/medusa/src/api/routes/admin/regions/remove-payment-provider.ts deleted file mode 100644 index c49c47adb9..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/remove-payment-provider.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { defaultAdminRegionFields, defaultAdminRegionRelations } from "." - -import { EntityManager } from "typeorm" -import RegionService from "../../../../services/region" - -/** - * @oas [delete] /admin/regions/{id}/payment-providers/{provider_id} - * operationId: "PostRegionsRegionPaymentProvidersProvider" - * summary: "Remove Payment Provider" - * description: "Remove a Payment Provider from a Region. The payment provider will still be available for usage in other regions." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Region. - * - (path) provider_id=* {string} The ID of the Payment Provider. - * x-codegen: - * method: deletePaymentProvider - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.deletePaymentProvider(regionId, "manual") - * .then(({ region }) => { - * console.log(region.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminRegionDeletePaymentProvider - * } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const removePaymentProvider = - * useAdminRegionDeletePaymentProvider(regionId) - * // ... - * - * const handleRemovePaymentProvider = ( - * providerId: string - * ) => { - * removePaymentProvider.mutate(providerId, { - * onSuccess: ({ region }) => { - * console.log(region.payment_providers) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/regions/{id}/payment-providers/{provider_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminRegionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { region_id, provider_id } = req.params - - const regionService: RegionService = req.scope.resolve("regionService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await regionService - .withTransaction(transactionManager) - .removePaymentProvider(region_id, provider_id) - }) - - const region = await regionService.retrieve(region_id, { - select: defaultAdminRegionFields, - relations: defaultAdminRegionRelations, - }) - - res.json({ region }) -} diff --git a/packages/medusa/src/api/routes/admin/regions/update-region.ts b/packages/medusa/src/api/routes/admin/regions/update-region.ts deleted file mode 100644 index d00f1e891b..0000000000 --- a/packages/medusa/src/api/routes/admin/regions/update-region.ts +++ /dev/null @@ -1,240 +0,0 @@ -import { - IsArray, - IsBoolean, - IsNumber, - IsObject, - IsOptional, - IsString, -} from "class-validator" -import { EntityManager } from "typeorm" - -import { defaultAdminRegionFields, defaultAdminRegionRelations } from "." -import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" -import RegionService from "../../../../services/region" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/regions/{id} - * operationId: "PostRegionsRegion" - * summary: "Update a Region" - * description: "Update a Region's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Region. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostRegionsRegionReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.regions.update(regionId, { - * name: "Europe" - * }) - * .then(({ region }) => { - * console.log(region.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateRegion } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ - * regionId - * }: Props) => { - * const updateRegion = useAdminUpdateRegion(regionId) - * // ... - * - * const handleUpdate = ( - * countries: string[] - * ) => { - * updateRegion.mutate({ - * countries, - * }, { - * onSuccess: ({ region }) => { - * console.log(region.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/regions/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "Europe" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminRegionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { region_id } = req.params - const validated = await validator(AdminPostRegionsRegionReq, req.body) - - const regionService: RegionService = req.scope.resolve("regionService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await regionService - .withTransaction(transactionManager) - .update(region_id, validated) - }) - - const region = await regionService.retrieve(region_id, { - select: defaultAdminRegionFields, - relations: defaultAdminRegionRelations, - }) - - res.status(200).json({ region }) -} - -/** - * @schema AdminPostRegionsRegionReq - * type: object - * description: "The details to update of the regions." - * properties: - * name: - * description: "The name of the Region" - * type: string - * currency_code: - * description: "The 3 character ISO currency code to use in the Region." - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * automatic_taxes: - * description: >- - * If set to `true`, the Medusa backend will automatically calculate taxes for carts in this region. If set to `false`, the taxes must be calculated manually. - * externalDocs: - * url: https://docs.medusajs.com/modules/taxes/storefront/manual-calculation - * description: How to calculate taxes in a storefront. - * type: boolean - * gift_cards_taxable: - * description: >- - * If set to `true`, taxes will be applied on gift cards. - * type: boolean - * tax_provider_id: - * description: "The ID of the tax provider to use. If none provided, the system tax provider is used." - * type: string - * tax_code: - * description: "The tax code of the Region." - * type: string - * tax_rate: - * description: "The tax rate to use in the Region." - * type: number - * includes_tax: - * x-featureFlag: "tax_inclusive_pricing" - * description: "Whether taxes are included in the prices of the region." - * type: boolean - * payment_providers: - * description: "A list of Payment Provider IDs that can be used in the Region" - * type: array - * items: - * type: string - * fulfillment_providers: - * description: "A list of Fulfillment Provider IDs that can be used in the Region" - * type: array - * items: - * type: string - * countries: - * description: "A list of countries' 2 ISO characters that should be included in the Region." - * type: array - * items: - * type: string - */ -export class AdminPostRegionsRegionReq { - @IsString() - @IsOptional() - name?: string - - @IsString() - @IsOptional() - currency_code?: string - - @IsString() - @IsOptional() - tax_code?: string - - @IsNumber() - @IsOptional() - tax_rate?: number - - @IsBoolean() - @IsOptional() - gift_cards_taxable?: boolean - - @IsBoolean() - @IsOptional() - automatic_taxes?: boolean - - @IsString() - @IsOptional() - tax_provider_id?: string | null - - @IsArray() - @IsString({ each: true }) - @IsOptional() - payment_providers?: string[] - - @IsArray() - @IsString({ each: true }) - @IsOptional() - fulfillment_providers?: string[] - - // iso_2 country codes - @IsArray() - @IsString({ each: true }) - @IsOptional() - countries?: string[] - - @FeatureFlagDecorators(TaxInclusivePricingFeatureFlag.key, [ - IsOptional(), - IsBoolean(), - ]) - includes_tax?: boolean - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/reservations/create-reservation.ts b/packages/medusa/src/api/routes/admin/reservations/create-reservation.ts deleted file mode 100644 index de2a3a07c5..0000000000 --- a/packages/medusa/src/api/routes/admin/reservations/create-reservation.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { IsNumber, IsObject, IsOptional, IsString } from "class-validator" - -import { IInventoryService } from "@medusajs/types" -import { isDefined } from "@medusajs/utils" -import { validateUpdateReservationQuantity } from "./utils/validate-reservation-quantity" - -/** - * @oas [post] /admin/reservations - * operationId: "PostReservations" - * summary: "Create a Reservation" - * description: "Create a Reservation which can be associated with any resource, such as an order's line item." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostReservationsReq" - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.reservations.create({ - * line_item_id: "item_123", - * location_id: "loc_123", - * inventory_item_id: "iitem_123", - * quantity: 1 - * }) - * .then(({ reservation }) => { - * console.log(reservation.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateReservation } from "medusa-react" - * - * const CreateReservation = () => { - * const createReservation = useAdminCreateReservation() - * // ... - * - * const handleCreate = ( - * locationId: string, - * inventoryItemId: string, - * quantity: number - * ) => { - * createReservation.mutate({ - * location_id: locationId, - * inventory_item_id: inventoryItemId, - * quantity, - * }, { - * onSuccess: ({ reservation }) => { - * console.log(reservation.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateReservation - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/reservations' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "line_item_id": "item_123", - * "location_id": "loc_123", - * "inventory_item_id": "iitem_123", - * "quantity": 1 - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Reservations - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReservationsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { validatedBody } = req as { validatedBody: AdminPostReservationsReq } - - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - - const userId: string = req.user.id || req.user.userId - - if (isDefined(validatedBody.line_item_id)) { - await validateUpdateReservationQuantity( - validatedBody.line_item_id, - validatedBody.quantity, - { - lineItemService: req.scope.resolve("lineItemService"), - inventoryService: req.scope.resolve("inventoryService"), - } - ) - } - - const reservation = await inventoryService.createReservationItem({ - ...validatedBody, - created_by: userId, - }) - - res.status(200).json({ reservation }) -} - -/** - * @schema AdminPostReservationsReq - * type: object - * description: "The details of the reservation to create." - * required: - * - location_id - * - inventory_item_id - * - quantity - * properties: - * line_item_id: - * description: "The ID of the line item of the reservation." - * type: string - * location_id: - * description: "The ID of the location of the reservation." - * type: string - * inventory_item_id: - * description: "The ID of the inventory item the reservation is associated with." - * type: string - * quantity: - * description: "The quantity to reserve." - * type: number - * description: - * description: "The reservation's description." - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostReservationsReq { - @IsString() - @IsOptional() - line_item_id?: string - - @IsString() - location_id: string - - @IsString() - inventory_item_id: string - - @IsNumber() - quantity: number - - @IsString() - @IsOptional() - description?: string - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/reservations/delete-reservation.ts b/packages/medusa/src/api/routes/admin/reservations/delete-reservation.ts deleted file mode 100644 index 49c06db629..0000000000 --- a/packages/medusa/src/api/routes/admin/reservations/delete-reservation.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { IInventoryService } from "@medusajs/types" -import { EntityManager } from "typeorm" - -/** - * @oas [delete] /admin/reservations/{id} - * operationId: "DeleteReservationsReservation" - * summary: "Delete a Reservation" - * description: "Delete a Reservation. Associated resources, such as the line item, will not be deleted." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Reservation to delete. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.reservations.delete(reservationId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteReservation } from "medusa-react" - * - * type Props = { - * reservationId: string - * } - * - * const Reservation = ({ reservationId }: Props) => { - * const deleteReservation = useAdminDeleteReservation( - * reservationId - * ) - * // ... - * - * const handleDelete = () => { - * deleteReservation.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Reservation - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/reservations/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Reservations - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReservationsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - const manager: EntityManager = req.scope.resolve("manager") - - await inventoryService.deleteReservationItem(id) - - res.json({ - id, - object: "reservation", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/reservations/get-reservation.ts b/packages/medusa/src/api/routes/admin/reservations/get-reservation.ts deleted file mode 100644 index e7c02ea1b1..0000000000 --- a/packages/medusa/src/api/routes/admin/reservations/get-reservation.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { IInventoryService } from "@medusajs/types" -import { MedusaError } from "@medusajs/utils" - -/** - * @oas [get] /admin/reservations/{id} - * operationId: "GetReservationsReservation" - * summary: "Get a Reservation" - * description: "Retrieve a reservation's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the reservation. - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.reservations.retrieve(reservationId) - * .then(({ reservation }) => { - * console.log(reservation.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminReservation } from "medusa-react" - * - * type Props = { - * reservationId: string - * } - * - * const Reservation = ({ reservationId }: Props) => { - * const { reservation, isLoading } = useAdminReservation( - * reservationId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {reservation && {reservation.inventory_item_id}} - *
- * ) - * } - * - * export default Reservation - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/reservations/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Reservations - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReservationsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - - const [reservations, count] = await inventoryService.listReservationItems({ - id, - }) - - if (!count) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Reservation with id ${id} not found` - ) - } - - res.status(200).json({ reservation: reservations[0] }) -} diff --git a/packages/medusa/src/api/routes/admin/reservations/index.ts b/packages/medusa/src/api/routes/admin/reservations/index.ts deleted file mode 100644 index d72a0fe537..0000000000 --- a/packages/medusa/src/api/routes/admin/reservations/index.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import { InventoryItemDTO, ReservationItemDTO } from "@medusajs/types" -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" - -import { AdminGetReservationsParams } from "./list-reservations" -import { AdminPostReservationsReq } from "./create-reservation" -import { AdminPostReservationsReservationReq } from "./update-reservation" -import { LineItem } from "../../../../models" -import { Router } from "express" -import { checkRegisteredModules } from "../../../middlewares/check-registered-modules" - -const route = Router() - -export default (app) => { - app.use( - "/reservations", - checkRegisteredModules({ - inventoryService: - "Inventory is not enabled. Please add an Inventory module to enable this functionality.", - }), - route - ) - - route.get("/:id", middlewares.wrap(require("./get-reservation").default)) - - route.post( - "/", - transformBody(AdminPostReservationsReq), - middlewares.wrap(require("./create-reservation").default) - ) - - route.get( - "/", - transformQuery(AdminGetReservationsParams, { - defaultFields: defaultReservationFields, - defaultRelations: defaultAdminReservationRelations, - isList: true, - }), - middlewares.wrap(require("./list-reservations").default) - ) - - route.post( - "/:id", - transformBody(AdminPostReservationsReservationReq), - middlewares.wrap(require("./update-reservation").default) - ) - - route.delete( - "/:id", - middlewares.wrap(require("./delete-reservation").default) - ) - - return app -} - -/** - * @schema AdminReservationsRes - * type: object - * description: "The reservation's details." - * required: - * - reservation - * properties: - * reservation: - * description: Reservation details. - * $ref: "#/components/schemas/ReservationItemDTO" - */ -export type AdminReservationsRes = { - reservation: ReservationItemDTO -} - -/** - * @schema ExtendedReservationItem - * type: object - * allOf: - * - $ref: "#/components/schemas/ReservationItemDTO" - * - type: object - * properties: - * line_item: - * description: The line item associated with the reservation. - * $ref: "#/components/schemas/LineItem" - * inventory_item: - * description: The inventory item associated with the reservation. - * $ref: "#/components/schemas/InventoryItemDTO" - */ -export type ExtendedReservationItem = ReservationItemDTO & { - line_item?: LineItem - inventory_item?: InventoryItemDTO -} - -/** - * @schema AdminReservationsListRes - * type: object - * description: "The list of reservations with pagination fields." - * required: - * - reservations - * - count - * - offset - * - limit - * properties: - * reservations: - * type: array - * description: An array of reservations details. - * items: - * $ref: "#/components/schemas/ExtendedReservationItem" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of reservations skipped when retrieving the reservations. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminReservationsListRes = PaginatedResponse & { - reservations: ReservationItemDTO[] -} - -export const defaultAdminReservationRelations = [] - -export const defaultReservationFields = [ - "id", - "location_id", - "inventory_item_id", - "quantity", - "line_item_id", - "description", - "metadata", - "created_at", - "updated_at", -] - -/** - * @schema AdminReservationsDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Reservation. - * object: - * type: string - * description: The type of the object that was deleted. - * default: reservation - * deleted: - * type: boolean - * description: Whether or not the Reservation was deleted. - * default: true - */ -export type AdminReservationsDeleteRes = DeleteResponse - -export * from "./create-reservation" -export * from "./delete-reservation" -export * from "./get-reservation" -export * from "./list-reservations" -export * from "./update-reservation" diff --git a/packages/medusa/src/api/routes/admin/reservations/list-reservations.ts b/packages/medusa/src/api/routes/admin/reservations/list-reservations.ts deleted file mode 100644 index 7234a59cfd..0000000000 --- a/packages/medusa/src/api/routes/admin/reservations/list-reservations.ts +++ /dev/null @@ -1,304 +0,0 @@ -import { IsArray, IsOptional, IsString, ValidateNested } from "class-validator" -import { Request, Response } from "express" -import { - DateComparisonOperator, - NumericalComparisonOperator, - StringComparisonOperator, - extendedFindParamsMixin, -} from "../../../../types/common" - -import { IInventoryService } from "@medusajs/types" -import { promiseAll } from "@medusajs/utils" -import { Type } from "class-transformer" -import { EntityManager } from "typeorm" -import { LineItemService } from "../../../../services" -import { IsType } from "../../../../utils/validators/is-type" -import { joinInventoryItems } from "./utils/join-inventory-items" -import { joinLineItems } from "./utils/join-line-items" - -/** - * @oas [get] /admin/reservations - * operationId: "GetReservations" - * summary: "List Reservations" - * description: "Retrieve a list of Reservations. The reservations can be filtered by fields such as `location_id` or `quantity`. The reservations can also be paginated." - * x-authenticated: true - * parameters: - * - in: query - * name: location_id - * style: form - * explode: false - * description: Filter by location ID - * schema: - * type: array - * items: - * type: string - * - in: query - * name: inventory_item_id - * style: form - * explode: false - * description: Filter by inventory item ID. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: line_item_id - * style: form - * explode: false - * description: Filter by line item ID. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: quantity - * description: Filter by reservation quantity - * schema: - * type: object - * properties: - * lt: - * type: number - * description: filter by reservation quantity less than this number - * gt: - * type: number - * description: filter by reservation quantity greater than this number - * lte: - * type: number - * description: filter by reservation quantity less than or equal to this number - * gte: - * type: number - * description: filter by reservation quantity greater than or equal to this number - * - in: query - * name: description - * description: Filter by description. - * schema: - * oneOf: - * - type: string - * description: description value to filter by. - * - type: object - * properties: - * contains: - * type: string - * description: filter by reservation description containing search string. - * starts_with: - * type: string - * description: filter by reservation description starting with search string. - * ends_with: - * type: string - * description: filter by reservation description ending with search string. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - (query) offset=0 {integer} The number of reservations to skip when retrieving the reservations. - * - (query) limit=20 {integer} Limit the number of reservations returned. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned reservations. - * - (query) fields {string} Comma-separated fields that should be included in the returned reservations. - * x-codegen: - * method: list - * queryParams: AdminGetReservationsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.reservations.list() - * .then(({ reservations, count, limit, offset }) => { - * console.log(reservations.length) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminReservations } from "medusa-react" - * - * const Reservations = () => { - * const { reservations, isLoading } = useAdminReservations() - * - * return ( - *
- * {isLoading && Loading...} - * {reservations && !reservations.length && ( - * No Reservations - * )} - * {reservations && reservations.length > 0 && ( - *
    - * {reservations.map((reservation) => ( - *
  • {reservation.quantity}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Reservations - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/product-categories' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Reservations - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReservationsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - const manager: EntityManager = req.scope.resolve("manager") - - const { filterableFields, listConfig } = req - - const relations = new Set(listConfig.relations ?? []) - - const includeItems = relations.delete("line_item") - const includeInventoryItems = relations.delete("inventory_item") - - if (listConfig.relations?.length) { - listConfig.relations = [...relations] - } - - const [reservations, count] = await inventoryService.listReservationItems( - filterableFields, - listConfig, - { - transactionManager: manager, - } - ) - - const promises: Promise[] = [] - - if (includeInventoryItems) { - promises.push( - joinInventoryItems(reservations, { - inventoryService, - manager, - }) - ) - } - - if (includeItems) { - const lineItemService: LineItemService = - req.scope.resolve("lineItemService") - - promises.push(joinLineItems(reservations, lineItemService)) - } - - await promiseAll(promises) - - const { limit, offset } = req.validatedQuery - - res.json({ reservations, count, limit, offset }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved reservations. - */ -export class AdminGetReservationsParams extends extendedFindParamsMixin({ - limit: 20, - offset: 0, -}) { - /** - * Location IDs to filter reservations by. - */ - @IsOptional() - @IsType([String, [String]]) - location_id?: string | string[] - - /** - * Inventory item IDs to filter reservations by. - */ - @IsArray() - @IsString({ each: true }) - @IsOptional() - inventory_item_id?: string[] - - /** - * Line item IDs to filter reservations by. - */ - @IsArray() - @IsString({ each: true }) - @IsOptional() - line_item_id?: string[] - - /** - * "Create by" user IDs to filter reservations by. - */ - @IsArray() - @IsString({ each: true }) - @IsOptional() - created_by?: string[] - - /** - * Numerical filters to apply on the reservations' `quantity` field. - */ - @IsOptional() - @ValidateNested() - @Type(() => NumericalComparisonOperator) - quantity?: NumericalComparisonOperator - - /** - * Date filters to apply on the reservations' `created_at` field. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the reservations' `updated_at` field. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * String filters to apply on the reservations' `description` field. - */ - @IsOptional() - @IsType([StringComparisonOperator, String]) - description?: string | StringComparisonOperator -} diff --git a/packages/medusa/src/api/routes/admin/reservations/update-reservation.ts b/packages/medusa/src/api/routes/admin/reservations/update-reservation.ts deleted file mode 100644 index 9901e440d4..0000000000 --- a/packages/medusa/src/api/routes/admin/reservations/update-reservation.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { IsNumber, IsObject, IsOptional, IsString } from "class-validator" - -import { EntityManager } from "typeorm" -import { IInventoryService } from "@medusajs/types" -import { LineItemService } from "../../../../services" -import { isDefined } from "@medusajs/utils" -import { validateUpdateReservationQuantity } from "./utils/validate-reservation-quantity" - -/** - * @oas [post] /admin/reservations/{id} - * operationId: "PostReservationsReservation" - * summary: "Update a Reservation" - * description: "Update a Reservation's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Reservation. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostReservationsReservationReq" - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.reservations.update(reservationId, { - * quantity: 3 - * }) - * .then(({ reservation }) => { - * console.log(reservation.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateReservation } from "medusa-react" - * - * type Props = { - * reservationId: string - * } - * - * const Reservation = ({ reservationId }: Props) => { - * const updateReservation = useAdminUpdateReservation( - * reservationId - * ) - * // ... - * - * const handleUpdate = ( - * quantity: number - * ) => { - * updateReservation.mutate({ - * quantity, - * }) - * } - * - * // ... - * } - * - * export default Reservation - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/reservations/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "quantity": 3, - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Reservations - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReservationsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const { validatedBody } = req as { - validatedBody: AdminPostReservationsReservationReq - } - - const manager: EntityManager = req.scope.resolve("manager") - const lineItemService: LineItemService = req.scope.resolve("lineItemService") - - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - - const reservation = await inventoryService.retrieveReservationItem(id) - - if (reservation.line_item_id && isDefined(validatedBody.quantity)) { - await validateUpdateReservationQuantity( - reservation.line_item_id, - validatedBody.quantity - reservation.quantity, - { - lineItemService, - inventoryService, - } - ) - } - - const result = await manager.transaction(async (manager) => { - await inventoryService.updateReservationItem(id, validatedBody) - }) - - res.status(200).json({ reservation: result }) -} - -/** - * @schema AdminPostReservationsReservationReq - * type: object - * description: "The details to update of the reservation." - * properties: - * location_id: - * description: "The ID of the location associated with the reservation." - * type: string - * quantity: - * description: "The quantity to reserve." - * type: number - * description: - * description: "The reservation's description." - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostReservationsReservationReq { - @IsNumber() - @IsOptional() - quantity?: number - - @IsString() - @IsOptional() - location_id?: string - - @IsString() - @IsOptional() - description?: string - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/reservations/utils/join-inventory-items.ts b/packages/medusa/src/api/routes/admin/reservations/utils/join-inventory-items.ts deleted file mode 100644 index e7e6d4b7bd..0000000000 --- a/packages/medusa/src/api/routes/admin/reservations/utils/join-inventory-items.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { EntityManager } from "typeorm" -import { ExtendedReservationItem } from ".." -import { IInventoryService } from "@medusajs/types" - -export const joinInventoryItems = async ( - reservations: ExtendedReservationItem[], - dependencies: { - inventoryService: IInventoryService - manager: EntityManager - } -): Promise => { - const [inventoryItems] = - await dependencies.inventoryService.listInventoryItems( - { - id: reservations.map((r) => r.inventory_item_id), - }, - {}, - { - transactionManager: dependencies.manager, - } - ) - - const inventoryItemMap = new Map(inventoryItems.map((i) => [i.id, i])) - - return reservations.map((reservation) => { - reservation.inventory_item = inventoryItemMap.get( - reservation.inventory_item_id - ) - - return reservation - }) -} diff --git a/packages/medusa/src/api/routes/admin/reservations/utils/join-line-items.ts b/packages/medusa/src/api/routes/admin/reservations/utils/join-line-items.ts deleted file mode 100644 index fc40a14ac0..0000000000 --- a/packages/medusa/src/api/routes/admin/reservations/utils/join-line-items.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ExtendedReservationItem } from ".." -import { LineItemService } from "../../../../../services" - -export const joinLineItems = async ( - reservations: ExtendedReservationItem[], - lineItemService: LineItemService -): Promise => { - const lineItems = await lineItemService.list( - { - id: reservations - .map((r) => r.line_item_id) - .filter((lId: string | null | undefined): lId is string => !!lId), - }, - { - relations: ["order"], - } - ) - - const lineItemMap = new Map(lineItems.map((i) => [i.id, i])) - - return reservations.map((reservation) => { - if (!reservation.line_item_id) { - return reservation - } - - reservation.line_item = lineItemMap.get(reservation.line_item_id) - - return reservation - }) -} diff --git a/packages/medusa/src/api/routes/admin/reservations/utils/validate-reservation-quantity.ts b/packages/medusa/src/api/routes/admin/reservations/utils/validate-reservation-quantity.ts deleted file mode 100644 index 875349e551..0000000000 --- a/packages/medusa/src/api/routes/admin/reservations/utils/validate-reservation-quantity.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { IInventoryService } from "@medusajs/types" -import { MedusaError } from "@medusajs/utils" -import { LineItemService } from "../../../../../services" - -export const validateUpdateReservationQuantity = async ( - lineItemId: string, - quantityUpdate: number, - context: { - lineItemService: LineItemService - inventoryService: IInventoryService - } -) => { - const { lineItemService, inventoryService } = context - const [reservationItems] = await inventoryService.listReservationItems({ - line_item_id: lineItemId, - }) - - const totalQuantity = reservationItems.reduce( - (acc, cur) => acc + cur.quantity, - quantityUpdate - ) - - const lineItem = await lineItemService.retrieve(lineItemId) - - if (totalQuantity > lineItem.quantity - (lineItem.fulfilled_quantity || 0)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "The reservation quantity cannot be greater than the unfulfilled line item quantity" - ) - } -} diff --git a/packages/medusa/src/api/routes/admin/return-reasons/create-reason.ts b/packages/medusa/src/api/routes/admin/return-reasons/create-reason.ts deleted file mode 100644 index d3f414d684..0000000000 --- a/packages/medusa/src/api/routes/admin/return-reasons/create-reason.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { IsOptional, IsString } from "class-validator" -import { - defaultAdminReturnReasonsFields, - defaultAdminReturnReasonsRelations, -} from "." - -import { ReturnReasonService } from "../../../../services" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/return-reasons - * operationId: "PostReturnReasons" - * summary: "Create a Return Reason" - * description: "Create a Return Reason." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostReturnReasonsReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returnReasons.create({ - * label: "Damaged", - * value: "damaged" - * }) - * .then(({ return_reason }) => { - * console.log(return_reason.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateReturnReason } from "medusa-react" - * - * const CreateReturnReason = () => { - * const createReturnReason = useAdminCreateReturnReason() - * // ... - * - * const handleCreate = ( - * label: string, - * value: string - * ) => { - * createReturnReason.mutate({ - * label, - * value, - * }, { - * onSuccess: ({ return_reason }) => { - * console.log(return_reason.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateReturnReason - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/return-reasons' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "label": "Damaged", - * "value": "damaged" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Return Reasons - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReturnReasonsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminPostReturnReasonsReq, req.body) - - const returnReasonService: ReturnReasonService = req.scope.resolve( - "returnReasonService" - ) - const manager: EntityManager = req.scope.resolve("manager") - const result = await manager.transaction(async (transactionManager) => { - return await returnReasonService - .withTransaction(transactionManager) - .create(validated) - }) - - const reason = await returnReasonService.retrieve(result.id, { - select: defaultAdminReturnReasonsFields, - relations: defaultAdminReturnReasonsRelations, - }) - - res.status(200).json({ return_reason: reason }) -} - -/** - * @schema AdminPostReturnReasonsReq - * type: object - * description: "The details of the return reason to create." - * required: - * - label - * - value - * properties: - * label: - * description: "The label to display to the Customer." - * type: string - * value: - * description: "A unique value of the return reason." - * type: string - * parent_return_reason_id: - * description: "The ID of the parent return reason." - * type: string - * description: - * description: "The description of the Reason." - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostReturnReasonsReq { - @IsString() - value: string - - @IsString() - label: string - - @IsOptional() - @IsString() - parent_return_reason_id?: string - - @IsOptional() - @IsString() - description?: string - - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/return-reasons/delete-reason.ts b/packages/medusa/src/api/routes/admin/return-reasons/delete-reason.ts deleted file mode 100644 index 3305b9e5b6..0000000000 --- a/packages/medusa/src/api/routes/admin/return-reasons/delete-reason.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { EntityManager } from "typeorm" -import { ReturnReasonService } from "../../../../services" - -/** - * @oas [delete] /admin/return-reasons/{id} - * operationId: "DeleteReturnReason" - * summary: "Delete a Return Reason" - * description: "Delete a return reason." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the return reason - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returnReasons.delete(returnReasonId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteReturnReason } from "medusa-react" - * - * type Props = { - * returnReasonId: string - * } - * - * const ReturnReason = ({ returnReasonId }: Props) => { - * const deleteReturnReason = useAdminDeleteReturnReason( - * returnReasonId - * ) - * // ... - * - * const handleDelete = () => { - * deleteReturnReason.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default ReturnReason - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/return-reasons/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Return Reasons - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReturnReasonsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const returnReasonService: ReturnReasonService = req.scope.resolve( - "returnReasonService" - ) - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await returnReasonService - .withTransaction(transactionManager) - .delete(id) - }) - - res.json({ - id: id, - object: "return_reason", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/return-reasons/get-reason.ts b/packages/medusa/src/api/routes/admin/return-reasons/get-reason.ts deleted file mode 100644 index 728ff1d6fe..0000000000 --- a/packages/medusa/src/api/routes/admin/return-reasons/get-reason.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { - defaultAdminReturnReasonsFields, - defaultAdminReturnReasonsRelations, -} from "." - -import { ReturnReasonService } from "../../../../services" - -/** - * @oas [get] /admin/return-reasons/{id} - * operationId: "GetReturnReasonsReason" - * summary: "Get a Return Reason" - * description: "Retrieve a Return Reason's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Return Reason. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returnReasons.retrieve(returnReasonId) - * .then(({ return_reason }) => { - * console.log(return_reason.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminReturnReason } from "medusa-react" - * - * type Props = { - * returnReasonId: string - * } - * - * const ReturnReason = ({ returnReasonId }: Props) => { - * const { return_reason, isLoading } = useAdminReturnReason( - * returnReasonId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {return_reason && {return_reason.label}} - *
- * ) - * } - * - * export default ReturnReason - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/return-reasons/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Return Reasons - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReturnReasonsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const returnReasonService: ReturnReasonService = req.scope.resolve( - "returnReasonService" - ) - - const data = await returnReasonService.retrieve(id, { - select: defaultAdminReturnReasonsFields, - relations: defaultAdminReturnReasonsRelations, - }) - - res.status(200).json({ return_reason: data }) -} diff --git a/packages/medusa/src/api/routes/admin/return-reasons/index.ts b/packages/medusa/src/api/routes/admin/return-reasons/index.ts deleted file mode 100644 index fc36e65ad0..0000000000 --- a/packages/medusa/src/api/routes/admin/return-reasons/index.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { Router } from "express" -import { ReturnReason } from "../../../.." -import { DeleteResponse } from "../../../../types/common" -import middlewares from "../../../middlewares" - -const route = Router() - -export default (app) => { - app.use("/return-reasons", route) - - /** - * List reasons - */ - route.get("/", middlewares.wrap(require("./list-reasons").default)) - - /** - * Retrieve reason - */ - route.get("/:id", middlewares.wrap(require("./get-reason").default)) - - /** - * Create a reason - */ - route.post("/", middlewares.wrap(require("./create-reason").default)) - - /** - * Update a reason - */ - route.post("/:id", middlewares.wrap(require("./update-reason").default)) - - /** - * Delete a reason - */ - route.delete("/:id", middlewares.wrap(require("./delete-reason").default)) - - return app -} - -export const defaultAdminReturnReasonsFields: (keyof ReturnReason)[] = [ - "id", - "value", - "label", - "parent_return_reason_id", - "description", - "created_at", - "updated_at", - "deleted_at", -] - -export const defaultAdminReturnReasonsRelations: (keyof ReturnReason)[] = [ - "parent_return_reason", - "return_reason_children", -] - -/** - * @schema AdminReturnReasonsRes - * type: object - * description: "The return reason's details." - * x-expanded-relations: - * field: return_reason - * relations: - * - parent_return_reason - * - return_reason_children - * required: - * - return_reason - * properties: - * return_reason: - * description: "The return reason's details." - * $ref: "#/components/schemas/ReturnReason" - */ -export type AdminReturnReasonsRes = { - return_reason: ReturnReason -} - -/** - * @schema AdminReturnReasonsListRes - * type: object - * description: "The list of return reasons." - * x-expanded-relations: - * field: return_reasons - * relations: - * - parent_return_reason - * - return_reason_children - * required: - * - return_reasons - * properties: - * return_reasons: - * type: array - * description: "The list of return reasons." - * items: - * $ref: "#/components/schemas/ReturnReason" - */ -export type AdminReturnReasonsListRes = { - return_reasons: ReturnReason[] -} - -/** - * @schema AdminReturnReasonsDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted return reason - * object: - * type: string - * description: The type of the object that was deleted. - * default: return_reason - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminReturnReasonsDeleteRes = DeleteResponse - -export * from "./create-reason" -export * from "./update-reason" diff --git a/packages/medusa/src/api/routes/admin/return-reasons/list-reasons.ts b/packages/medusa/src/api/routes/admin/return-reasons/list-reasons.ts deleted file mode 100644 index 80b68ff8bc..0000000000 --- a/packages/medusa/src/api/routes/admin/return-reasons/list-reasons.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { - defaultAdminReturnReasonsFields, - defaultAdminReturnReasonsRelations, -} from "." -import { ReturnReason } from "../../../../models" -import { ReturnReasonService } from "../../../../services" -import { Selector } from "../../../../types/common" - -/** - * @oas [get] /admin/return-reasons - * operationId: "GetReturnReasons" - * summary: "List Return Reasons" - * description: "Retrieve a list of Return Reasons." - * x-authenticated: true - * x-codegen: - * method: list - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returnReasons.list() - * .then(({ return_reasons }) => { - * console.log(return_reasons.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminReturnReasons } from "medusa-react" - * - * const ReturnReasons = () => { - * const { return_reasons, isLoading } = useAdminReturnReasons() - * - * return ( - *
- * {isLoading && Loading...} - * {return_reasons && !return_reasons.length && ( - * No Return Reasons - * )} - * {return_reasons && return_reasons.length > 0 && ( - *
    - * {return_reasons.map((reason) => ( - *
  • - * {reason.label}: {reason.value} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ReturnReasons - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/return-reasons' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Return Reasons - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReturnReasonsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const returnReasonService: ReturnReasonService = req.scope.resolve( - "returnReasonService" - ) - - const query: Selector = { parent_return_reason_id: null } - const data = await returnReasonService.list(query, { - select: defaultAdminReturnReasonsFields, - relations: defaultAdminReturnReasonsRelations, - }) - - res.status(200).json({ return_reasons: data }) -} diff --git a/packages/medusa/src/api/routes/admin/return-reasons/update-reason.ts b/packages/medusa/src/api/routes/admin/return-reasons/update-reason.ts deleted file mode 100644 index 333eaaba05..0000000000 --- a/packages/medusa/src/api/routes/admin/return-reasons/update-reason.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { IsOptional, IsString } from "class-validator" -import { - defaultAdminReturnReasonsFields, - defaultAdminReturnReasonsRelations, -} from "." - -import { ReturnReasonService } from "../../../../services" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/return-reasons/{id} - * operationId: "PostReturnReasonsReason" - * summary: "Update a Return Reason" - * description: "Update a Return Reason's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Return Reason. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostReturnReasonsReasonReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returnReasons.update(returnReasonId, { - * label: "Damaged" - * }) - * .then(({ return_reason }) => { - * console.log(return_reason.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateReturnReason } from "medusa-react" - * - * type Props = { - * returnReasonId: string - * } - * - * const ReturnReason = ({ returnReasonId }: Props) => { - * const updateReturnReason = useAdminUpdateReturnReason( - * returnReasonId - * ) - * // ... - * - * const handleUpdate = ( - * label: string - * ) => { - * updateReturnReason.mutate({ - * label, - * }, { - * onSuccess: ({ return_reason }) => { - * console.log(return_reason.label) - * } - * }) - * } - * - * // ... - * } - * - * export default ReturnReason - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/return-reasons/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "label": "Damaged" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Return Reasons - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReturnReasonsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = await validator(AdminPostReturnReasonsReasonReq, req.body) - - const returnReasonService: ReturnReasonService = req.scope.resolve( - "returnReasonService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await returnReasonService - .withTransaction(transactionManager) - .update(id, validated) - }) - - const reason = await returnReasonService.retrieve(id, { - select: defaultAdminReturnReasonsFields, - relations: defaultAdminReturnReasonsRelations, - }) - - res.status(200).json({ return_reason: reason }) -} - -/** - * @schema AdminPostReturnReasonsReasonReq - * type: object - * description: "The details to update of the return reason." - * properties: - * label: - * description: "The label to display to the Customer." - * type: string - * value: - * description: "A unique value of the return reason." - * type: string - * description: - * description: "The description of the Reason." - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostReturnReasonsReasonReq { - @IsOptional() - @IsString() - label?: string - - @IsOptional() - @IsString() - value?: string - - @IsOptional() - @IsString() - description?: string - - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/returns/__tests__/receive-return.js b/packages/medusa/src/api/routes/admin/returns/__tests__/receive-return.js deleted file mode 100644 index 44d0ab3261..0000000000 --- a/packages/medusa/src/api/routes/admin/returns/__tests__/receive-return.js +++ /dev/null @@ -1,59 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { OrderServiceMock } from "../../../../../services/__mocks__/order" -import { ReturnService } from "../../../../../services/__mocks__/return" - -describe("POST /admin/returns/:id/receive", () => { - describe("successfully receives a return", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/returns/${IdMap.getId("test-return")}/receive`, - { - payload: { - items: [ - { - item_id: IdMap.getId("test"), - quantity: 2, - }, - ], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls ReturnService receive", () => { - expect(ReturnService.receive).toHaveBeenCalledTimes(1) - expect(ReturnService.receive).toHaveBeenCalledWith( - IdMap.getId("test-return"), - [{ item_id: IdMap.getId("test"), quantity: 2 }], - undefined, - true, - { location_id: undefined } - ) - }) - - it("calls OrderService registerReturnReceived", () => { - expect(OrderServiceMock.registerReturnReceived).toHaveBeenCalledTimes(1) - expect(OrderServiceMock.registerReturnReceived).toHaveBeenCalledWith( - IdMap.getId("test-order"), - { - id: IdMap.getId("test-return"), - order_id: IdMap.getId("test-order"), - }, - undefined - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/returns/cancel-return.ts b/packages/medusa/src/api/routes/admin/returns/cancel-return.ts deleted file mode 100644 index 9f2e26d25d..0000000000 --- a/packages/medusa/src/api/routes/admin/returns/cancel-return.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { OrderService, ReturnService } from "../../../../services" -import { EntityManager } from "typeorm" -import { defaultReturnCancelFields, defaultReturnCancelRelations } from "." - -/** - * @oas [post] /admin/returns/{id}/cancel - * operationId: "PostReturnsReturnCancel" - * summary: "Cancel a Return" - * description: "Registers a Return as canceled. The return can be associated with an order, claim, or swap." - * parameters: - * - (path) id=* {string} The ID of the Return. - * x-codegen: - * method: cancel - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returns.cancel(returnId) - * .then(({ order }) => { - * console.log(order.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCancelReturn } from "medusa-react" - * - * type Props = { - * returnId: string - * } - * - * const Return = ({ returnId }: Props) => { - * const cancelReturn = useAdminCancelReturn( - * returnId - * ) - * // ... - * - * const handleCancel = () => { - * cancelReturn.mutate(void 0, { - * onSuccess: ({ order }) => { - * console.log(order.returns) - * } - * }) - * } - * - * // ... - * } - * - * export default Return - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/returns/{id}/cancel' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Returns - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReturnsCancelRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const returnService: ReturnService = req.scope.resolve("returnService") - const orderService: OrderService = req.scope.resolve("orderService") - - const manager: EntityManager = req.scope.resolve("manager") - let result = await manager.transaction(async (transactionManager) => { - return await returnService.withTransaction(transactionManager).cancel(id) - }) - - if (result.swap_id) { - const swapService = req.scope.resolve("swapService") - result = await swapService.retrieve(result.swap_id) - } else if (result.claim_order_id) { - const claimService = req.scope.resolve("claimService") - result = await claimService.retrieve(result.claim_order_id) - } - - const order = await orderService.retrieve(result.order_id!, { - select: defaultReturnCancelFields, - relations: defaultReturnCancelRelations, - }) - - res.status(200).json({ order }) -} diff --git a/packages/medusa/src/api/routes/admin/returns/index.ts b/packages/medusa/src/api/routes/admin/returns/index.ts deleted file mode 100644 index 6a4f84a688..0000000000 --- a/packages/medusa/src/api/routes/admin/returns/index.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { Router } from "express" -import "reflect-metadata" -import { Order, Return } from "../../../.." -import { PaginatedResponse } from "../../../../types/common" -import middlewares from "../../../middlewares" -import { - defaultAdminOrdersFields, - defaultAdminOrdersRelations, -} from "../../../../types/orders" - -const route = Router() - -export default (app) => { - app.use("/returns", route) - - /** - * List returns - */ - route.get("/", middlewares.wrap(require("./list-returns").default)) - - route.post( - "/:id/receive", - middlewares.wrap(require("./receive-return").default) - ) - - route.post( - "/:id/cancel", - middlewares.wrap(require("./cancel-return").default) - ) - - return app -} - -export const defaultRelations = ["swap"] -export const defaultRelationsList = ["swap", "order"] -export const defaultReturnCancelRelations = [...defaultAdminOrdersRelations] -export const defaultReturnCancelFields = [...defaultAdminOrdersFields] - -/** - * @schema AdminReturnsCancelRes - * type: object - * description: "The associated order's details." - * x-expanded-relations: - * field: order - * relations: - * - billing_address - * - claims - * - claims.additional_items - * - claims.additional_items.variant - * - claims.claim_items - * - claims.claim_items.images - * - claims.claim_items.item - * - claims.fulfillments - * - claims.fulfillments.tracking_links - * - claims.return_order - * - claims.return_order.shipping_method - * - claims.return_order.shipping_method.tax_lines - * - claims.shipping_address - * - claims.shipping_methods - * - customer - * - discounts - * - discounts.rule - * - fulfillments - * - fulfillments.items - * - fulfillments.tracking_links - * - gift_card_transactions - * - gift_cards - * - items - * - payments - * - refunds - * - region - * - returns - * - returns.items - * - returns.items.reason - * - returns.shipping_method - * - returns.shipping_method.tax_lines - * - shipping_address - * - shipping_methods - * - swaps - * - swaps.additional_items - * - swaps.additional_items.variant - * - swaps.fulfillments - * - swaps.fulfillments.tracking_links - * - swaps.payment - * - swaps.return_order - * - swaps.return_order.shipping_method - * - swaps.return_order.shipping_method.tax_lines - * - swaps.shipping_address - * - swaps.shipping_methods - * - swaps.shipping_methods.tax_lines - * required: - * - order - * properties: - * order: - * description: Order details. - * $ref: "#/components/schemas/Order" - */ -export type AdminReturnsCancelRes = { - order: Order -} - -/** - * @schema AdminReturnsListRes - * type: object - * description: "The list of returns with pagination fields." - * x-expanded-relation: - * field: returns - * relations: - * - order - * - swap - * required: - * - returns - * - count - * - offset - * - limit - * properties: - * returns: - * type: array - * description: An array of returns details. - * items: - * $ref: "#/components/schemas/Return" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of returns skipped when retrieving the returns. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminReturnsListRes = PaginatedResponse & { - returns: Return[] -} - -/** - * @schema AdminReturnsRes - * type: object - * description: "The return's details." - * x-expanded-relation: - * field: return - * relations: - * - swap - * required: - * - return - * properties: - * return: - * description: Return details. - * $ref: "#/components/schemas/Return" - */ -export type AdminReturnsRes = { - return: Return -} - -export * from "./list-returns" -export * from "./receive-return" diff --git a/packages/medusa/src/api/routes/admin/returns/list-returns.ts b/packages/medusa/src/api/routes/admin/returns/list-returns.ts deleted file mode 100644 index db5b3d07ca..0000000000 --- a/packages/medusa/src/api/routes/admin/returns/list-returns.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { IsNumber, IsOptional } from "class-validator" - -import { FindConfig } from "../../../../types/common" -import { Return } from "../../../../models" -import { ReturnService } from "../../../../services" -import { Type } from "class-transformer" -import { defaultRelationsList } from "." -import { validator } from "../../../../utils/validator" - -/** - * @oas [get] /admin/returns - * operationId: "GetReturns" - * summary: "List Returns" - * description: "Retrieve a list of Returns. The returns can be paginated." - * parameters: - * - (query) limit=50 {number} Limit the number of Returns returned. - * - (query) offset=0 {number} The number of Returns to skip when retrieving the Returns. - * x-codegen: - * method: list - * queryParams: AdminGetReturnsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returns.list() - * .then(({ returns, limit, offset, count }) => { - * console.log(returns.length) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminReturns } from "medusa-react" - * - * const Returns = () => { - * const { returns, isLoading } = useAdminReturns() - * - * return ( - *
- * {isLoading && Loading...} - * {returns && !returns.length && ( - * No Returns - * )} - * {returns && returns.length > 0 && ( - *
    - * {returns.map((returnData) => ( - *
  • - * {returnData.status} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Returns - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/returns' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Returns - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReturnsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const returnService: ReturnService = req.scope.resolve("returnService") - - const validated = await validator(AdminGetReturnsParams, req.query) - - const selector = {} - - const listConfig = { - relations: defaultRelationsList, - skip: validated.offset, - take: validated.limit, - order: { created_at: "DESC" }, - } as FindConfig - - const [returns, count] = await returnService.listAndCount(selector, { - ...listConfig, - }) - - res.json({ - returns, - count, - offset: validated.offset, - limit: validated.limit, - }) -} - -/** - * {@inheritDoc FindPaginationParams} - */ -export class AdminGetReturnsParams { - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 50 - */ - @IsOptional() - @IsNumber() - @Type(() => Number) - limit?: number = 50 - - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 50 - */ - @IsOptional() - @IsNumber() - @Type(() => Number) - offset?: number = 0 -} diff --git a/packages/medusa/src/api/routes/admin/returns/receive-return.ts b/packages/medusa/src/api/routes/admin/returns/receive-return.ts deleted file mode 100644 index 9bca1c6af0..0000000000 --- a/packages/medusa/src/api/routes/admin/returns/receive-return.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { - IsArray, - IsNumber, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { OrderService, ReturnService, SwapService } from "../../../../services" - -import { Type } from "class-transformer" -import { isDefined } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { validator } from "../../../../utils/validator" -import { defaultRelations } from "." - -/** - * @oas [post] /admin/returns/{id}/receive - * operationId: "PostReturnsReturnReceive" - * summary: "Receive a Return" - * description: "Mark a Return as received. This also updates the status of associated order, claim, or swap accordingly." - * parameters: - * - (path) id=* {string} The ID of the Return. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostReturnsReturnReceiveReq" - * x-codegen: - * method: receive - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.returns.receive(returnId, { - * items: [ - * { - * item_id, - * quantity: 1 - * } - * ] - * }) - * .then((data) => { - * console.log(data.return.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminReceiveReturn } from "medusa-react" - * - * type ReceiveReturnData = { - * items: { - * item_id: string - * quantity: number - * }[] - * } - * - * type Props = { - * returnId: string - * } - * - * const Return = ({ returnId }: Props) => { - * const receiveReturn = useAdminReceiveReturn( - * returnId - * ) - * // ... - * - * const handleReceive = (data: ReceiveReturnData) => { - * receiveReturn.mutate(data, { - * onSuccess: ({ return: dataReturn }) => { - * console.log(dataReturn.status) - * } - * }) - * } - * - * // ... - * } - * - * export default Return - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/returns/{id}/receive' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "items": [ - * { - * "item_id": "asafg", - * "quantity": 1 - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Returns - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminReturnsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = await validator(AdminPostReturnsReturnReceiveReq, req.body) - - const returnService: ReturnService = req.scope.resolve("returnService") - const orderService: OrderService = req.scope.resolve("orderService") - const swapService: SwapService = req.scope.resolve("swapService") - const entityManager: EntityManager = req.scope.resolve("manager") - - let receivedReturn - await entityManager.transaction(async (manager) => { - let refundAmount = validated.refund - - if (isDefined(validated.refund) && validated.refund! < 0) { - refundAmount = 0 - } - - receivedReturn = await returnService - .withTransaction(manager) - .receive(id, validated.items, refundAmount, true, { - locationId: validated.location_id, - }) - - if (receivedReturn.order_id) { - await orderService - .withTransaction(manager) - .registerReturnReceived( - receivedReturn.order_id, - receivedReturn, - refundAmount - ) - } - - if (receivedReturn.swap_id) { - await swapService - .withTransaction(manager) - .registerReceived(receivedReturn.swap_id) - } - }) - - receivedReturn = await returnService.retrieve(id, { - relations: defaultRelations, - }) - - res.status(200).json({ return: receivedReturn }) -} - -class Item { - @IsString() - item_id: string - - @IsNumber() - quantity: number -} - -/** - * @schema AdminPostReturnsReturnReceiveReq - * type: object - * description: "The details of the received return." - * required: - * - items - * properties: - * items: - * description: The Line Items that have been received. - * type: array - * items: - * type: object - * required: - * - item_id - * - quantity - * properties: - * item_id: - * description: The ID of the Line Item. - * type: string - * quantity: - * description: The quantity of the Line Item. - * type: integer - * refund: - * description: The amount to refund. - * type: number - * location_id: - * description: The ID of the location to return items from. - * type: string - */ -export class AdminPostReturnsReturnReceiveReq { - @IsArray() - @ValidateNested({ each: true }) - @Type(() => Item) - items: Item[] - - @IsOptional() - @IsNumber() - refund?: number - - @IsOptional() - @IsString() - location_id?: string -} diff --git a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/add-product-batch.ts b/packages/medusa/src/api/routes/admin/sales-channels/__tests__/add-product-batch.ts deleted file mode 100644 index 5fe904e0cc..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/add-product-batch.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { SalesChannelServiceMock } from "../../../../../services/__mocks__/sales-channel" -import SalesChannelFeatureFlag from "../../../../../loaders/feature-flags/sales-channels"; - -describe("POST /admin/sales-channels/:id/products/batch", () => { - describe("add product to a sales channel", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/sales-channels/${IdMap.getId( - "sales_channel_1" - )}/products/batch`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - payload: { - product_ids: [{ id: "sales_channel_1_product_1" }], - }, - flags: [SalesChannelFeatureFlag], - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls the retrieve method from the sales channel service", () => { - expect(SalesChannelServiceMock.addProducts).toHaveBeenCalledTimes(1) - expect(SalesChannelServiceMock.addProducts).toHaveBeenCalledWith( - IdMap.getId("sales_channel_1"), - ["sales_channel_1_product_1"] - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/create-sales-channel.ts b/packages/medusa/src/api/routes/admin/sales-channels/__tests__/create-sales-channel.ts deleted file mode 100644 index 071d9d978f..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/create-sales-channel.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -import { request } from "../../../../../helpers/test-request" -import { SalesChannelServiceMock } from "../../../../../services/__mocks__/sales-channel" -import SalesChannelFeatureFlag from "../../../../../loaders/feature-flags/sales-channels"; - -describe("POST /admin/sales-channels", () => { - describe("successfully get a sales channel", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/admin/sales-channels`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - payload: { - name: "sales channel 1 name", - description: "sales channel 1 description", - }, - flags: [SalesChannelFeatureFlag], - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls the create method from the sales channel service", () => { - expect(SalesChannelServiceMock.create).toHaveBeenCalledTimes(1) - expect(SalesChannelServiceMock.create).toHaveBeenCalledWith( - expect.objectContaining({ - name: "sales channel 1 name", - description: "sales channel 1 description", - }) - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/delete-products-batch.ts b/packages/medusa/src/api/routes/admin/sales-channels/__tests__/delete-products-batch.ts deleted file mode 100644 index 6da1d5760d..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/delete-products-batch.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { SalesChannelServiceMock } from "../../../../../services/__mocks__/sales-channel" -import SalesChannelFeatureFlag from "../../../../../loaders/feature-flags/sales-channels"; - -describe("DELETE /admin/sales-channels/:id/products/batch", () => { - describe("remove product from a sales channel", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/sales-channels/${IdMap.getId("sales_channel_1")}/products/batch`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - payload: { - product_ids: [{ id: IdMap.getId("sales_channel_1_product_1") }] - }, - flags: [SalesChannelFeatureFlag], - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls the retrieve method from the sales channel service", () => { - expect(SalesChannelServiceMock.removeProducts).toHaveBeenCalledTimes(1) - expect(SalesChannelServiceMock.removeProducts).toHaveBeenCalledWith( - IdMap.getId("sales_channel_1"), - [IdMap.getId("sales_channel_1_product_1")] - ) - }) - }) -}) \ No newline at end of file diff --git a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/delete-sales-channel.ts b/packages/medusa/src/api/routes/admin/sales-channels/__tests__/delete-sales-channel.ts deleted file mode 100644 index d941d01204..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/delete-sales-channel.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { SalesChannelServiceMock } from "../../../../../services/__mocks__/sales-channel" -import SalesChannelFeatureFlag from "../../../../../loaders/feature-flags/sales-channels"; - -describe("DELETE /admin/sales-channels/:id", () => { - describe("successfully delete a sales channel", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/sales-channels/${IdMap.getId("sales_channel_1")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - flags: [SalesChannelFeatureFlag], - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls the delete method from the sales channel service", () => { - expect(SalesChannelServiceMock.delete).toHaveBeenCalledTimes(1) - expect(SalesChannelServiceMock.delete).toHaveBeenCalledWith( - IdMap.getId("sales_channel_1"), - ) - }) - - it("returns the expected result", () => { - expect(subject.body).toEqual({ - id: IdMap.getId("sales_channel_1"), - object: "sales-channel", - deleted: true, - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/get-sales-channel.ts b/packages/medusa/src/api/routes/admin/sales-channels/__tests__/get-sales-channel.ts deleted file mode 100644 index 0df7ebe301..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/get-sales-channel.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { SalesChannelServiceMock } from "../../../../../services/__mocks__/sales-channel" -import SalesChannelFeatureFlag from "../../../../../loaders/feature-flags/sales-channels"; - -describe("GET /admin/sales-channels/:id", () => { - describe("successfully get a sales channel", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/admin/sales-channels/${IdMap.getId("sales_channel_1")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - flags: [SalesChannelFeatureFlag], - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls the retrieve method from the sales channel service", () => { - expect(SalesChannelServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(SalesChannelServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("sales_channel_1"), - ) - }) - - it("returns the expected sales channel", () => { - expect(subject.body.sales_channel).toEqual({ - id: IdMap.getId("sales_channel_1"), - name: "sales channel 1 name", - description: "sales channel 1 description", - is_disabled: false, - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/list-sales-channels.js b/packages/medusa/src/api/routes/admin/sales-channels/__tests__/list-sales-channels.js deleted file mode 100644 index 835e1309a0..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/list-sales-channels.js +++ /dev/null @@ -1,56 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { SalesChannelServiceMock } from "../../../../../services/__mocks__/sales-channel" -import SalesChannelFeatureFlag from "../../../../../loaders/feature-flags/sales-channels"; - -describe("GET /admin/sales-channels/", () => { - describe("successfully list the sales channel", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/admin/sales-channels`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - flags: [SalesChannelFeatureFlag], - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls the listAndCount method from the sales channel service", () => { - expect(SalesChannelServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(SalesChannelServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - { - order: { created_at: "DESC" }, - relations: [], - skip: 0, - take: 20 - } - ) - }) - - it("returns the expected sales channel", () => { - expect(subject.body).toEqual({ - sales_channels: [{ - id: IdMap.getId("sales_channel_1"), - name: "sales channel 1 name", - description: "sales channel 1 description", - is_disabled: false, - }], - offset: 0, - limit: 20, - count: 1, - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/update-sales-channel.ts b/packages/medusa/src/api/routes/admin/sales-channels/__tests__/update-sales-channel.ts deleted file mode 100644 index d723beb692..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/__tests__/update-sales-channel.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { SalesChannelServiceMock } from "../../../../../services/__mocks__/sales-channel" -import SalesChannelFeatureFlag from "../../../../../loaders/feature-flags/sales-channels"; - -describe("POST /admin/regions/:region_id/countries", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - const id = IdMap.getId("test_sales_channel") - subject = await request("POST", `/admin/sales-channels/${id}`, { - payload: { - name: "amazon", - description: "This is our amazon sales channel", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - flags: [SalesChannelFeatureFlag], - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns updated sales channel", () => { - expect(subject.body.sales_channel).toEqual({ - id: IdMap.getId("test_sales_channel"), - name: "amazon", - description: "This is our amazon sales channel", - }) - }) - - it("calls service update", () => { - expect(SalesChannelServiceMock.update).toHaveBeenCalledTimes(1) - expect(SalesChannelServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("test_sales_channel"), - { - name: "amazon", - description: "This is our amazon sales channel", - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/sales-channels/add-product-batch.ts b/packages/medusa/src/api/routes/admin/sales-channels/add-product-batch.ts deleted file mode 100644 index 27c81bdb15..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/add-product-batch.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { IsArray, ValidateNested } from "class-validator" -import { Request, Response } from "express" - -import { EntityManager } from "typeorm" -import { ProductBatchSalesChannel } from "../../../../types/sales-channels" -import { SalesChannelService } from "../../../../services" -import { Type } from "class-transformer" - -/** - * @oas [post] /admin/sales-channels/{id}/products/batch - * operationId: "PostSalesChannelsChannelProductsBatch" - * summary: "Add Products to Sales Channel" - * description: "Add a list of products to a sales channel." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Sales channel. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostSalesChannelsChannelProductsBatchReq" - * x-codegen: - * method: addProducts - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.addProducts(salesChannelId, { - * product_ids: [ - * { - * id: productId - * } - * ] - * }) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminAddProductsToSalesChannel } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const addProducts = useAdminAddProductsToSalesChannel( - * salesChannelId - * ) - * // ... - * - * const handleAddProducts = (productId: string) => { - * addProducts.mutate({ - * product_ids: [ - * { - * id: productId, - * }, - * ], - * }, { - * onSuccess: ({ sales_channel }) => { - * console.log(sales_channel.id) - * } - * }) - * } - * - * // ... - * } - * - * export default SalesChannel - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/sales-channels/{id}/products/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "product_ids": [ - * { - * "id": "{product_id}" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Sales Channels - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminSalesChannelsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response): Promise => { - const validatedBody = - req.validatedBody as AdminPostSalesChannelsChannelProductsBatchReq - - const { id } = req.params - - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const salesChannel = await manager.transaction(async (transactionManager) => { - return await salesChannelService - .withTransaction(transactionManager) - .addProducts( - id, - validatedBody.product_ids.map((p) => p.id) - ) - }) - - res.status(200).json({ sales_channel: salesChannel }) -} - -/** - * @schema AdminPostSalesChannelsChannelProductsBatchReq - * type: object - * description: "The details of the products to add to the sales channel." - * required: - * - product_ids - * properties: - * product_ids: - * description: The IDs of the products to add to the sales channel - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * type: string - * description: The ID of the product - */ -export class AdminPostSalesChannelsChannelProductsBatchReq { - @IsArray() - @ValidateNested({ each: true }) - @Type(() => ProductBatchSalesChannel) - product_ids: ProductBatchSalesChannel[] -} diff --git a/packages/medusa/src/api/routes/admin/sales-channels/associate-stock-location.ts b/packages/medusa/src/api/routes/admin/sales-channels/associate-stock-location.ts deleted file mode 100644 index 62ef5d3afd..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/associate-stock-location.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { IsString } from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" - -import { - SalesChannelLocationService, - SalesChannelService, -} from "../../../../services" - -/** - * @oas [post] /admin/sales-channels/{id}/stock-locations - * operationId: "PostSalesChannelsSalesChannelStockLocation" - * summary: "Associate a Stock Location" - * description: "Associate a stock location with a Sales Channel." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Sales Channel. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostSalesChannelsChannelStockLocationsReq" - * x-codegen: - * method: addLocation - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.addLocation(salesChannelId, { - * location_id: "loc_123" - * }) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminAddLocationToSalesChannel - * } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const addLocation = useAdminAddLocationToSalesChannel() - * // ... - * - * const handleAddLocation = (locationId: string) => { - * addLocation.mutate({ - * sales_channel_id: salesChannelId, - * location_id: locationId - * }, { - * onSuccess: ({ sales_channel }) => { - * console.log(sales_channel.locations) - * } - * }) - * } - * - * // ... - * } - * - * export default SalesChannel - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/sales-channels/{id}/stock-locations' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "locaton_id": "loc_123" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Sales Channels - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminSalesChannelsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - const { validatedBody } = req as { - validatedBody: AdminPostSalesChannelsChannelStockLocationsReq - } - - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - const channelLocationService: SalesChannelLocationService = req.scope.resolve( - "salesChannelLocationService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await channelLocationService - .withTransaction(transactionManager) - .associateLocation(id, validatedBody.location_id) - }) - - const channel = await salesChannelService.retrieve(id) - - res.status(200).json({ sales_channel: channel }) -} - -/** - * @schema AdminPostSalesChannelsChannelStockLocationsReq - * type: object - * required: - * - location_id - * properties: - * location_id: - * description: The ID of the stock location - * type: string - */ - -export class AdminPostSalesChannelsChannelStockLocationsReq { - @IsString() - location_id: string -} diff --git a/packages/medusa/src/api/routes/admin/sales-channels/create-sales-channel.ts b/packages/medusa/src/api/routes/admin/sales-channels/create-sales-channel.ts deleted file mode 100644 index c377168264..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/create-sales-channel.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { IsBoolean, IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" - -import { CreateSalesChannelInput } from "../../../../types/sales-channels" -import { EntityManager } from "typeorm" -import SalesChannelService from "../../../../services/sales-channel" - -/** - * @oas [post] /admin/sales-channels - * operationId: "PostSalesChannels" - * summary: "Create a Sales Channel" - * description: "Create a Sales Channel." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostSalesChannelsReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.create({ - * name: "App", - * description: "Mobile app" - * }) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateSalesChannel } from "medusa-react" - * - * const CreateSalesChannel = () => { - * const createSalesChannel = useAdminCreateSalesChannel() - * // ... - * - * const handleCreate = (name: string, description: string) => { - * createSalesChannel.mutate({ - * name, - * description, - * }, { - * onSuccess: ({ sales_channel }) => { - * console.log(sales_channel.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateSalesChannel - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/sales-channels' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "App" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Sales Channels - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminSalesChannelsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const validatedBody = req.validatedBody as CreateSalesChannelInput - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const salesChannel = await manager.transaction(async (transactionManager) => { - return await salesChannelService - .withTransaction(transactionManager) - .create(validatedBody) - }) - - res.status(200).json({ sales_channel: salesChannel }) -} - -/** - * @schema AdminPostSalesChannelsReq - * type: object - * description: "The details of the sales channel to create." - * required: - * - name - * properties: - * name: - * description: The name of the Sales Channel - * type: string - * description: - * description: The description of the Sales Channel - * type: string - * is_disabled: - * description: Whether the Sales Channel is disabled. - * type: boolean - */ -export class AdminPostSalesChannelsReq { - @IsString() - name: string - - @IsString() - @IsOptional() - description: string - - @IsBoolean() - @IsOptional() - is_disabled?: boolean -} diff --git a/packages/medusa/src/api/routes/admin/sales-channels/delete-products-batch.ts b/packages/medusa/src/api/routes/admin/sales-channels/delete-products-batch.ts deleted file mode 100644 index 3b05abfc55..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/delete-products-batch.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { IsArray, ValidateNested } from "class-validator" -import { Request, Response } from "express" - -import { EntityManager } from "typeorm" -import { ProductBatchSalesChannel } from "../../../../types/sales-channels" -import { SalesChannelService } from "../../../../services" -import { Type } from "class-transformer" - -/** - * @oas [delete] /admin/sales-channels/{id}/products/batch - * operationId: "DeleteSalesChannelsChannelProductsBatch" - * summary: "Remove Products from Sales Channel" - * description: "Remove a list of products from a sales channel. This does not delete the product. It only removes the association between the product and the sales channel." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Sales Channel - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteSalesChannelsChannelProductsBatchReq" - * x-codegen: - * method: removeProducts - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.removeProducts(salesChannelId, { - * product_ids: [ - * { - * id: productId - * } - * ] - * }) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminDeleteProductsFromSalesChannel, - * } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const deleteProducts = useAdminDeleteProductsFromSalesChannel( - * salesChannelId - * ) - * // ... - * - * const handleDeleteProducts = (productId: string) => { - * deleteProducts.mutate({ - * product_ids: [ - * { - * id: productId, - * }, - * ], - * }, { - * onSuccess: ({ sales_channel }) => { - * console.log(sales_channel.id) - * } - * }) - * } - * - * // ... - * } - * - * export default SalesChannel - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/sales-channels/{id}/products/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "product_ids": [ - * { - * "id": "{product_id}" - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Sales Channels - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminSalesChannelsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req: Request, res: Response) => { - const validatedBody = - req.validatedBody as AdminDeleteSalesChannelsChannelProductsBatchReq - const { id } = req.params - - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const salesChannel = await manager.transaction(async (transactionManager) => { - return await salesChannelService - .withTransaction(transactionManager) - .removeProducts( - id, - validatedBody.product_ids.map((p) => p.id) - ) - }) - - res.status(200).json({ sales_channel: salesChannel }) -} - -/** - * @schema AdminDeleteSalesChannelsChannelProductsBatchReq - * type: object - * description: "The details of the products to delete from the sales channel." - * required: - * - product_ids - * properties: - * product_ids: - * description: The IDs of the products to remove from the sales channel. - * type: array - * items: - * type: object - * required: - * - id - * properties: - * id: - * description: The ID of a product - * type: string - */ -export class AdminDeleteSalesChannelsChannelProductsBatchReq { - @IsArray() - @ValidateNested({ each: true }) - @Type(() => ProductBatchSalesChannel) - product_ids: ProductBatchSalesChannel[] -} diff --git a/packages/medusa/src/api/routes/admin/sales-channels/delete-sales-channel.ts b/packages/medusa/src/api/routes/admin/sales-channels/delete-sales-channel.ts deleted file mode 100644 index cd84349105..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/delete-sales-channel.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { Request, Response } from "express" - -import { EntityManager } from "typeorm" -import { SalesChannelService } from "../../../../services/" - -/** - * @oas [delete] /admin/sales-channels/{id} - * operationId: "DeleteSalesChannelsSalesChannel" - * summary: "Delete a Sales Channel" - * description: "Delete a sales channel. Associated products, stock locations, and other resources are not deleted." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Sales channel. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.delete(salesChannelId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteSalesChannel } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const deleteSalesChannel = useAdminDeleteSalesChannel( - * salesChannelId - * ) - * // ... - * - * const handleDelete = () => { - * deleteSalesChannel.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default SalesChannel - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/sales-channels/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Sales Channels - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminSalesChannelsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response): Promise => { - const { id } = req.params - - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await salesChannelService - .withTransaction(transactionManager) - .delete(id) - }) - - res.json({ - id, - object: "sales-channel", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/sales-channels/get-sales-channel.ts b/packages/medusa/src/api/routes/admin/sales-channels/get-sales-channel.ts deleted file mode 100644 index 8d7e38f0ec..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/get-sales-channel.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Request, Response } from "express" - -import { SalesChannelService } from "../../../../services" - -/** - * @oas [get] /admin/sales-channels/{id} - * operationId: "GetSalesChannelsSalesChannel" - * summary: "Get a Sales Channel" - * description: "Retrieve a sales channel's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Sales channel. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.retrieve(salesChannelId) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminSalesChannel } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const { - * sales_channel, - * isLoading, - * } = useAdminSalesChannel(salesChannelId) - * - * return ( - *
- * {isLoading && Loading...} - * {sales_channel && {sales_channel.name}} - *
- * ) - * } - * - * export default SalesChannel - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/sales-channels/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Sales Channels - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminSalesChannelsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response): Promise => { - const { id } = req.params - - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - - const salesChannel = await salesChannelService.retrieve(id) - res.status(200).json({ sales_channel: salesChannel }) -} diff --git a/packages/medusa/src/api/routes/admin/sales-channels/index.ts b/packages/medusa/src/api/routes/admin/sales-channels/index.ts deleted file mode 100644 index f574b82b71..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/index.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { Router } from "express" -import "reflect-metadata" -import { SalesChannel } from "../../../../models" -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" -import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled" -import { validateProductsExist } from "../../../middlewares/validators/product-existence" -import { AdminPostSalesChannelsChannelProductsBatchReq } from "./add-product-batch" -import { AdminPostSalesChannelsReq } from "./create-sales-channel" -import { AdminDeleteSalesChannelsChannelProductsBatchReq } from "./delete-products-batch" -import { AdminGetSalesChannelsParams } from "./list-sales-channels" -import { AdminPostSalesChannelsSalesChannelReq } from "./update-sales-channel" -import { AdminPostSalesChannelsChannelStockLocationsReq } from "./associate-stock-location" -import { AdminDeleteSalesChannelsChannelStockLocationsReq } from "./remove-stock-location" -import { checkRegisteredModules } from "../../../middlewares/check-registered-modules" - -const route = Router() - -export default (app) => { - app.use("/sales-channels", isFeatureFlagEnabled("sales_channels"), route) - - route.get( - "/", - transformQuery(AdminGetSalesChannelsParams, { - isList: true, - }), - middlewares.wrap(require("./list-sales-channels").default) - ) - - const salesChannelRouter = Router({ mergeParams: true }) - route.use("/:id", salesChannelRouter) - - salesChannelRouter.get( - "/", - middlewares.wrap(require("./get-sales-channel").default) - ) - salesChannelRouter.delete( - "/", - middlewares.wrap(require("./delete-sales-channel").default) - ) - salesChannelRouter.post( - "/", - transformBody(AdminPostSalesChannelsSalesChannelReq), - middlewares.wrap(require("./update-sales-channel").default) - ) - salesChannelRouter.post( - "/stock-locations", - checkRegisteredModules({ - stockLocationService: - "Stock Locations are not enabled. Please add a Stock Location module to enable this functionality.", - }), - transformBody(AdminPostSalesChannelsChannelStockLocationsReq), - middlewares.wrap(require("./associate-stock-location").default) - ) - salesChannelRouter.delete( - "/stock-locations", - checkRegisteredModules({ - stockLocationService: - "Stock Locations are not enabled. Please add a Stock Location module to enable this functionality.", - }), - transformBody(AdminDeleteSalesChannelsChannelStockLocationsReq), - middlewares.wrap(require("./remove-stock-location").default) - ) - salesChannelRouter.delete( - "/products/batch", - transformBody(AdminDeleteSalesChannelsChannelProductsBatchReq), - middlewares.wrap(require("./delete-products-batch").default) - ) - salesChannelRouter.post( - "/products/batch", - transformBody(AdminPostSalesChannelsChannelProductsBatchReq), - validateProductsExist((req) => req.body.product_ids), - middlewares.wrap(require("./add-product-batch").default) - ) - - route.post( - "/", - transformBody(AdminPostSalesChannelsReq), - middlewares.wrap(require("./create-sales-channel").default) - ) - - return app -} - -/** - * @schema AdminSalesChannelsRes - * type: object - * description: "The sales channel's details." - * required: - * - sales_channel - * properties: - * sales_channel: - * description: Sales Channel's details. - * $ref: "#/components/schemas/SalesChannel" - */ -export type AdminSalesChannelsRes = { - sales_channel: SalesChannel -} - -/** - * @schema AdminSalesChannelsDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted sales channel - * object: - * type: string - * description: The type of the object that was deleted. - * default: sales-channel - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminSalesChannelsDeleteRes = DeleteResponse - -/** - * @schema AdminSalesChannelsDeleteLocationRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the removed stock location from a sales channel - * object: - * type: string - * description: The type of the object that was removed. - * default: stock-location - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminSalesChannelsDeleteLocationRes = DeleteResponse - -/** - * @schema AdminSalesChannelsListRes - * type: object - * description: "The list of sales channels with pagination fields." - * required: - * - sales_channels - * - count - * - offset - * - limit - * properties: - * sales_channels: - * type: array - * description: "An array of sales channels details." - * items: - * $ref: "#/components/schemas/SalesChannel" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of items skipped before the returned results - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminSalesChannelsListRes = PaginatedResponse & { - sales_channels: SalesChannel[] -} - -export * from "./add-product-batch" -export * from "./create-sales-channel" -export * from "./delete-products-batch" -export * from "./delete-sales-channel" -export * from "./get-sales-channel" -export * from "./list-sales-channels" -export * from "./update-sales-channel" -export * from "./associate-stock-location" -export * from "./remove-stock-location" diff --git a/packages/medusa/src/api/routes/admin/sales-channels/list-sales-channels.ts b/packages/medusa/src/api/routes/admin/sales-channels/list-sales-channels.ts deleted file mode 100644 index afa3b61d6f..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/list-sales-channels.ts +++ /dev/null @@ -1,248 +0,0 @@ -import { - DateComparisonOperator, - extendedFindParamsMixin, -} from "../../../../types/common" -import { IsOptional, IsString, ValidateNested } from "class-validator" -import { Request, Response } from "express" - -import { SalesChannelService } from "../../../../services" -import { Type } from "class-transformer" - -/** - * @oas [get] /admin/sales-channels - * operationId: "GetSalesChannels" - * summary: "List Sales Channels" - * description: "Retrieve a list of sales channels. The sales channels can be filtered by fields such as `q` or `name`. The sales channels can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) id {string} Filter by a sales channel ID. - * - (query) name {string} Filter by name. - * - (query) description {string} Filter by description. - * - (query) q {string} term used to search sales channels' names and descriptions. - * - (query) order {string} A sales-channel field to sort-order the retrieved sales channels by. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: deleted_at - * description: Filter by a deletion date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - (query) offset=0 {integer} The number of sales channels to skip when retrieving the sales channels. - * - (query) limit=20 {integer} Limit the number of sales channels returned. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned sales channels. - * - (query) fields {string} Comma-separated fields that should be included in the returned sales channels. - * x-codegen: - * method: list - * queryParams: AdminGetSalesChannelsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.list() - * .then(({ sales_channels, limit, offset, count }) => { - * console.log(sales_channels.length) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminSalesChannels } from "medusa-react" - * - * const SalesChannels = () => { - * const { sales_channels, isLoading } = useAdminSalesChannels() - * - * return ( - *
- * {isLoading && Loading...} - * {sales_channels && !sales_channels.length && ( - * No Sales Channels - * )} - * {sales_channels && sales_channels.length > 0 && ( - *
    - * {sales_channels.map((salesChannel) => ( - *
  • {salesChannel.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default SalesChannels - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/sales-channels' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Sales Channels - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminSalesChannelsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - - const listConfig = req.listConfig - const filterableFields = req.filterableFields - - const [salesChannels, count] = await salesChannelService.listAndCount( - filterableFields, - listConfig - ) - - res.status(200).json({ - sales_channels: salesChannels, - count, - offset: listConfig.skip, - limit: listConfig.take, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved sales channels. - */ -export class AdminGetSalesChannelsParams extends extendedFindParamsMixin() { - /** - * ID to filter sales channels by. - */ - @IsString() - @IsOptional() - id?: string - - /** - * Search term to search sales channels' names and descriptions. - */ - @IsOptional() - @IsString() - q?: string - - /** - * Name to filter sales channels by. - */ - @IsOptional() - @IsString() - name?: string - - /** - * Description to filter sales channels by. - */ - @IsOptional() - @IsString() - description?: string - - /** - * Date filters to apply on sales channels' `created_at` field. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on sales channels' `updated_at` field. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on sales channels' `deleted_at` field. - */ - @ValidateNested() - @IsOptional() - @Type(() => DateComparisonOperator) - deleted_at?: DateComparisonOperator - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string -} diff --git a/packages/medusa/src/api/routes/admin/sales-channels/remove-stock-location.ts b/packages/medusa/src/api/routes/admin/sales-channels/remove-stock-location.ts deleted file mode 100644 index f869b1dbe4..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/remove-stock-location.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { Request, Response } from "express" - -import { EntityManager } from "typeorm" -import { IsString } from "class-validator" -import { SalesChannelLocationService } from "../../../../services" - -/** - * @oas [delete] /admin/sales-channels/{id}/stock-locations - * operationId: "DeleteSalesChannelsSalesChannelStockLocation" - * summary: "Remove Stock Location from Sales Channels." - * description: "Remove a stock location from a Sales Channel. This only removes the association between the stock location and the sales channel. It does not delete the stock location." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Sales Channel. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteSalesChannelsChannelStockLocationsReq" - * x-codegen: - * method: removeLocation - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.removeLocation(salesChannelId, { - * location_id: "loc_id" - * }) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminRemoveLocationFromSalesChannel - * } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const removeLocation = useAdminRemoveLocationFromSalesChannel() - * // ... - * - * const handleRemoveLocation = (locationId: string) => { - * removeLocation.mutate({ - * sales_channel_id: salesChannelId, - * location_id: locationId - * }, { - * onSuccess: ({ sales_channel }) => { - * console.log(sales_channel.locations) - * } - * }) - * } - * - * // ... - * } - * - * export default SalesChannel - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/sales-channels/{id}/stock-locations' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "locaton_id": "loc_id" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Sales Channels - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminSalesChannelsDeleteLocationRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - const { validatedBody } = req as { - validatedBody: AdminDeleteSalesChannelsChannelStockLocationsReq - } - - const channelLocationService: SalesChannelLocationService = req.scope.resolve( - "salesChannelLocationService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - await channelLocationService - .withTransaction(transactionManager) - .removeLocation(validatedBody.location_id, id) - }) - - res.json({ - id, - object: "stock-location", - deleted: true, - }) -} - -/** - * @schema AdminDeleteSalesChannelsChannelStockLocationsReq - * type: object - * required: - * - location_id - * properties: - * location_id: - * description: The ID of the stock location - * type: string - */ -export class AdminDeleteSalesChannelsChannelStockLocationsReq { - @IsString() - location_id: string -} diff --git a/packages/medusa/src/api/routes/admin/sales-channels/update-sales-channel.ts b/packages/medusa/src/api/routes/admin/sales-channels/update-sales-channel.ts deleted file mode 100644 index 0f2bedbbf7..0000000000 --- a/packages/medusa/src/api/routes/admin/sales-channels/update-sales-channel.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { IsBoolean, IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" - -import { SalesChannelService } from "../../../../services" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/sales-channels/{id} - * operationId: "PostSalesChannelsSalesChannel" - * summary: "Update a Sales Channel" - * description: "Update a Sales Channel's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Sales Channel. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostSalesChannelsSalesChannelReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.salesChannels.update(salesChannelId, { - * name: "App" - * }) - * .then(({ sales_channel }) => { - * console.log(sales_channel.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateSalesChannel } from "medusa-react" - * - * type Props = { - * salesChannelId: string - * } - * - * const SalesChannel = ({ salesChannelId }: Props) => { - * const updateSalesChannel = useAdminUpdateSalesChannel( - * salesChannelId - * ) - * // ... - * - * const handleUpdate = ( - * is_disabled: boolean - * ) => { - * updateSalesChannel.mutate({ - * is_disabled, - * }, { - * onSuccess: ({ sales_channel }) => { - * console.log(sales_channel.is_disabled) - * } - * }) - * } - * - * // ... - * } - * - * export default SalesChannel - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/sales-channels/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "App" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Sales Channels - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminSalesChannelsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - const { validatedBody } = req as { - validatedBody: AdminPostSalesChannelsSalesChannelReq - } - - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - const manager: EntityManager = req.scope.resolve("manager") - const sales_channel = await manager.transaction( - async (transactionManager) => { - return await salesChannelService - .withTransaction(transactionManager) - .update(id, validatedBody) - } - ) - - res.status(200).json({ sales_channel }) -} - -/** - * @schema AdminPostSalesChannelsSalesChannelReq - * type: object - * description: "The details to update of the sales channel." - * properties: - * name: - * type: string - * description: The name of the sales channel - * description: - * type: string - * description: The description of the sales channel. - * is_disabled: - * type: boolean - * description: Whether the Sales Channel is disabled. - */ -export class AdminPostSalesChannelsSalesChannelReq { - @IsOptional() - @IsString() - name?: string - - @IsOptional() - @IsString() - description?: string - - @IsBoolean() - @IsOptional() - is_disabled?: boolean -} diff --git a/packages/medusa/src/api/routes/admin/shipping-options/__tests__/create-shipping-option.js b/packages/medusa/src/api/routes/admin/shipping-options/__tests__/create-shipping-option.js deleted file mode 100644 index b14e7c71fe..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-options/__tests__/create-shipping-option.js +++ /dev/null @@ -1,95 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { ShippingOptionServiceMock } from "../../../../../services/__mocks__/shipping-option" -import { request } from "../../../../../helpers/test-request" - -describe("POST /admin/shipping-options", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("POST", "/admin/shipping-options", { - payload: { - name: "Test option", - region_id: "testregion", - provider_id: "test_provider", - data: { id: "test" }, - price_type: "flat_rate", - amount: 100, - requirements: [ - { - type: "min_subtotal", - amount: 1, - }, - ], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service create", () => { - expect(ShippingOptionServiceMock.create).toHaveBeenCalledTimes(1) - expect(ShippingOptionServiceMock.create).toHaveBeenCalledWith({ - is_return: false, - admin_only: false, - name: "Test option", - region_id: "testregion", - provider_id: "test_provider", - metadata: undefined, - data: { id: "test" }, - profile_id: expect.any(String), - price_type: "flat_rate", - amount: 100, - requirements: [ - { - type: "min_subtotal", - amount: 1, - }, - ], - }) - }) - }) - - describe("fails on invalid data", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("POST", "/admin/shipping-options", { - payload: { - price_type: "flat_rate", - amount: 100, - requirements: [ - { - type: "min_subtotal", - amount: 1, - }, - ], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns error", () => { - expect(subject.body.message).toEqual( - expect.stringContaining(`name must be a string`) - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/shipping-options/__tests__/delete-shipping-option.js b/packages/medusa/src/api/routes/admin/shipping-options/__tests__/delete-shipping-option.js deleted file mode 100644 index 188cdd0512..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-options/__tests__/delete-shipping-option.js +++ /dev/null @@ -1,34 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ShippingOptionServiceMock } from "../../../../../services/__mocks__/shipping-option" - -describe("DELETE /admin/shipping-options/{id}", () => { - describe("successful deletion", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/shipping-options/${IdMap.getId("validId")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service delete", () => { - expect(ShippingOptionServiceMock.delete).toHaveBeenCalledTimes(1) - expect(ShippingOptionServiceMock.delete).toHaveBeenCalledWith( - IdMap.getId("validId") - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/shipping-options/__tests__/get-shipping-options.js b/packages/medusa/src/api/routes/admin/shipping-options/__tests__/get-shipping-options.js deleted file mode 100644 index ffd130580e..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-options/__tests__/get-shipping-options.js +++ /dev/null @@ -1,57 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ShippingOptionServiceMock } from "../../../../../services/__mocks__/shipping-option" - -const defaultFields = [ - "id", - "name", - "region_id", - "profile_id", - "provider_id", - "price_type", - "amount", - "is_return", - "admin_only", - "data", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -const defaultRelations = ["region", "profile", "requirements"] - -describe("GET /admin/shipping-options/:optionId", () => { - describe("successful retrieval", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/admin/shipping-options/${IdMap.getId("validId")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve", () => { - expect(ShippingOptionServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(ShippingOptionServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("validId"), - { - select: defaultFields, - relations: defaultRelations, - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/shipping-options/__tests__/list-shipping-options.js b/packages/medusa/src/api/routes/admin/shipping-options/__tests__/list-shipping-options.js deleted file mode 100644 index c74e885d4f..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-options/__tests__/list-shipping-options.js +++ /dev/null @@ -1,41 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ShippingOptionServiceMock } from "../../../../../services/__mocks__/shipping-option" -import { - shippingOptionsDefaultFields, - shippingOptionsDefaultRelations, -} from "../index" - -describe("GET /admin/shipping-options", () => { - describe("successful retrieval", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/admin/shipping-options`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve", () => { - expect(ShippingOptionServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(ShippingOptionServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - { - order: { created_at: "DESC" }, - select: shippingOptionsDefaultFields, - relations: shippingOptionsDefaultRelations, - skip: 0, - take: 50, - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/shipping-options/__tests__/update-shipping-option.js b/packages/medusa/src/api/routes/admin/shipping-options/__tests__/update-shipping-option.js deleted file mode 100644 index f6886a05f1..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-options/__tests__/update-shipping-option.js +++ /dev/null @@ -1,56 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ShippingOptionServiceMock } from "../../../../../services/__mocks__/shipping-option" - -describe("POST /admin/shipping-options", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/shipping-options/${IdMap.getId("validId")}`, - { - payload: { - name: "Test option", - amount: 100, - requirements: [ - { - id: "yes", - type: "min_subtotal", - amount: 1, - }, - ], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service method", () => { - expect(ShippingOptionServiceMock.update).toHaveBeenCalledTimes(1) - expect(ShippingOptionServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("validId"), - { - name: "Test option", - amount: 100, - requirements: [ - { - id: "yes", - type: "min_subtotal", - amount: 1, - }, - ], - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/shipping-options/create-shipping-option.ts b/packages/medusa/src/api/routes/admin/shipping-options/create-shipping-option.ts deleted file mode 100644 index a18f1c3e4a..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-options/create-shipping-option.ts +++ /dev/null @@ -1,297 +0,0 @@ -import { - IsArray, - IsBoolean, - IsEnum, - IsNumber, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { - shippingOptionsDefaultFields, - shippingOptionsDefaultRelations, -} from "." -import { RequirementType, ShippingOptionPriceType } from "../../../../models" - -import { Type } from "class-transformer" -import { EntityManager } from "typeorm" -import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" -import { ShippingOptionService } from "../../../../services" -import { CreateShippingOptionInput } from "../../../../types/shipping-options" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/shipping-options - * operationId: "PostShippingOptions" - * summary: "Create Shipping Option" - * description: "Create a Shipping Option." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostShippingOptionsReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingOptions.create({ - * name: "PostFake", - * region_id, - * provider_id, - * data: { - * }, - * price_type: "flat_rate" - * }) - * .then(({ shipping_option }) => { - * console.log(shipping_option.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateShippingOption } from "medusa-react" - * - * type CreateShippingOption = { - * name: string - * provider_id: string - * data: Record - * price_type: string - * amount: number - * } - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ regionId }: Props) => { - * const createShippingOption = useAdminCreateShippingOption() - * // ... - * - * const handleCreate = ( - * data: CreateShippingOption - * ) => { - * createShippingOption.mutate({ - * ...data, - * region_id: regionId - * }, { - * onSuccess: ({ shipping_option }) => { - * console.log(shipping_option.id) - * } - * }) - * } - * - * // ... - * } - * - * export default Region - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/shipping-options' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "PostFake", - * "region_id": "afasf", - * "provider_id": "manual", - * "data": {}, - * "price_type": "flat_rate" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Shipping Options - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminShippingOptionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminPostShippingOptionsReq, req.body) - - const optionService: ShippingOptionService = req.scope.resolve( - "shippingOptionService" - ) - const shippingProfileService = req.scope.resolve("shippingProfileService") - - // Add to default shipping profile - if (!validated.profile_id) { - const { id } = await shippingProfileService.retrieveDefault() - validated.profile_id = id - } - - const manager: EntityManager = req.scope.resolve("manager") - const result = await manager.transaction(async (transactionManager) => { - return await optionService - .withTransaction(transactionManager) - .create(validated as CreateShippingOptionInput) - }) - - const data = await optionService.retrieve(result.id, { - select: shippingOptionsDefaultFields, - relations: shippingOptionsDefaultRelations, - }) - - res.status(200).json({ shipping_option: data }) -} - -class OptionRequirement { - @IsEnum(RequirementType, { - message: `Invalid option type, must be one of "min_subtotal" or "max_subtotal"`, - }) - type: RequirementType - - @IsNumber() - amount: number -} - -/** - * @schema AdminPostShippingOptionsReq - * type: object - * description: "The details of the shipping option to create." - * required: - * - name - * - region_id - * - provider_id - * - data - * - price_type - * properties: - * name: - * description: "The name of the Shipping Option" - * type: string - * region_id: - * description: "The ID of the Region in which the Shipping Option will be available." - * type: string - * provider_id: - * description: "The ID of the Fulfillment Provider that handles the Shipping Option." - * type: string - * profile_id: - * description: "The ID of the Shipping Profile to add the Shipping Option to." - * type: number - * data: - * description: "The data needed for the Fulfillment Provider to handle shipping with this Shipping Option." - * type: object - * price_type: - * description: >- - * The type of the Shipping Option price. `flat_rate` indicates fixed pricing, whereas `calculated` indicates that the price will be calculated each time by the fulfillment provider. - * type: string - * enum: - * - flat_rate - * - calculated - * amount: - * description: >- - * The amount to charge for the Shipping Option. If the `price_type` is set to `calculated`, this amount will not actually be used. - * type: integer - * requirements: - * description: "The requirements that must be satisfied for the Shipping Option to be available." - * type: array - * items: - * type: object - * required: - * - type - * - amount - * properties: - * type: - * description: The type of the requirement - * type: string - * enum: - * - max_subtotal - * - min_subtotal - * amount: - * description: The amount to compare with. - * type: integer - * is_return: - * description: Whether the Shipping Option can be used for returns or during checkout. - * type: boolean - * default: false - * admin_only: - * description: >- - * If set to `true`, the shipping option can only be used when creating draft orders. - * type: boolean - * default: false - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * includes_tax: - * description: "Tax included in prices of shipping option" - * x-featureFlag: "tax_inclusive_pricing" - * type: boolean - */ -export class AdminPostShippingOptionsReq { - @IsString() - name: string - - @IsString() - region_id: string - - @IsString() - provider_id: string - - @IsString() - @IsOptional() - profile_id?: string - - @IsObject() - data: Record - - @IsEnum(ShippingOptionPriceType, { - message: `Invalid price type, must be one of "flat_rate" or "calculated"`, - }) - price_type: ShippingOptionPriceType - - @IsOptional() - @IsNumber() - amount?: number - - @IsArray() - @IsOptional() - @ValidateNested({ each: true }) - @Type(() => OptionRequirement) - requirements?: OptionRequirement[] - - @IsOptional() - @Type(() => Boolean) - admin_only?: boolean = false - - @IsOptional() - @Type(() => Boolean) - is_return?: boolean = false - - @IsObject() - @IsOptional() - metadata?: Record - - @FeatureFlagDecorators(TaxInclusivePricingFeatureFlag.key, [ - IsOptional(), - IsBoolean(), - ]) - includes_tax?: boolean -} diff --git a/packages/medusa/src/api/routes/admin/shipping-options/delete-shipping-option.ts b/packages/medusa/src/api/routes/admin/shipping-options/delete-shipping-option.ts deleted file mode 100644 index c88f900743..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-options/delete-shipping-option.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { EntityManager } from "typeorm" - -/** - * @oas [delete] /admin/shipping-options/{id} - * operationId: "DeleteShippingOptionsOption" - * summary: "Delete Shipping Option" - * description: "Delete a Shipping Option. Once deleted, it can't be used when creating orders or returns." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Shipping Option. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingOptions.delete(optionId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteShippingOption } from "medusa-react" - * - * type Props = { - * shippingOptionId: string - * } - * - * const ShippingOption = ({ shippingOptionId }: Props) => { - * const deleteShippingOption = useAdminDeleteShippingOption( - * shippingOptionId - * ) - * // ... - * - * const handleDelete = () => { - * deleteShippingOption.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default ShippingOption - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/shipping-options/{option_id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Shipping Options - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminShippingOptionsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { option_id } = req.params - const optionService = req.scope.resolve("shippingOptionService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await optionService - .withTransaction(transactionManager) - .delete(option_id) - }) - - res.json({ - id: option_id, - object: "shipping-option", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/shipping-options/get-shipping-option.ts b/packages/medusa/src/api/routes/admin/shipping-options/get-shipping-option.ts deleted file mode 100644 index cc34f10abf..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-options/get-shipping-option.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { - shippingOptionsDefaultFields, - shippingOptionsDefaultRelations, -} from "." - -/** - * @oas [get] /admin/shipping-options/{id} - * operationId: "GetShippingOptionsOption" - * summary: "Get a Shipping Option" - * description: "Retrieve a Shipping Option's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Shipping Option. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingOptions.retrieve(optionId) - * .then(({ shipping_option }) => { - * console.log(shipping_option.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminShippingOption } from "medusa-react" - * - * type Props = { - * shippingOptionId: string - * } - * - * const ShippingOption = ({ shippingOptionId }: Props) => { - * const { - * shipping_option, - * isLoading - * } = useAdminShippingOption( - * shippingOptionId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {shipping_option && {shipping_option.name}} - *
- * ) - * } - * - * export default ShippingOption - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/shipping-options/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Shipping Options - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminShippingOptionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { option_id } = req.params - const optionService = req.scope.resolve("shippingOptionService") - - const data = await optionService.retrieve(option_id, { - select: shippingOptionsDefaultFields, - relations: shippingOptionsDefaultRelations, - }) - - res.status(200).json({ shipping_option: data }) -} diff --git a/packages/medusa/src/api/routes/admin/shipping-options/index.ts b/packages/medusa/src/api/routes/admin/shipping-options/index.ts deleted file mode 100644 index 8d53718f4d..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-options/index.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { Router } from "express" -import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" -import { ShippingOption } from "../../../../models" -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import middlewares, { transformQuery } from "../../../middlewares" -import { AdminGetShippingOptionsParams } from "./list-shipping-options" - -const route = Router() - -export default (app, featureFlagRouter: FlagRouter) => { - app.use("/shipping-options", route) - - if (featureFlagRouter.isFeatureEnabled(TaxInclusivePricingFeatureFlag.key)) { - shippingOptionsDefaultFields.push("includes_tax") - } - - route.get( - "/", - transformQuery(AdminGetShippingOptionsParams, { - defaultFields: shippingOptionsDefaultFields, - defaultRelations: shippingOptionsDefaultRelations, - isList: true, - }), - middlewares.wrap(require("./list-shipping-options").default) - ) - route.post("/", middlewares.wrap(require("./create-shipping-option").default)) - - route.get( - "/:option_id", - middlewares.wrap(require("./get-shipping-option").default) - ) - route.post( - "/:option_id", - middlewares.wrap(require("./update-shipping-option").default) - ) - route.delete( - "/:option_id", - middlewares.wrap(require("./delete-shipping-option").default) - ) - - return app -} - -export const shippingOptionsDefaultFields: (keyof ShippingOption)[] = [ - "id", - "name", - "region_id", - "profile_id", - "provider_id", - "price_type", - "amount", - "is_return", - "admin_only", - "data", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -export const shippingOptionsDefaultRelations = [ - "region", - "profile", - "requirements", -] - -/** - * @schema AdminShippingOptionsListRes - * type: object - * description: "The list of shipping options with pagination fields." - * x-expanded-relations: - * field: shipping_options - * relations: - * - profile - * - region - * - requirements - * eager: - * - region.fulfillment_providers - * - region.payment_providers - * required: - * - shipping_options - * - count - * - offset - * - limit - * properties: - * shipping_options: - * type: array - * description: "An array of shipping options details." - * items: - * $ref: "#/components/schemas/ShippingOption" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of shipping options skipped when retrieving the shipping options. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminShippingOptionsListRes = PaginatedResponse & { - shipping_options: ShippingOption[] -} - -/** - * @schema AdminShippingOptionsRes - * type: object - * description: "The shipping option's details." - * x-expanded-relations: - * field: shipping_option - * relations: - * - profile - * - region - * - requirements - * eager: - * - region.fulfillment_providers - * - region.payment_providers - * required: - * - shipping_option - * properties: - * shipping_option: - * description: "Shipping option details." - * $ref: "#/components/schemas/ShippingOption" - */ -export type AdminShippingOptionsRes = { - shipping_option: ShippingOption -} - -/** - * @schema AdminShippingOptionsDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Shipping Option. - * object: - * type: string - * description: The type of the object that was deleted. - * default: shipping-option - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminShippingOptionsDeleteRes = DeleteResponse - -export * from "./create-shipping-option" -export * from "./delete-shipping-option" -export * from "./get-shipping-option" -export * from "./list-shipping-options" -export * from "./update-shipping-option" diff --git a/packages/medusa/src/api/routes/admin/shipping-options/list-shipping-options.ts b/packages/medusa/src/api/routes/admin/shipping-options/list-shipping-options.ts deleted file mode 100644 index 678581e5c7..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-options/list-shipping-options.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { - IsBoolean, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" - -import { Transform, Type } from "class-transformer" -import { Request, Response } from "express" -import { PricingService, ShippingOptionService } from "../../../../services" -import { - DateComparisonOperator, - extendedFindParamsMixin, -} from "../../../../types/common" -import { IsType } from "../../../../utils" -import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean" - -/** - * @oas [get] /admin/shipping-options - * operationId: "GetShippingOptions" - * summary: "List Shipping Options" - * description: "Retrieve a list of Shipping Options. The shipping options can be filtered by fields such as `region_id` or `is_return`. The shipping options can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) name {string} Filter by name. - * - (query) region_id {string} Filter by the ID of the region the shipping options belong to. - * - (query) is_return {boolean} Filter by whether the shipping options are return shipping options. - * - (query) admin_only {boolean} Filter by whether the shipping options are available for admin users only. - * - (query) q {string} Term used to search shipping options' name. - * - (query) order {string} A shipping option field to sort-order the retrieved shipping options by. - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by shipping option IDs. - * schema: - * oneOf: - * - type: string - * description: ID of the shipping option. - * - type: array - * items: - * type: string - * description: ID of a shipping option. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: deleted_at - * description: Filter by a deletion date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - (query) offset=0 {integer} The number of users to skip when retrieving the shipping options. - * - (query) limit=20 {integer} Limit the number of shipping options returned. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned shipping options. - * - (query) fields {string} Comma-separated fields that should be included in the returned shipping options. - * x-codegen: - * method: list - * queryParams: AdminGetShippingOptionsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingOptions.list() - * .then(({ shipping_options, count }) => { - * console.log(shipping_options.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminShippingOptions } from "medusa-react" - * - * const ShippingOptions = () => { - * const { - * shipping_options, - * isLoading - * } = useAdminShippingOptions() - * - * return ( - *
- * {isLoading && Loading...} - * {shipping_options && !shipping_options.length && ( - * No Shipping Options - * )} - * {shipping_options && shipping_options.length > 0 && ( - *
    - * {shipping_options.map((option) => ( - *
  • {option.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ShippingOptions - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/shipping-options' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Shipping Options - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminShippingOptionsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const optionService: ShippingOptionService = req.scope.resolve( - "shippingOptionService" - ) - const pricingService: PricingService = req.scope.resolve("pricingService") - - const listConfig = req.listConfig - const filterableFields = req.filterableFields - - const [data, count] = await optionService.listAndCount( - filterableFields, - listConfig - ) - - const options = await pricingService.setShippingOptionPrices(data) - - res.status(200).json({ - shipping_options: options, - count, - offset: listConfig.skip, - limit: listConfig.take, - }) -} - -/** - * Parameters used to filter the retrieved shipping options. - */ -export class AdminGetShippingOptionsParams extends extendedFindParamsMixin({ - limit: 50, - offset: 0, -}) { - /** - * IDs to filter shipping options by. - */ - @IsOptional() - @IsType([String, [String]]) - id?: string | string[] - - /** - * Name to filter shipping options by. - */ - @IsOptional() - @IsString() - name?: string - - /** - * Filter by a region ID. - */ - @IsOptional() - @IsString() - region_id?: string - - /** - * Filter by whether the shipping option is used for returns or orders. - */ - @IsOptional() - @IsBoolean() - @Transform(({ value }) => optionalBooleanMapper.get(value)) - is_return?: boolean - - /** - * Filter by whether the shipping options are available for admin users only. - */ - @IsOptional() - @IsBoolean() - @Transform(({ value }) => optionalBooleanMapper.get(value)) - admin_only?: boolean - - /** - * Filter shipping options by a search query. - */ - @IsOptional() - @IsString() - q?: string - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsOptional() - @IsString() - order?: string - - /** - * Date filters to apply on shipping options' `created_at` field. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on shipping options' `updated_at` field. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on shipping options' `deleted_at` field. - */ - @ValidateNested() - @IsOptional() - @Type(() => DateComparisonOperator) - deleted_at?: DateComparisonOperator - - /** - * Comma-separated fields that should be included in the returned shipping options. - */ - @IsOptional() - @IsString() - fields?: string - - /** - * Comma-separated relations that should be expanded in the returned shipping options. - */ - @IsOptional() - @IsString() - expand?: string -} diff --git a/packages/medusa/src/api/routes/admin/shipping-options/update-shipping-option.ts b/packages/medusa/src/api/routes/admin/shipping-options/update-shipping-option.ts deleted file mode 100644 index 558b7f8c58..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-options/update-shipping-option.ts +++ /dev/null @@ -1,260 +0,0 @@ -import { - IsArray, - IsBoolean, - IsEnum, - IsNumber, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { - shippingOptionsDefaultFields, - shippingOptionsDefaultRelations, -} from "." - -import { Type } from "class-transformer" -import { EntityManager } from "typeorm" -import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" -import { ShippingOptionPriceType } from "../../../../models" -import { ShippingOptionService } from "../../../../services" -import { UpdateShippingOptionInput } from "../../../../types/shipping-options" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/shipping-options/{id} - * operationId: "PostShippingOptionsOption" - * summary: "Update Shipping Option" - * description: "Update a Shipping Option's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Shipping Option. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostShippingOptionsOptionReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingOptions.update(optionId, { - * name: "PostFake", - * requirements: [ - * { - * id, - * type: "max_subtotal", - * amount: 1000 - * } - * ] - * }) - * .then(({ shipping_option }) => { - * console.log(shipping_option.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateShippingOption } from "medusa-react" - * - * type Props = { - * shippingOptionId: string - * } - * - * const ShippingOption = ({ shippingOptionId }: Props) => { - * const updateShippingOption = useAdminUpdateShippingOption( - * shippingOptionId - * ) - * // ... - * - * const handleUpdate = ( - * name: string, - * requirements: { - * id: string, - * type: string, - * amount: number - * }[] - * ) => { - * updateShippingOption.mutate({ - * name, - * requirements - * }, { - * onSuccess: ({ shipping_option }) => { - * console.log(shipping_option.requirements) - * } - * }) - * } - * - * // ... - * } - * - * export default ShippingOption - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/shipping-options/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "requirements": [ - * { - * "type": "max_subtotal", - * "amount": 1000 - * } - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Shipping Options - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminShippingOptionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { option_id } = req.params - - const validated = (await validator( - AdminPostShippingOptionsOptionReq, - req.body - )) as UpdateShippingOptionInput - - const optionService: ShippingOptionService = req.scope.resolve( - "shippingOptionService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await optionService - .withTransaction(transactionManager) - .update(option_id, validated) - }) - - const data = await optionService.retrieve(option_id, { - select: shippingOptionsDefaultFields, - relations: shippingOptionsDefaultRelations, - }) - - res.status(200).json({ shipping_option: data }) -} - -class OptionRequirement { - @IsString() - @IsOptional() - id: string - - @IsString() - type: string - - @IsNumber() - amount: number -} - -/** - * @schema AdminPostShippingOptionsOptionReq - * type: object - * description: "The details to update of the shipping option." - * required: - * - requirements - * properties: - * name: - * description: "The name of the Shipping Option" - * type: string - * amount: - * description: >- - * The amount to charge for the Shipping Option. If the `price_type` of the shipping option is `calculated`, this amount will not actually be used. - * type: integer - * admin_only: - * description: >- - * If set to `true`, the shipping option can only be used when creating draft orders. - * type: boolean - * metadata: - * description: "An optional set of key-value pairs with additional information." - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * requirements: - * description: "The requirements that must be satisfied for the Shipping Option to be available." - * type: array - * items: - * type: object - * required: - * - type - * - amount - * properties: - * id: - * description: The ID of an existing requirement. If an ID is passed, the existing requirement's details are updated. Otherwise, a new requirement is created. - * type: string - * type: - * description: The type of the requirement - * type: string - * enum: - * - max_subtotal - * - min_subtotal - * amount: - * description: The amount to compare with. - * type: integer - * includes_tax: - * description: "Tax included in prices of shipping option" - * x-featureFlag: "tax_inclusive_pricing" - * type: boolean - */ -export class AdminPostShippingOptionsOptionReq { - @IsString() - @IsOptional() - name: string - - @IsNumber() - @IsOptional() - amount?: number - - @IsEnum(ShippingOptionPriceType, { - message: `Invalid price type, must be one of "flat_rate" or "calculated"`, - }) - @IsOptional() - price_type?: ShippingOptionPriceType - - @IsArray() - @ValidateNested({ each: true }) - @Type(() => OptionRequirement) - requirements: OptionRequirement[] - - @IsBoolean() - @IsOptional() - admin_only?: boolean - - @IsObject() - @IsOptional() - metadata?: Record - - @FeatureFlagDecorators(TaxInclusivePricingFeatureFlag.key, [ - IsOptional(), - IsBoolean(), - ]) - includes_tax?: boolean -} diff --git a/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/create-shipping-profile.js b/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/create-shipping-profile.js deleted file mode 100644 index 37c19ed827..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/create-shipping-profile.js +++ /dev/null @@ -1,35 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ShippingProfileServiceMock } from "../../../../../services/__mocks__/shipping-profile" - -describe("POST /admin/shipping-profiles", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/shipping-profiles", { - payload: { - name: "Test Profile", - type: "default", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service create", () => { - expect(ShippingProfileServiceMock.create).toHaveBeenCalledTimes(1) - expect(ShippingProfileServiceMock.create).toHaveBeenCalledWith({ - name: "Test Profile", - type: "default", - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/delete-shipping-profile.js b/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/delete-shipping-profile.js deleted file mode 100644 index 83fccd2fd0..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/delete-shipping-profile.js +++ /dev/null @@ -1,34 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ShippingOptionServiceMock } from "../../../../../services/__mocks__/shipping-option" - -describe("POST /admin/shipping-options", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/shipping-options/${IdMap.getId("validId")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service delete", () => { - expect(ShippingOptionServiceMock.delete).toHaveBeenCalledTimes(1) - expect(ShippingOptionServiceMock.delete).toHaveBeenCalledWith( - IdMap.getId("validId") - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/get-shipping-profile.js b/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/get-shipping-profile.js deleted file mode 100644 index 71ff42b8c8..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/get-shipping-profile.js +++ /dev/null @@ -1,50 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ShippingProfileServiceMock } from "../../../../../services/__mocks__/shipping-profile" - -const defaultFields = [ - "id", - "name", - "type", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -const defaultRelations = ["products.profiles", "shipping_options"] - -describe("GET /admin/shipping-profiles/:profile_id", () => { - describe("successful retrieval", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/admin/shipping-profiles/${IdMap.getId("validId")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve", () => { - expect(ShippingProfileServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(ShippingProfileServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("validId"), - { - select: defaultFields, - relations: defaultRelations, - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/list-shipping-profiles.js b/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/list-shipping-profiles.js deleted file mode 100644 index 7d65e88ed2..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/list-shipping-profiles.js +++ /dev/null @@ -1,28 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ShippingProfileServiceMock } from "../../../../../services/__mocks__/shipping-profile" - -describe("GET /admin/shipping-profiles", () => { - describe("successful retrieval", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/admin/shipping-profiles`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve", () => { - expect(ShippingProfileServiceMock.list).toHaveBeenCalledTimes(1) - expect(ShippingProfileServiceMock.list).toHaveBeenCalledWith() - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/update-shipping-profile.js b/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/update-shipping-profile.js deleted file mode 100644 index ae744b1e04..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-profiles/__tests__/update-shipping-profile.js +++ /dev/null @@ -1,40 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ShippingProfileServiceMock } from "../../../../../services/__mocks__/shipping-profile" - -describe("POST /admin/shipping-profile", () => { - describe("successful update", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/shipping-profiles/${IdMap.getId("validId")}`, - { - payload: { - name: "Test option", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service method", () => { - expect(ShippingProfileServiceMock.update).toHaveBeenCalledTimes(1) - expect(ShippingProfileServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("validId"), - { - name: "Test option", - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/shipping-profiles/create-shipping-profile.ts b/packages/medusa/src/api/routes/admin/shipping-profiles/create-shipping-profile.ts deleted file mode 100644 index 640f7dcc34..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-profiles/create-shipping-profile.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { IsEnum, IsObject, IsOptional, IsString } from "class-validator" -import { EntityManager } from "typeorm" -import { ShippingProfileType } from "../../../../models" -import { ShippingProfileService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/shipping-profiles - * operationId: "PostShippingProfiles" - * summary: "Create a Shipping Profile" - * description: "Create a Shipping Profile." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostShippingProfilesReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingProfiles.create({ - * name: "Large Products" - * }) - * .then(({ shipping_profile }) => { - * console.log(shipping_profile.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { ShippingProfileType } from "@medusajs/medusa" - * import { useAdminCreateShippingProfile } from "medusa-react" - * - * const CreateShippingProfile = () => { - * const createShippingProfile = useAdminCreateShippingProfile() - * // ... - * - * const handleCreate = ( - * name: string, - * type: ShippingProfileType - * ) => { - * createShippingProfile.mutate({ - * name, - * type - * }, { - * onSuccess: ({ shipping_profile }) => { - * console.log(shipping_profile.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateShippingProfile - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/shipping-profiles' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "Large Products" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Shipping Profiles - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminShippingProfilesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminPostShippingProfilesReq, req.body) - - const profileService: ShippingProfileService = req.scope.resolve( - "shippingProfileService" - ) - const manager: EntityManager = req.scope.resolve("manager") - const data = await manager.transaction(async (transactionManager) => { - return await profileService - .withTransaction(transactionManager) - .create(validated) - }) - - res.status(200).json({ shipping_profile: data }) -} - -/** - * @schema AdminPostShippingProfilesReq - * type: object - * description: "The details of the shipping profile to create." - * required: - * - name - * - type - * properties: - * name: - * description: The name of the Shipping Profile - * type: string - * type: - * description: The type of the Shipping Profile - * type: string - * enum: [default, gift_card, custom] - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostShippingProfilesReq { - @IsString() - name: string - - @IsEnum(ShippingProfileType, { - message: "type must be one of 'default', 'custom', 'gift_card'", - }) - type: ShippingProfileType - - @IsOptional() - @IsObject() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/shipping-profiles/delete-shipping-profile.ts b/packages/medusa/src/api/routes/admin/shipping-profiles/delete-shipping-profile.ts deleted file mode 100644 index f23fdf0db0..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-profiles/delete-shipping-profile.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { EntityManager } from "typeorm" -import { ShippingProfileService } from "../../../../services" - -/** - * @oas [delete] /admin/shipping-profiles/{id} - * operationId: "DeleteShippingProfilesProfile" - * summary: "Delete a Shipping Profile" - * description: "Delete a Shipping Profile. Associated shipping options are deleted as well." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Shipping Profile. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingProfiles.delete(profileId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteShippingProfile } from "medusa-react" - * - * type Props = { - * shippingProfileId: string - * } - * - * const ShippingProfile = ({ shippingProfileId }: Props) => { - * const deleteShippingProfile = useAdminDeleteShippingProfile( - * shippingProfileId - * ) - * // ... - * - * const handleDelete = () => { - * deleteShippingProfile.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default ShippingProfile - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/shipping-profiles/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Shipping Profiles - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteShippingProfileRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { profile_id } = req.params - const profileService: ShippingProfileService = req.scope.resolve( - "shippingProfileService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await profileService - .withTransaction(transactionManager) - .delete(profile_id) - }) - - res.status(200).json({ - id: profile_id, - object: "shipping_profile", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/shipping-profiles/get-shipping-profile.ts b/packages/medusa/src/api/routes/admin/shipping-profiles/get-shipping-profile.ts deleted file mode 100644 index b2a7f08788..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-profiles/get-shipping-profile.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { - defaultAdminShippingProfilesFields, - defaultAdminShippingProfilesRelations, -} from "." - -import { ShippingProfileService } from "../../../../services" - -/** - * @oas [get] /admin/shipping-profiles/{id} - * operationId: "GetShippingProfilesProfile" - * summary: "Get a Shipping Profile" - * description: "Retrieve a Shipping Profile's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Shipping Profile. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingProfiles.retrieve(profileId) - * .then(({ shipping_profile }) => { - * console.log(shipping_profile.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminShippingProfile } from "medusa-react" - * - * type Props = { - * shippingProfileId: string - * } - * - * const ShippingProfile = ({ shippingProfileId }: Props) => { - * const { - * shipping_profile, - * isLoading - * } = useAdminShippingProfile( - * shippingProfileId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {shipping_profile && ( - * {shipping_profile.name} - * )} - *
- * ) - * } - * - * export default ShippingProfile - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/shipping-profiles/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Shipping Profiles - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminShippingProfilesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { profile_id } = req.params - const profileService: ShippingProfileService = req.scope.resolve( - "shippingProfileService" - ) - - const profile = await profileService.retrieve(profile_id, { - select: defaultAdminShippingProfilesFields, - relations: defaultAdminShippingProfilesRelations, - }) - - res.status(200).json({ shipping_profile: profile }) -} diff --git a/packages/medusa/src/api/routes/admin/shipping-profiles/index.ts b/packages/medusa/src/api/routes/admin/shipping-profiles/index.ts deleted file mode 100644 index 6c7fd99636..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-profiles/index.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Router } from "express" -import "reflect-metadata" -import { ShippingProfile } from "../../../.." -import { DeleteResponse } from "../../../../types/common" -import middlewares from "../../../middlewares" - -const route = Router() - -export default (app) => { - app.use("/shipping-profiles", route) - - route.get("/", middlewares.wrap(require("./list-shipping-profiles").default)) - route.post( - "/", - middlewares.wrap(require("./create-shipping-profile").default) - ) - - route.get( - "/:profile_id", - middlewares.wrap(require("./get-shipping-profile").default) - ) - route.post( - "/:profile_id", - middlewares.wrap(require("./update-shipping-profile").default) - ) - route.delete( - "/:profile_id", - middlewares.wrap(require("./delete-shipping-profile").default) - ) - - return app -} - -export const defaultAdminShippingProfilesFields: (keyof ShippingProfile)[] = [ - "id", - "name", - "type", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -export const defaultAdminShippingProfilesRelations: string[] = [ - "products.profiles", - "shipping_options", -] - -/** - * @schema AdminDeleteShippingProfileRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Shipping Profile. - * object: - * type: string - * description: The type of the object that was deleted. - * default: shipping_profile - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminDeleteShippingProfileRes = DeleteResponse - -/** - * @schema AdminShippingProfilesRes - * type: object - * description: "The shipping profile's details." - * x-expanded-relations: - * field: shipping_profile - * relations: - * - products - * - shipping_options - * required: - * - shipping_profile - * properties: - * shipping_profile: - * description: Shipping profile details. - * $ref: "#/components/schemas/ShippingProfile" - */ -export type AdminShippingProfilesRes = { - shipping_profile: ShippingProfile -} - -/** - * @schema AdminShippingProfilesListRes - * type: object - * description: "The list of shipping profiles." - * required: - * - shipping_profiles - * properties: - * shipping_profiles: - * type: array - * description: An array of shipping profiles details. - * items: - * $ref: "#/components/schemas/ShippingProfile" - */ -export type AdminShippingProfilesListRes = { - shipping_profiles: ShippingProfile[] -} - -export * from "./create-shipping-profile" -export * from "./delete-shipping-profile" -export * from "./update-shipping-profile" diff --git a/packages/medusa/src/api/routes/admin/shipping-profiles/list-shipping-profiles.ts b/packages/medusa/src/api/routes/admin/shipping-profiles/list-shipping-profiles.ts deleted file mode 100644 index ca6229b035..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-profiles/list-shipping-profiles.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { ShippingProfileService } from "../../../../services" - -/** - * @oas [get] /admin/shipping-profiles - * operationId: "GetShippingProfiles" - * summary: "List Shipping Profiles" - * description: "Retrieve a list of Shipping Profiles." - * x-authenticated: true - * x-codegen: - * method: list - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingProfiles.list() - * .then(({ shipping_profiles }) => { - * console.log(shipping_profiles.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminShippingProfiles } from "medusa-react" - * - * const ShippingProfiles = () => { - * const { - * shipping_profiles, - * isLoading - * } = useAdminShippingProfiles() - * - * return ( - *
- * {isLoading && Loading...} - * {shipping_profiles && !shipping_profiles.length && ( - * No Shipping Profiles - * )} - * {shipping_profiles && shipping_profiles.length > 0 && ( - *
    - * {shipping_profiles.map((profile) => ( - *
  • {profile.name}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ShippingProfiles - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/shipping-profiles' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Shipping Profiles - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminShippingProfilesListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const profileService: ShippingProfileService = req.scope.resolve( - "shippingProfileService" - ) - - const data = await profileService.list() - - res.status(200).json({ shipping_profiles: data }) -} diff --git a/packages/medusa/src/api/routes/admin/shipping-profiles/update-shipping-profile.ts b/packages/medusa/src/api/routes/admin/shipping-profiles/update-shipping-profile.ts deleted file mode 100644 index 7fa58fccd4..0000000000 --- a/packages/medusa/src/api/routes/admin/shipping-profiles/update-shipping-profile.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { - IsArray, - IsEnum, - IsObject, - IsOptional, - IsString, -} from "class-validator" - -import { EntityManager } from "typeorm" -import { ShippingProfileType } from "../../../../models" -import { ShippingProfileService } from "../../../../services" -import { validator } from "../../../../utils/validator" -import { - defaultAdminShippingProfilesFields, - defaultAdminShippingProfilesRelations, -} from "." - -/** - * @oas [post] /admin/shipping-profiles/{id} - * operationId: "PostShippingProfilesProfile" - * summary: "Update a Shipping Profile" - * description: "Update a Shipping Profile's details." - * parameters: - * - (path) id=* {string} The ID of the Shipping Profile. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostShippingProfilesProfileReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.shippingProfiles.update(shippingProfileId, { - * name: 'Large Products' - * }) - * .then(({ shipping_profile }) => { - * console.log(shipping_profile.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { ShippingProfileType } from "@medusajs/medusa" - * import { useAdminUpdateShippingProfile } from "medusa-react" - * - * type Props = { - * shippingProfileId: string - * } - * - * const ShippingProfile = ({ shippingProfileId }: Props) => { - * const updateShippingProfile = useAdminUpdateShippingProfile( - * shippingProfileId - * ) - * // ... - * - * const handleUpdate = ( - * name: string, - * type: ShippingProfileType - * ) => { - * updateShippingProfile.mutate({ - * name, - * type - * }, { - * onSuccess: ({ shipping_profile }) => { - * console.log(shipping_profile.name) - * } - * }) - * } - * - * // ... - * } - * - * export default ShippingProfile - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/shipping-profiles/{id} \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "Large Products" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Shipping Profiles - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminShippingProfilesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { profile_id } = req.params - - const validated = await validator( - AdminPostShippingProfilesProfileReq, - req.body - ) - - const profileService: ShippingProfileService = req.scope.resolve( - "shippingProfileService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await profileService - .withTransaction(transactionManager) - .update(profile_id, validated) - }) - - const data = await profileService.retrieve(profile_id, { - select: defaultAdminShippingProfilesFields, - relations: defaultAdminShippingProfilesRelations, - }) - - res.status(200).json({ shipping_profile: data }) -} - -/** - * @schema AdminPostShippingProfilesProfileReq - * type: object - * description: "The detail to update of the shipping profile." - * properties: - * name: - * description: The name of the Shipping Profile - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * type: - * description: The type of the Shipping Profile - * type: string - * enum: [default, gift_card, custom] - * products: - * description: product IDs to associate with the Shipping Profile - * type: array - * shipping_options: - * description: Shipping option IDs to associate with the Shipping Profile - * type: array - */ -export class AdminPostShippingProfilesProfileReq { - @IsString() - @IsOptional() - name?: string - - @IsOptional() - @IsObject() - metadata?: Record - - @IsOptional() - @IsEnum(ShippingProfileType, { - message: "type must be one of 'default', 'custom', 'gift_card'", - }) - type?: ShippingProfileType - - @IsOptional() - @IsArray() - @IsString({ each: true }) - products?: string[] - - @IsOptional() - @IsArray() - @IsString({ each: true }) - shipping_options?: string[] -} diff --git a/packages/medusa/src/api/routes/admin/stock-locations/create-stock-location.ts b/packages/medusa/src/api/routes/admin/stock-locations/create-stock-location.ts deleted file mode 100644 index 948db35bb3..0000000000 --- a/packages/medusa/src/api/routes/admin/stock-locations/create-stock-location.ts +++ /dev/null @@ -1,236 +0,0 @@ -import { - IsNotEmpty, - IsObject, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { Request, Response } from "express" -import { Transform, Type } from "class-transformer" - -import { FindParams } from "../../../../types/common" -import { IStockLocationService } from "@medusajs/types" - -/** - * @oas [post] /admin/stock-locations - * operationId: "PostStockLocations" - * summary: "Create a Stock Location" - * description: "Create a Stock Location." - * x-authenticated: true - * parameters: - * - (query) expand {string} Comma-separated relations that should be expanded in the returned stock location. - * - (query) fields {string} Comma-separated fields that should be included in the returned stock location. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostStockLocationsReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.stockLocations.create({ - * name: "Main Warehouse", - * }) - * .then(({ stock_location }) => { - * console.log(stock_location.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateStockLocation } from "medusa-react" - * - * const CreateStockLocation = () => { - * const createStockLocation = useAdminCreateStockLocation() - * // ... - * - * const handleCreate = (name: string) => { - * createStockLocation.mutate({ - * name, - * }, { - * onSuccess: ({ stock_location }) => { - * console.log(stock_location.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateStockLocation - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/stock-locations' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "App" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Stock Locations - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminStockLocationsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const locationService: IStockLocationService = req.scope.resolve( - "stockLocationService" - ) - - const createdStockLocation = await locationService.create( - req.validatedBody as AdminPostStockLocationsReq - ) - - const stockLocation = await locationService.retrieve( - createdStockLocation.id, - req.retrieveConfig - ) - - res.status(200).json({ stock_location: stockLocation }) -} - -/** - * @schema AdminPostStockLocationsReqAddress - * type: object - * required: - * - address_1 - * - country_code - * properties: - * address_1: - * type: string - * description: Stock location address - * example: 35, Jhon Doe Ave - * address_2: - * type: string - * description: Stock location address' complement - * example: apartment 4432 - * company: - * type: string - * description: Stock location address' company - * city: - * type: string - * description: Stock location address' city - * example: Mexico city - * country_code: - * description: "The two character ISO code for the country." - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements - * description: See a list of codes. - * phone: - * type: string - * description: Stock location address' phone number - * example: +1 555 61646 - * postal_code: - * type: string - * description: Stock location address' postal code - * example: HD3-1G8 - * province: - * type: string - * description: Stock location address' province - * example: Sinaloa - */ -class StockLocationAddress { - @IsString() - address_1: string - - @IsOptional() - @IsString() - address_2?: string - - @IsOptional() - @IsString() - company?: string - - @IsOptional() - @IsString() - city?: string - - @IsString() - country_code: string - - @IsOptional() - @IsString() - phone?: string - - @IsOptional() - @IsString() - postal_code?: string - - @IsOptional() - @IsString() - province?: string -} - -/** - * @schema AdminPostStockLocationsReq - * type: object - * description: "The details of the stock location to create." - * required: - * - name - * properties: - * name: - * description: the name of the stock location - * type: string - * address_id: - * description: the ID of an existing stock location address to associate with the stock location. Only required if `address` is not provided. - * type: string - * metadata: - * type: object - * description: An optional key-value map with additional details - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * address: - * description: A new stock location address to create and associate with the stock location. Only required if `address_id` is not provided. - * $ref: "#/components/schemas/StockLocationAddressInput" - */ -export class AdminPostStockLocationsReq { - @IsString() - @IsNotEmpty() - @Transform(({ value }: { value: string }) => value?.trim()) - name: string - - @IsOptional() - @ValidateNested() - @Type(() => StockLocationAddress) - address?: StockLocationAddress - - @IsOptional() - @IsString() - address_id?: string - - @IsObject() - @IsOptional() - metadata?: Record -} - -export class AdminPostStockLocationsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/stock-locations/delete-stock-location.ts b/packages/medusa/src/api/routes/admin/stock-locations/delete-stock-location.ts deleted file mode 100644 index 20078c5701..0000000000 --- a/packages/medusa/src/api/routes/admin/stock-locations/delete-stock-location.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { IInventoryService, IStockLocationService } from "@medusajs/types" -import { promiseAll } from "@medusajs/utils" -import { EntityManager } from "typeorm" -import { SalesChannelLocationService } from "../../../../services" - -/** - * @oas [delete] /admin/stock-locations/{id} - * operationId: "DeleteStockLocationsStockLocation" - * summary: "Delete a Stock Location" - * description: "Delete a Stock Location." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Stock Location. - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.stockLocations.delete(stockLocationId) - * .then(({ id, object, deleted }) => { - * console.log(id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteStockLocation } from "medusa-react" - * - * type Props = { - * stockLocationId: string - * } - * - * const StockLocation = ({ stockLocationId }: Props) => { - * const deleteLocation = useAdminDeleteStockLocation( - * stockLocationId - * ) - * // ... - * - * const handleDelete = () => { - * deleteLocation.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * } - * - * export default StockLocation - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/stock-locations/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Stock Locations - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminStockLocationsDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - */ -export default async (req, res) => { - const { id } = req.params - - const stockLocationService: IStockLocationService = req.scope.resolve( - "stockLocationService" - ) - - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - - const salesChannelLocationService: SalesChannelLocationService = - req.scope.resolve("salesChannelLocationService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - await salesChannelLocationService - .withTransaction(transactionManager) - .removeLocation(id) - - await stockLocationService.delete(id) - - if (inventoryService) { - await promiseAll([ - inventoryService.deleteInventoryItemLevelByLocationId(id), - inventoryService.deleteReservationItemByLocationId(id), - ]) - } - }) - - res.status(200).send({ - id, - object: "stock_location", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/stock-locations/get-stock-location.ts b/packages/medusa/src/api/routes/admin/stock-locations/get-stock-location.ts deleted file mode 100644 index 032a3d975c..0000000000 --- a/packages/medusa/src/api/routes/admin/stock-locations/get-stock-location.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { IStockLocationService } from "@medusajs/types" -import { Request, Response } from "express" -import { - SalesChannelLocationService, - SalesChannelService, -} from "../../../../services" -import { FindParams } from "../../../../types/common" -import { joinSalesChannels } from "./utils/join-sales-channels" - -/** - * @oas [get] /admin/stock-locations/{id} - * operationId: "GetStockLocationsStockLocation" - * summary: "Get a Stock Location" - * description: "Retrieve a Stock Location's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Stock Location. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned stock location. - * - (query) fields {string} Comma-separated fields that should be included in the returned stock location. - * x-codegen: - * method: retrieve - * queryParams: AdminGetStockLocationsLocationParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.stockLocations.retrieve(stockLocationId) - * .then(({ stock_location }) => { - * console.log(stock_location.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminStockLocation } from "medusa-react" - * - * type Props = { - * stockLocationId: string - * } - * - * const StockLocation = ({ stockLocationId }: Props) => { - * const { - * stock_location, - * isLoading - * } = useAdminStockLocation(stockLocationId) - * - * return ( - *
- * {isLoading && Loading...} - * {stock_location && ( - * {stock_location.name} - * )} - *
- * ) - * } - * - * export default StockLocation - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/stock-locations/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Stock Locations - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminStockLocationsRes" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const locationService: IStockLocationService = req.scope.resolve( - "stockLocationService" - ) - const channelLocationService: SalesChannelLocationService = req.scope.resolve( - "salesChannelLocationService" - ) - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - - const { retrieveConfig } = req - - const includeSalesChannels = - !!retrieveConfig.relations?.includes("sales_channels") - - if (includeSalesChannels) { - retrieveConfig.relations = retrieveConfig.relations?.filter( - (r) => r !== "sales_channels" - ) - } - - let stockLocation = await locationService.retrieve(id, retrieveConfig) - - if (includeSalesChannels) { - const [location] = await joinSalesChannels( - [stockLocation], - channelLocationService, - salesChannelService - ) - stockLocation = location - } - - res.status(200).json({ stock_location: stockLocation }) -} - -export class AdminGetStockLocationsLocationParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/stock-locations/index.ts b/packages/medusa/src/api/routes/admin/stock-locations/index.ts deleted file mode 100644 index c31c802811..0000000000 --- a/packages/medusa/src/api/routes/admin/stock-locations/index.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { - DeleteResponse, - PaginatedResponse, - StockLocationTypes, -} from "@medusajs/types" -import { Router } from "express" -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" -import { checkRegisteredModules } from "../../../middlewares/check-registered-modules" -import { - AdminPostStockLocationsParams, - AdminPostStockLocationsReq, -} from "./create-stock-location" -import { AdminGetStockLocationsLocationParams } from "./get-stock-location" -import { AdminGetStockLocationsParams } from "./list-stock-locations" -import { - AdminPostStockLocationsLocationParams, - AdminPostStockLocationsLocationReq, -} from "./update-stock-location" - -const route = Router() - -export default (app) => { - app.use( - "/stock-locations", - checkRegisteredModules({ - stockLocationService: - "Stock Locations are not enabled. Please add a Stock Location module to enable this functionality.", - }), - route - ) - - route.get( - "/", - transformQuery(AdminGetStockLocationsParams, { - defaultFields: defaultAdminStockLocationFields, - defaultRelations: defaultAdminStockLocationRelations, - isList: true, - }), - middlewares.wrap(require("./list-stock-locations").default) - ) - route.post( - "/", - transformQuery(AdminPostStockLocationsParams, { - defaultFields: defaultAdminStockLocationFields, - defaultRelations: defaultAdminStockLocationRelations, - isList: false, - }), - transformBody(AdminPostStockLocationsReq), - middlewares.wrap(require("./create-stock-location").default) - ) - - route.get( - "/:id", - transformQuery(AdminGetStockLocationsLocationParams, { - defaultFields: defaultAdminStockLocationFields, - defaultRelations: defaultAdminStockLocationRelations, - isList: false, - }), - middlewares.wrap(require("./get-stock-location").default) - ) - - route.post( - "/:id", - transformQuery(AdminPostStockLocationsLocationParams, { - defaultFields: defaultAdminStockLocationFields, - defaultRelations: defaultAdminStockLocationRelations, - isList: false, - }), - transformBody(AdminPostStockLocationsLocationReq), - middlewares.wrap(require("./update-stock-location").default) - ) - - route.delete( - "/:id", - middlewares.wrap(require("./delete-stock-location").default) - ) - - return app -} - -// eslint-disable-next-line max-len -export const defaultAdminStockLocationFields: (keyof StockLocationTypes.StockLocationDTO)[] = - ["id", "name", "address_id", "metadata", "created_at", "updated_at"] - -export const defaultAdminStockLocationRelations = [] - -/** - * @schema AdminStockLocationsDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Stock Location. - * object: - * type: string - * description: The type of the object that was deleted. - * default: stock_location - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminStockLocationsDeleteRes = DeleteResponse - -/** - * @schema AdminStockLocationsRes - * type: object - * description: "The stock location's details." - * required: - * - stock_location - * properties: - * stock_location: - * description: "Stock location details." - * $ref: "#/components/schemas/StockLocationExpandedDTO" - */ -export type AdminStockLocationsRes = { - stock_location: StockLocationTypes.StockLocationExpandedDTO -} - -/** - * @schema AdminStockLocationsListRes - * type: object - * description: "The list of stock locations with pagination fields." - * required: - * - stock_locations - * - count - * - offset - * - limit - * properties: - * stock_locations: - * type: array - * description: "The list of stock locations." - * items: - * $ref: "#/components/schemas/StockLocationExpandedDTO" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of stock locations skipped when retrieving the stock locations. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminStockLocationsListRes = PaginatedResponse & { - stock_locations: StockLocationTypes.StockLocationExpandedDTO[] -} - -export * from "./create-stock-location" -export * from "./get-stock-location" -export * from "./list-stock-locations" -export * from "./update-stock-location" diff --git a/packages/medusa/src/api/routes/admin/stock-locations/list-stock-locations.ts b/packages/medusa/src/api/routes/admin/stock-locations/list-stock-locations.ts deleted file mode 100644 index 9f36dd5eed..0000000000 --- a/packages/medusa/src/api/routes/admin/stock-locations/list-stock-locations.ts +++ /dev/null @@ -1,275 +0,0 @@ -import { IStockLocationService } from "@medusajs/types" -import { IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" -import { - SalesChannelLocationService, - SalesChannelService, -} from "../../../../services" -import { extendedFindParamsMixin } from "../../../../types/common" -import { IsType } from "../../../../utils/validators/is-type" -import { joinSalesChannels } from "./utils/join-sales-channels" - -/** - * @oas [get] /admin/stock-locations - * operationId: "GetStockLocations" - * summary: "List Stock Locations" - * description: "Retrieve a list of stock locations. The stock locations can be filtered by fields such as `name` or `created_at`. The stock locations can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) id {string} Filter by ID. - * - (query) name {string} Filter by name. - * - (query) order {string} A stock-location field to sort-order the retrieved stock locations by. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: deleted_at - * description: Filter by a deletion date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - (query) offset=0 {integer} The number of stock locations to skip when retrieving the stock locations. - * - (query) limit=20 {integer} Limit the number of stock locations returned. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned stock locations. - * - (query) fields {string} Comma-separated fields that should be included in the returned stock locations. - * x-codegen: - * method: list - * queryParams: AdminGetStockLocationsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.stockLocations.list() - * .then(({ stock_locations, limit, offset, count }) => { - * console.log(stock_locations.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminStockLocations } from "medusa-react" - * - * function StockLocations() { - * const { - * stock_locations, - * isLoading - * } = useAdminStockLocations() - * - * return ( - *
- * {isLoading && Loading...} - * {stock_locations && !stock_locations.length && ( - * No Locations - * )} - * {stock_locations && stock_locations.length > 0 && ( - *
    - * {stock_locations.map( - * (location) => ( - *
  • {location.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default StockLocations - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/stock-locations' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Stock Locations - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminStockLocationsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const stockLocationService: IStockLocationService = req.scope.resolve( - "stockLocationService" - ) - const channelLocationService: SalesChannelLocationService = req.scope.resolve( - "salesChannelLocationService" - ) - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - - const { filterableFields, listConfig } = req - const { skip, take } = listConfig - - const filterOnSalesChannel = !!filterableFields.sales_channel_id - - const includeSalesChannels = - !!listConfig.relations?.includes("sales_channels") - - if (includeSalesChannels) { - listConfig.relations = listConfig.relations?.filter( - (r) => r !== "sales_channels" - ) - } - - if (filterOnSalesChannel) { - const ids: string[] = Array.isArray(filterableFields.sales_channel_id) - ? filterableFields.sales_channel_id - : [filterableFields.sales_channel_id] - - delete filterableFields.sales_channel_id - - const locationIds = await channelLocationService.listLocationIds(ids) - - filterableFields.id = [...new Set(locationIds.flat())] - } - - let [locations, count] = await stockLocationService.listAndCount( - filterableFields, - listConfig - ) - - if (includeSalesChannels) { - locations = await joinSalesChannels( - locations, - channelLocationService, - salesChannelService - ) - } - - res.status(200).json({ - stock_locations: locations, - count, - offset: skip, - limit: take, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved stock locations. - */ -export class AdminGetStockLocationsParams extends extendedFindParamsMixin({ - limit: 20, - offset: 0, -}) { - /** - * Search term to search stock location names. - */ - @IsString() - @IsOptional() - q?: string - - /** - * IDs to filter stock locations by. - */ - @IsOptional() - @IsType([String, [String]]) - id?: string | string[] - - /** - * Names to filter stock locations by. - */ - @IsOptional() - @IsType([String, [String]]) - name?: string | string[] - - /** - * Filter stock locations by the ID of their associated addresses. - */ - @IsOptional() - @IsType([String, [String]]) - address_id?: string | string[] - - /** - * Filter stock locations by the ID of their associated sales channels. - */ - @IsOptional() - @IsType([String, [String]]) - sales_channel_id?: string | string[] - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string -} diff --git a/packages/medusa/src/api/routes/admin/stock-locations/update-stock-location.ts b/packages/medusa/src/api/routes/admin/stock-locations/update-stock-location.ts deleted file mode 100644 index efad1a6a65..0000000000 --- a/packages/medusa/src/api/routes/admin/stock-locations/update-stock-location.ts +++ /dev/null @@ -1,219 +0,0 @@ -import { IStockLocationService } from "@medusajs/types" -import { Type } from "class-transformer" -import { IsObject, IsOptional, IsString, ValidateNested } from "class-validator" -import { Request, Response } from "express" -import { FindParams } from "../../../../types/common" - -/** - * @oas [post] /admin/stock-locations/{id} - * operationId: "PostStockLocationsStockLocation" - * summary: "Update a Stock Location" - * description: "Update a Stock Location's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Stock Location. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned stock location. - * - (query) fields {string} Comma-separated fields that should be included in the returned stock location. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostStockLocationsLocationReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.stockLocations.update(stockLocationId, { - * name: 'Main Warehouse' - * }) - * .then(({ stock_location }) => { - * console.log(stock_location.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateStockLocation } from "medusa-react" - * - * type Props = { - * stockLocationId: string - * } - * - * const StockLocation = ({ stockLocationId }: Props) => { - * const updateLocation = useAdminUpdateStockLocation( - * stockLocationId - * ) - * // ... - * - * const handleUpdate = ( - * name: string - * ) => { - * updateLocation.mutate({ - * name - * }, { - * onSuccess: ({ stock_location }) => { - * console.log(stock_location.name) - * } - * }) - * } - * } - * - * export default StockLocation - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/stock-locations/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "Main Warehouse" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Stock Locations - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminStockLocationsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const locationService: IStockLocationService = req.scope.resolve( - "stockLocationService" - ) - - await locationService.update( - id, - req.validatedBody as AdminPostStockLocationsLocationReq - ) - - const stockLocation = await locationService.retrieve(id, req.retrieveConfig) - - res.status(200).json({ stock_location: stockLocation }) -} - -/** - * The attributes of a stock location address to create or update. - */ -class StockLocationAddress { - /** - * First line address. - */ - @IsString() - address_1: string - - /** - * Second line address. - */ - @IsOptional() - @IsString() - address_2?: string - - /** - * Company. - */ - @IsOptional() - @IsString() - company?: string - - /** - * City. - */ - @IsOptional() - @IsString() - city?: string - - /** - * Country code. - */ - @IsString() - country_code: string - - /** - * Phone. - */ - @IsOptional() - @IsString() - phone?: string - - /** - * Postal code. - */ - @IsOptional() - @IsString() - postal_code?: string - - /** - * Province. - */ - @IsOptional() - @IsString() - province?: string -} - -/** - * @schema AdminPostStockLocationsLocationReq - * type: object - * description: "The details to update of the stock location." - * properties: - * name: - * description: the name of the stock location - * type: string - * address_id: - * description: the stock location address ID - * type: string - * metadata: - * type: object - * description: An optional key-value map with additional details - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * address: - * description: The data of an associated address to create or update. - * $ref: "#/components/schemas/StockLocationAddressInput" - */ -export class AdminPostStockLocationsLocationReq { - @IsOptional() - @IsString() - name?: string - - @IsOptional() - @ValidateNested() - @Type(() => StockLocationAddress) - address?: StockLocationAddress - - @IsOptional() - @IsString() - address_id?: string - - @IsObject() - @IsOptional() - metadata?: Record -} - -export class AdminPostStockLocationsLocationParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/stock-locations/utils/join-sales-channels.ts b/packages/medusa/src/api/routes/admin/stock-locations/utils/join-sales-channels.ts deleted file mode 100644 index 5936abc1ca..0000000000 --- a/packages/medusa/src/api/routes/admin/stock-locations/utils/join-sales-channels.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { StockLocationDTO, StockLocationExpandedDTO } from "@medusajs/types" -import { promiseAll } from "@medusajs/utils" -import { - SalesChannelLocationService, - SalesChannelService, -} from "../../../../../services" - -const joinSalesChannels = async ( - locations: StockLocationDTO[], - channelLocationService: SalesChannelLocationService, - salesChannelService: SalesChannelService -): Promise => { - return await promiseAll( - locations.map(async (location: StockLocationExpandedDTO) => { - const salesChannelIds = await channelLocationService.listSalesChannelIds( - location.id - ) - const [salesChannels] = await salesChannelService.listAndCount( - { - id: salesChannelIds, - }, - {} - ) - - location.sales_channels = salesChannels - - return location - }) - ) -} - -export { joinSalesChannels } diff --git a/packages/medusa/src/api/routes/admin/store/__tests__/add-currency.js b/packages/medusa/src/api/routes/admin/store/__tests__/add-currency.js deleted file mode 100644 index 328545be47..0000000000 --- a/packages/medusa/src/api/routes/admin/store/__tests__/add-currency.js +++ /dev/null @@ -1,28 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { StoreServiceMock } from "../../../../../services/__mocks__/store" - -describe("POST /admin/store/currencies/:currency_code", () => { - describe("successful addition", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/admin/store/currencies/dkk`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve", () => { - expect(StoreServiceMock.addCurrency).toHaveBeenCalledTimes(1) - expect(StoreServiceMock.addCurrency).toHaveBeenCalledWith("dkk") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/store/__tests__/get-store.js b/packages/medusa/src/api/routes/admin/store/__tests__/get-store.js deleted file mode 100644 index a456a243c7..0000000000 --- a/packages/medusa/src/api/routes/admin/store/__tests__/get-store.js +++ /dev/null @@ -1,30 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { StoreServiceMock } from "../../../../../services/__mocks__/store" - -describe("GET /admin/store", () => { - describe("successful addition", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/admin/store`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve", () => { - expect(StoreServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(StoreServiceMock.retrieve).toHaveBeenCalledWith({ - relations: ["currencies", "default_currency", "default_sales_channel"], - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/store/__tests__/remove-currency.js b/packages/medusa/src/api/routes/admin/store/__tests__/remove-currency.js deleted file mode 100644 index bdb606fc3c..0000000000 --- a/packages/medusa/src/api/routes/admin/store/__tests__/remove-currency.js +++ /dev/null @@ -1,28 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { StoreServiceMock } from "../../../../../services/__mocks__/store" - -describe("DELETE /admin/store/currencies/:currency_code", () => { - describe("successful addition", () => { - let subject - - beforeAll(async () => { - subject = await request("DELETE", `/admin/store/currencies/dkk`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve", () => { - expect(StoreServiceMock.removeCurrency).toHaveBeenCalledTimes(1) - expect(StoreServiceMock.removeCurrency).toHaveBeenCalledWith("dkk") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/store/__tests__/update-store.js b/packages/medusa/src/api/routes/admin/store/__tests__/update-store.js deleted file mode 100644 index de8e1511e5..0000000000 --- a/packages/medusa/src/api/routes/admin/store/__tests__/update-store.js +++ /dev/null @@ -1,89 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { StoreServiceMock } from "../../../../../services/__mocks__/store" - -describe("POST /admin/store", () => { - describe("successful creation", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("POST", "/admin/store", { - payload: { - name: "New Name", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service update", () => { - expect(StoreServiceMock.update).toHaveBeenCalledTimes(1) - expect(StoreServiceMock.update).toHaveBeenCalledWith({ - name: "New Name", - }) - }) - }) - - describe("successful creation", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("POST", "/admin/store", { - payload: { - currencies: ["DKK", "USD"], - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service update", () => { - expect(StoreServiceMock.update).toHaveBeenCalledTimes(1) - expect(StoreServiceMock.update).toHaveBeenCalledWith({ - currencies: ["DKK", "USD"], - }) - }) - }) - - describe("throws when currencies is not an array", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("POST", "/admin/store", { - payload: { - currencies: "DKK", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("throws a descriptive error", () => { - expect(subject.body.message).toEqual("currencies must be an array") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/store/add-currency.ts b/packages/medusa/src/api/routes/admin/store/add-currency.ts deleted file mode 100644 index f900fde794..0000000000 --- a/packages/medusa/src/api/routes/admin/store/add-currency.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { StoreService } from "../../../../services" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/store/currencies/{code} - * operationId: "PostStoreCurrenciesCode" - * summary: "Add a Currency Code" - * description: "Add a Currency Code to the available currencies in a store. This does not create new currencies, as currencies are defined within the Medusa backend. - * To create a currency, you can create a migration that inserts the currency into the database." - * x-authenticated: true - * parameters: - * - in: path - * name: code - * required: true - * description: The 3 character ISO currency code. - * schema: - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * x-codegen: - * method: addCurrency - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.store.addCurrency("eur") - * .then(({ store }) => { - * console.log(store.currencies); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminAddStoreCurrency } from "medusa-react" - * - * const Store = () => { - * const addCurrency = useAdminAddStoreCurrency() - * // ... - * - * const handleAdd = (code: string) => { - * addCurrency.mutate(code, { - * onSuccess: ({ store }) => { - * console.log(store.currencies) - * } - * }) - * } - * - * // ... - * } - * - * export default Store - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/store/currencies/{currency_code}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Store - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminStoresRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { currency_code } = req.params - - const storeService: StoreService = req.scope.resolve("storeService") - const manager: EntityManager = req.scope.resolve("manager") - const data = await manager.transaction(async (transactionManager) => { - return await storeService - .withTransaction(transactionManager) - .addCurrency(currency_code) - }) - - res.status(200).json({ store: data }) -} diff --git a/packages/medusa/src/api/routes/admin/store/get-store.ts b/packages/medusa/src/api/routes/admin/store/get-store.ts deleted file mode 100644 index 98b48cd04e..0000000000 --- a/packages/medusa/src/api/routes/admin/store/get-store.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { defaultRelationsExtended } from "." -import { - FulfillmentProviderService, - PaymentProviderService, - StoreService, -} from "../../../../services" -import { ExtendedStoreDTO } from "../../../../types/store" -import { MedusaModule } from "@medusajs/modules-sdk" - -/** - * @oas [get] /admin/store - * operationId: "GetStore" - * summary: "Get Store details" - * description: "Retrieve the Store's details." - * x-authenticated: true - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.store.retrieve() - * .then(({ store }) => { - * console.log(store.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminStore } from "medusa-react" - * - * const Store = () => { - * const { - * store, - * isLoading - * } = useAdminStore() - * - * return ( - *
- * {isLoading && Loading...} - * {store && {store.name}} - *
- * ) - * } - * - * export default Store - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/store' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Store - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminExtendedStoresRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const storeService: StoreService = req.scope.resolve("storeService") - - const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter") - - const paymentProviderService: PaymentProviderService = req.scope.resolve( - "paymentProviderService" - ) - const fulfillmentProviderService: FulfillmentProviderService = - req.scope.resolve("fulfillmentProviderService") - - const relations = [...defaultRelationsExtended] - if (featureFlagRouter.isFeatureEnabled("sales_channels")) { - relations.push("default_sales_channel") - } - - const data = (await storeService.retrieve({ - relations, - })) as ExtendedStoreDTO - - data.feature_flags = featureFlagRouter.listFlags() - data.modules = MedusaModule.getLoadedModules() - .map((loadedModule) => { - return Object.entries(loadedModule).map(([key, service]) => { - return { - module: key, - resolution: service.__definition.defaultPackage, - } - }) - }) - .flat() - - const paymentProviders = await paymentProviderService.list() - const fulfillmentProviders = await fulfillmentProviderService.list() - - data.payment_providers = paymentProviders - data.fulfillment_providers = fulfillmentProviders - - res.status(200).json({ store: data }) -} diff --git a/packages/medusa/src/api/routes/admin/store/index.ts b/packages/medusa/src/api/routes/admin/store/index.ts deleted file mode 100644 index 877a1852c8..0000000000 --- a/packages/medusa/src/api/routes/admin/store/index.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { Router } from "express" -import { PaymentProvider, Store, TaxProvider } from "./../../../../" -import middlewares from "../../../middlewares" -import { ExtendedStoreDTO } from "../../../../types/store" - -const route = Router() - -export default (app) => { - app.use("/store", route) - - route.get("/", middlewares.wrap(require("./get-store").default)) - route.get( - "/payment-providers", - middlewares.wrap(require("./list-payment-providers").default) - ) - route.get( - "/tax-providers", - middlewares.wrap(require("./list-tax-providers").default) - ) - route.post("/", middlewares.wrap(require("./update-store").default)) - route.post( - "/currencies/:currency_code", - middlewares.wrap(require("./add-currency").default) - ) - route.delete( - "/currencies/:currency_code", - middlewares.wrap(require("./remove-currency").default) - ) - - return app -} - -export const defaultRelationsExtended = ["currencies", "default_currency"] - -/** - * @schema AdminExtendedStoresRes - * type: object - * description: "The store's details with additional details like payment and tax providers." - * x-expanded-relations: - * field: store - * relations: - * - currencies - * - default_currency - * required: - * - store - * properties: - * store: - * description: Store details. - * $ref: "#/components/schemas/ExtendedStoreDTO" - */ -export type AdminExtendedStoresRes = { - store: ExtendedStoreDTO -} - -/** - * @schema AdminStoresRes - * type: object - * description: "The store's details." - * required: - * - store - * properties: - * store: - * description: Store details. - * $ref: "#/components/schemas/Store" - */ -export type AdminStoresRes = { - store: Store -} - -/** - * @schema AdminTaxProvidersList - * type: object - * description: "The list of tax providers in a store." - * required: - * - tax_providers - * properties: - * tax_providers: - * type: array - * description: An array of tax providers details. - * items: - * $ref: "#/components/schemas/TaxProvider" - */ -export type AdminTaxProvidersList = { - tax_providers: TaxProvider[] -} - -/** - * @schema AdminPaymentProvidersList - * type: object - * description: "The list of payment providers in a store." - * required: - * - payment_providers - * properties: - * payment_providers: - * type: array - * description: An array of payment providers details. - * items: - * $ref: "#/components/schemas/PaymentProvider" - */ -export type AdminPaymentProvidersList = { - payment_providers: PaymentProvider[] -} - -export * from "./update-store" diff --git a/packages/medusa/src/api/routes/admin/store/list-payment-providers.ts b/packages/medusa/src/api/routes/admin/store/list-payment-providers.ts deleted file mode 100644 index 2d49e8ebc3..0000000000 --- a/packages/medusa/src/api/routes/admin/store/list-payment-providers.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { PaymentProviderService } from "../../../../services" - -/** - * @oas [get] /admin/store/payment-providers - * operationId: "GetStorePaymentProviders" - * summary: "List Payment Providers" - * description: "Retrieve a list of available Payment Providers in a store." - * x-authenticated: true - * x-codegen: - * method: listPaymentProviders - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.store.listPaymentProviders() - * .then(({ payment_providers }) => { - * console.log(payment_providers.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminStorePaymentProviders } from "medusa-react" - * - * const PaymentProviders = () => { - * const { - * payment_providers, - * isLoading - * } = useAdminStorePaymentProviders() - * - * return ( - *
- * {isLoading && Loading...} - * {payment_providers && !payment_providers.length && ( - * No Payment Providers - * )} - * {payment_providers && - * payment_providers.length > 0 &&( - *
    - * {payment_providers.map((provider) => ( - *
  • {provider.id}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default PaymentProviders - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/store/payment-providers' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Store - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPaymentProvidersList" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const paymentProviderService: PaymentProviderService = req.scope.resolve( - "paymentProviderService" - ) - const paymentProviders = await paymentProviderService.list() - res.status(200).json({ payment_providers: paymentProviders }) -} diff --git a/packages/medusa/src/api/routes/admin/store/list-tax-providers.ts b/packages/medusa/src/api/routes/admin/store/list-tax-providers.ts deleted file mode 100644 index 230c1ec14c..0000000000 --- a/packages/medusa/src/api/routes/admin/store/list-tax-providers.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { TaxProviderService } from "../../../../services" - -/** - * @oas [get] /admin/store/tax-providers - * operationId: "GetStoreTaxProviders" - * summary: "List Tax Providers" - * description: "Retrieve a list of available Tax Providers in a store." - * x-authenticated: true - * x-codegen: - * method: listTaxProviders - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.store.listTaxProviders() - * .then(({ tax_providers }) => { - * console.log(tax_providers.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminStoreTaxProviders } from "medusa-react" - * - * const TaxProviders = () => { - * const { - * tax_providers, - * isLoading - * } = useAdminStoreTaxProviders() - * - * return ( - *
- * {isLoading && Loading...} - * {tax_providers && !tax_providers.length && ( - * No Tax Providers - * )} - * {tax_providers && - * tax_providers.length > 0 &&( - *
    - * {tax_providers.map((provider) => ( - *
  • {provider.id}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default TaxProviders - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/store/tax-providers' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Store - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminTaxProvidersList" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const taxProviderService: TaxProviderService = - req.scope.resolve("taxProviderService") - const taxProviders = await taxProviderService.list() - res.status(200).json({ tax_providers: taxProviders }) -} diff --git a/packages/medusa/src/api/routes/admin/store/remove-currency.ts b/packages/medusa/src/api/routes/admin/store/remove-currency.ts deleted file mode 100644 index 2e7e5a6537..0000000000 --- a/packages/medusa/src/api/routes/admin/store/remove-currency.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { StoreService } from "../../../../services" -import { EntityManager } from "typeorm" - -/** - * @oas [delete] /admin/store/currencies/{code} - * operationId: "DeleteStoreCurrenciesCode" - * summary: "Remove a Currency" - * description: "Remove a Currency Code from the available currencies in a store. This does not completely delete the currency and it can be added again later to the store." - * x-authenticated: true - * parameters: - * - in: path - * name: code - * required: true - * description: The 3 character ISO currency code. - * schema: - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * x-codegen: - * method: deleteCurrency - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.store.deleteCurrency("eur") - * .then(({ store }) => { - * console.log(store.currencies); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteStoreCurrency } from "medusa-react" - * - * const Store = () => { - * const deleteCurrency = useAdminDeleteStoreCurrency() - * // ... - * - * const handleAdd = (code: string) => { - * deleteCurrency.mutate(code, { - * onSuccess: ({ store }) => { - * console.log(store.currencies) - * } - * }) - * } - * - * // ... - * } - * - * export default Store - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/store/currencies/{currency_code}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Store - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminStoresRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { currency_code } = req.params - - const storeService: StoreService = req.scope.resolve("storeService") - const manager: EntityManager = req.scope.resolve("manager") - const data = await manager.transaction(async (transactionManager) => { - return await storeService - .withTransaction(transactionManager) - .removeCurrency(currency_code) - }) - - res.status(200).json({ store: data }) -} diff --git a/packages/medusa/src/api/routes/admin/store/update-store.ts b/packages/medusa/src/api/routes/admin/store/update-store.ts deleted file mode 100644 index ea39d76dca..0000000000 --- a/packages/medusa/src/api/routes/admin/store/update-store.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { IsArray, IsObject, IsOptional, IsString } from "class-validator" - -import { StoreService } from "../../../../services" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/store - * operationId: "PostStore" - * summary: "Update Store Details" - * description: "Update the Store's details." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostStoreReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.store.update({ - * name: "Medusa Store" - * }) - * .then(({ store }) => { - * console.log(store.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateStore } from "medusa-react" - * - * function Store() { - * const updateStore = useAdminUpdateStore() - * // ... - * - * const handleUpdate = ( - * name: string - * ) => { - * updateStore.mutate({ - * name - * }, { - * onSuccess: ({ store }) => { - * console.log(store.name) - * } - * }) - * } - * } - * - * export default Store - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/store' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "Medusa Store" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Store - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminStoresRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validatedBody = await validator(AdminPostStoreReq, req.body) - - const storeService: StoreService = req.scope.resolve("storeService") - - const manager: EntityManager = req.scope.resolve("manager") - const store = await manager.transaction(async (transactionManager) => { - return await storeService - .withTransaction(transactionManager) - .update(validatedBody) - }) - - res.status(200).json({ store }) -} - -/** - * @schema AdminPostStoreReq - * type: object - * description: "The details to update of the store." - * properties: - * name: - * description: "The name of the Store" - * type: string - * swap_link_template: - * description: >- - * A template for Swap links - use `{{cart_id}}` to insert the Swap Cart ID - * type: string - * example: "http://example.com/swaps/{{cart_id}}" - * payment_link_template: - * description: "A template for payment links - use `{{cart_id}}` to insert the Cart ID" - * example: "http://example.com/payments/{{cart_id}}" - * type: string - * invite_link_template: - * description: "A template for invite links - use `{{invite_token}}` to insert the invite token" - * example: "http://example.com/invite?token={{invite_token}}" - * type: string - * default_currency_code: - * description: "The default currency code of the Store." - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * currencies: - * description: "Array of available currencies in the store. Each currency is in 3 character ISO code format." - * type: array - * items: - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * metadata: - * description: "An optional set of key-value pairs with additional information." - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminPostStoreReq { - @IsOptional() - @IsString() - name?: string - - @IsString() - @IsOptional() - swap_link_template?: string - - @IsString() - @IsOptional() - payment_link_template?: string - - @IsString() - @IsOptional() - invite_link_template?: string - - @IsString() - @IsOptional() - default_currency_code?: string - - @IsArray() - @IsString({ each: true }) - @IsOptional() - currencies?: string[] - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/swaps/__tests__/get-swap.js b/packages/medusa/src/api/routes/admin/swaps/__tests__/get-swap.js deleted file mode 100644 index 3c55487958..0000000000 --- a/packages/medusa/src/api/routes/admin/swaps/__tests__/get-swap.js +++ /dev/null @@ -1,77 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { SwapServiceMock } from "../../../../../services/__mocks__/swap" - -const defaultRelations = [ - "additional_items", - "additional_items.adjustments", - "cart", - "cart.items", - "cart.items.adjustments", - "cart.items.variant", - "fulfillments", - "order", - "payment", - "return_order", - "shipping_address", - "shipping_methods", - "shipping_methods.shipping_option", -] - -const defaultFields = [ - "id", - "fulfillment_status", - "payment_status", - "order_id", - "difference_due", - "cart_id", - "created_at", - "updated_at", - "metadata", - "cart.subtotal", - "cart.tax_total", - "cart.shipping_total", - "cart.discount_total", - "cart.gift_card_total", - "cart.total", -] - -describe("GET /admin/swaps/:id", () => { - describe("successfully gets a swap", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/admin/swaps/${IdMap.getId("test-swap")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls swapService retrieve", () => { - expect(SwapServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(SwapServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("test-swap"), - { - select: defaultFields, - relations: defaultRelations, - } - ) - }) - - it("returns swap", () => { - expect(subject.status).toEqual(200) - expect(subject.body.swap.id).toEqual("test-swap") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/swaps/__tests__/list-swaps.js b/packages/medusa/src/api/routes/admin/swaps/__tests__/list-swaps.js deleted file mode 100644 index 8a1a2381ae..0000000000 --- a/packages/medusa/src/api/routes/admin/swaps/__tests__/list-swaps.js +++ /dev/null @@ -1,48 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { SwapServiceMock } from "../../../../../services/__mocks__/swap" -import { request } from "../../../../../helpers/test-request" - -const defaultListOptions = { - take: 50, - skip: 0, - order: { created_at: "DESC" }, -} - -describe("GET /admin/swaps/", () => { - describe("successfully lists swaps", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/admin/swaps/`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls swapService list with default pagination and sorting options", () => { - expect(SwapServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(SwapServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - { - ...defaultListOptions, - } - ) - }) - - it("returns swaps", () => { - expect(subject.status).toEqual(200) - expect(subject.body.count).toBe(2) - expect(subject.body.swaps).toEqual([ - { id: IdMap.getId("test-swap") }, - { id: IdMap.getId("test-swap-1") }, - ]) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/swaps/get-swap.ts b/packages/medusa/src/api/routes/admin/swaps/get-swap.ts deleted file mode 100644 index b0aaf920cf..0000000000 --- a/packages/medusa/src/api/routes/admin/swaps/get-swap.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { defaultAdminSwapFields, defaultAdminSwapRelations } from "." - -import { SwapService } from "../../../../services" - -/** - * @oas [get] /admin/swaps/{id} - * operationId: "GetSwapsSwap" - * summary: "Get a Swap" - * description: "Retrieve a Swap's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Swap. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.swaps.retrieve(swapId) - * .then(({ swap }) => { - * console.log(swap.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminSwap } from "medusa-react" - * - * type Props = { - * swapId: string - * } - * - * const Swap = ({ swapId }: Props) => { - * const { swap, isLoading } = useAdminSwap(swapId) - * - * return ( - *
- * {isLoading && Loading...} - * {swap && {swap.id}} - *
- * ) - * } - * - * export default Swap - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/swaps/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Swaps - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminSwapsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const swapService: SwapService = req.scope.resolve("swapService") - - const swap = await swapService.retrieve(id, { - select: defaultAdminSwapFields, - relations: defaultAdminSwapRelations, - }) - - res.json({ swap }) -} diff --git a/packages/medusa/src/api/routes/admin/swaps/index.ts b/packages/medusa/src/api/routes/admin/swaps/index.ts deleted file mode 100644 index 3d18629197..0000000000 --- a/packages/medusa/src/api/routes/admin/swaps/index.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { Router } from "express" -import { Swap } from "../../../.." -import { PaginatedResponse } from "../../../../types/common" -import middlewares from "../../../middlewares" - -const route = Router() - -export default (app) => { - app.use("/swaps", route) - - /** - * List swaps - */ - route.get("/", middlewares.wrap(require("./list-swaps").default)) - - /** - * Get a swap - */ - route.get("/:id", middlewares.wrap(require("./get-swap").default)) - - return app -} - -export const defaultAdminSwapRelations = [ - "additional_items", - "additional_items.adjustments", - "cart", - "cart.items", - "cart.items.adjustments", - "cart.items.variant", - "fulfillments", - "order", - "payment", - "return_order", - "shipping_address", - "shipping_methods", - "shipping_methods.shipping_option", -] - -export const defaultAdminSwapFields = [ - "id", - "fulfillment_status", - "payment_status", - "order_id", - "difference_due", - "cart_id", - "created_at", - "updated_at", - "metadata", - "cart.subtotal", - "cart.tax_total", - "cart.shipping_total", - "cart.discount_total", - "cart.gift_card_total", - "cart.total", -] - -/** - * @schema AdminSwapsListRes - * type: object - * description: "The list of swaps with pagination fields." - * required: - * - swaps - * - count - * - offset - * - limit - * properties: - * swaps: - * type: array - * description: "An array of swaps details." - * items: - * $ref: "#/components/schemas/Swap" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of swaps skipped when retrieving the swaps. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminSwapsListRes = PaginatedResponse & { - swaps: Swap[] -} - -/** - * @schema AdminSwapsRes - * type: object - * description: "The swap's details." - * x-expanded-relations: - * field: swap - * relations: - * - additional_items - * - additional_items.adjustments - * - cart - * - cart.items - * - cart.items.adjustments - * - cart.items.variant - * - fulfillments - * - order - * - payment - * - return_order - * - shipping_address - * - shipping_methods - * eager: - * - fulfillments.items - * - shipping_methods.shipping_option - * required: - * - swap - * properties: - * swap: - * description: "Swap details." - * $ref: "#/components/schemas/Swap" - */ -export type AdminSwapsRes = { - swap: Swap -} - -export * from "./get-swap" -export * from "./list-swaps" diff --git a/packages/medusa/src/api/routes/admin/swaps/list-swaps.ts b/packages/medusa/src/api/routes/admin/swaps/list-swaps.ts deleted file mode 100644 index 280108e0dd..0000000000 --- a/packages/medusa/src/api/routes/admin/swaps/list-swaps.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { IsInt, IsOptional } from "class-validator" - -import { FindConfig } from "../../../../types/common" -import { Swap } from "../../../../models" -import { SwapService } from "../../../../services" -import { Type } from "class-transformer" -import { validator } from "../../../../utils/validator" - -/** - * @oas [get] /admin/swaps - * operationId: "GetSwaps" - * summary: "List Swaps" - * description: "Retrieve a list of Swaps. The swaps can be paginated." - * parameters: - * - (query) limit=50 {number} Limit the number of swaps returned. - * - (query) offset=0 {number} The number of swaps to skip when retrieving the swaps. - * x-authenticated: true - * x-codegen: - * method: list - * queryParams: AdminGetSwapsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.swaps.list() - * .then(({ swaps }) => { - * console.log(swaps.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminSwaps } from "medusa-react" - * - * const Swaps = () => { - * const { swaps, isLoading } = useAdminSwaps() - * - * return ( - *
- * {isLoading && Loading...} - * {swaps && !swaps.length && No Swaps} - * {swaps && swaps.length > 0 && ( - *
    - * {swaps.map((swap) => ( - *
  • {swap.payment_status}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Swaps - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/swaps' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Swaps - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminSwapsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const swapService: SwapService = req.scope.resolve("swapService") - - const { offset, limit } = await validator(AdminGetSwapsParams, req.query) - - const selector = {} - - const listConfig: FindConfig = { - skip: offset, - take: limit, - order: { created_at: "DESC" }, - } - - const [swaps, count] = await swapService.listAndCount(selector, { - ...listConfig, - }) - - res.json({ swaps, count, offset, limit }) -} - -/** - * {@inheritDoc FindPaginationParams} - */ -export class AdminGetSwapsParams { - /** - * {@inheritDoc FindPaginationParams.limit} - */ - @IsInt() - @IsOptional() - @Type(() => Number) - limit?: number = 50 - - /** - * {@inheritDoc FindPaginationParams.offset} - */ - @IsInt() - @IsOptional() - @Type(() => Number) - offset?: number = 0 -} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/add-to-product-types.ts b/packages/medusa/src/api/routes/admin/tax-rates/add-to-product-types.ts deleted file mode 100644 index b8a2b1105d..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/add-to-product-types.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { IsArray, IsOptional } from "class-validator" -import { getRetrieveConfig, pickByConfig } from "./utils/get-query-config" - -import { EntityManager } from "typeorm" -import { TaxRate } from "../../../.." -import { TaxRateService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/tax-rates/{id}/product-types/batch - * operationId: "PostTaxRatesTaxRateProductTypes" - * summary: "Add to Product Types" - * description: "Add Product Types to a Tax Rate." - * parameters: - * - (path) id=* {string} ID of the tax rate. - * - in: query - * name: fields - * description: "Comma-separated fields that should be included in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * - in: query - * name: expand - * description: "Comma-separated relations that should be expanded in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostTaxRatesTaxRateProductTypesReq" - * x-codegen: - * method: addProductTypes - * queryParams: AdminPostTaxRatesTaxRateProductTypesParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.addProductTypes(taxRateId, { - * product_types: [ - * productTypeId - * ] - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminCreateProductTypeTaxRates, - * } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const addProductTypes = useAdminCreateProductTypeTaxRates( - * taxRateId - * ) - * // ... - * - * const handleAddProductTypes = (productTypeIds: string[]) => { - * addProductTypes.mutate({ - * product_types: productTypeIds, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.product_types) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/tax-rates/{id}/product-types/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "product_types": [ - * "{product_type_id}" - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Tax Rates - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminTaxRatesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const value = await validator( - AdminPostTaxRatesTaxRateProductTypesReq, - req.body - ) - - const query = await validator( - AdminPostTaxRatesTaxRateProductTypesParams, - req.query - ) - - const rateService: TaxRateService = req.scope.resolve("taxRateService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await rateService - .withTransaction(transactionManager) - .addToProductType(req.params.id, value.product_types) - }) - - const config = getRetrieveConfig( - query.fields as (keyof TaxRate)[], - query.expand - ) - const rate = await rateService.retrieve(req.params.id, config) - const data = pickByConfig(rate, config) - - res.json({ tax_rate: data }) -} - -/** - * @schema AdminPostTaxRatesTaxRateProductTypesReq - * type: object - * description: "The product types to add to the tax rate." - * required: - * - product_types - * properties: - * product_types: - * type: array - * description: "The IDs of the types of products to associate with this tax rate" - * items: - * type: string - */ -export class AdminPostTaxRatesTaxRateProductTypesReq { - @IsArray() - product_types: string[] -} - -/** - * {@inheritDoc FindParams} - */ -export class AdminPostTaxRatesTaxRateProductTypesParams { - /** - * {@inheritDoc FindParams.expand} - */ - @IsArray() - @IsOptional() - expand?: string[] - - /** - * {@inheritDoc FindParams.fields} - */ - @IsArray() - @IsOptional() - fields?: string[] -} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/add-to-products.ts b/packages/medusa/src/api/routes/admin/tax-rates/add-to-products.ts deleted file mode 100644 index 4dac769cf6..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/add-to-products.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { IsArray, IsOptional } from "class-validator" -import { getRetrieveConfig, pickByConfig } from "./utils/get-query-config" - -import { EntityManager } from "typeorm" -import { TaxRate } from "../../../.." -import { TaxRateService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/tax-rates/{id}/products/batch - * operationId: "PostTaxRatesTaxRateProducts" - * summary: "Add to Products" - * description: "Add products to a tax rate." - * parameters: - * - (path) id=* {string} ID of the tax rate. - * - in: query - * name: fields - * description: "Comma-separated fields that should be included in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * - in: query - * name: expand - * description: "Comma-separated relations that should be expanded in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostTaxRatesTaxRateProductsReq" - * x-codegen: - * method: addProducts - * queryParams: AdminPostTaxRatesTaxRateProductsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.addProducts(taxRateId, { - * products: [ - * productId - * ] - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateProductTaxRates } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const addProduct = useAdminCreateProductTaxRates(taxRateId) - * // ... - * - * const handleAddProduct = (productIds: string[]) => { - * addProduct.mutate({ - * products: productIds, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.products) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/tax-rates/{id}/products/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "products": [ - * "{product_id}" - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Tax Rates - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminTaxRatesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const value = await validator(AdminPostTaxRatesTaxRateProductsReq, req.body) - - const query = await validator( - AdminPostTaxRatesTaxRateProductsParams, - req.query - ) - - const rateService: TaxRateService = req.scope.resolve("taxRateService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await rateService - .withTransaction(transactionManager) - .addToProduct(req.params.id, value.products) - }) - - const config = getRetrieveConfig( - query.fields as (keyof TaxRate)[], - query.expand - ) - const rate = await rateService.retrieve(req.params.id, config) - const data = pickByConfig(rate, config) - - res.json({ tax_rate: data }) -} - -/** - * @schema AdminPostTaxRatesTaxRateProductsReq - * type: object - * description: "The details of the products to associat with the tax rate." - * required: - * - products - * properties: - * products: - * type: array - * description: "The IDs of the products to associate with this tax rate" - * items: - * type: string - */ -export class AdminPostTaxRatesTaxRateProductsReq { - @IsArray() - products: string[] -} - -/** - * {@inheritDoc FindParams} - */ -export class AdminPostTaxRatesTaxRateProductsParams { - /** - * {@inheritDoc FindParams.expand} - */ - @IsArray() - @IsOptional() - expand?: string[] - - /** - * {@inheritDoc FindParams.fields} - */ - @IsArray() - @IsOptional() - fields?: string[] -} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/add-to-shipping-options.ts b/packages/medusa/src/api/routes/admin/tax-rates/add-to-shipping-options.ts deleted file mode 100644 index 0d37229842..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/add-to-shipping-options.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { IsArray, IsOptional } from "class-validator" -import { getRetrieveConfig, pickByConfig } from "./utils/get-query-config" - -import { EntityManager } from "typeorm" -import { TaxRate } from "../../../.." -import { TaxRateService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/tax-rates/{id}/shipping-options/batch - * operationId: "PostTaxRatesTaxRateShippingOptions" - * summary: "Add to Shipping Options" - * description: "Add Shipping Options to a Tax Rate." - * parameters: - * - (path) id=* {string} ID of the tax rate. - * - in: query - * name: fields - * description: "Comma-separated fields that should be included in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * - in: query - * name: expand - * description: "Comma-separated relations that should be expanded in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostTaxRatesTaxRateShippingOptionsReq" - * x-codegen: - * method: addShippingOptions - * queryParams: AdminPostTaxRatesTaxRateShippingOptionsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.addShippingOptions(taxRateId, { - * shipping_options: [ - * shippingOptionId - * ] - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateShippingTaxRates } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const addShippingOption = useAdminCreateShippingTaxRates( - * taxRateId - * ) - * // ... - * - * const handleAddShippingOptions = ( - * shippingOptionIds: string[] - * ) => { - * addShippingOption.mutate({ - * shipping_options: shippingOptionIds, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.shipping_options) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/tax-rates/{id}/shipping-options/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "shipping_options": [ - * "{shipping_option_id}" - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Tax Rates - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminTaxRatesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const value = await validator( - AdminPostTaxRatesTaxRateShippingOptionsReq, - req.body - ) - - const query = await validator( - AdminPostTaxRatesTaxRateShippingOptionsParams, - req.query - ) - - const rateService: TaxRateService = req.scope.resolve("taxRateService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await rateService - .withTransaction(transactionManager) - .addToShippingOption(req.params.id, value.shipping_options) - }) - - const config = getRetrieveConfig( - query.fields as (keyof TaxRate)[], - query.expand - ) - const rate = await rateService.retrieve(req.params.id, config) - const data = pickByConfig(rate, config) - - res.json({ tax_rate: data }) -} - -/** - * @schema AdminPostTaxRatesTaxRateShippingOptionsReq - * type: object - * description: "The details of the shipping options to associate with the tax rate." - * required: - * - shipping_options - * properties: - * shipping_options: - * type: array - * description: "The IDs of the shipping options to associate with this tax rate" - * items: - * type: string - */ -export class AdminPostTaxRatesTaxRateShippingOptionsReq { - @IsArray() - shipping_options: string[] -} - -/** - * {@inheritDoc FindParams} - */ -export class AdminPostTaxRatesTaxRateShippingOptionsParams { - /** - * {@inheritDoc FindParams.expand} - */ - @IsArray() - @IsOptional() - expand?: string[] - - /** - * {@inheritDoc FindParams.fields} - */ - @IsArray() - @IsOptional() - fields?: string[] -} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/create-tax-rate.ts b/packages/medusa/src/api/routes/admin/tax-rates/create-tax-rate.ts deleted file mode 100644 index 3d510a46e6..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/create-tax-rate.ts +++ /dev/null @@ -1,259 +0,0 @@ -import { IsArray, IsNumber, IsOptional, IsString } from "class-validator" -import { getRetrieveConfig, pickByConfig } from "./utils/get-query-config" - -import { omit } from "lodash" -import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { TaxRate } from "../../../.." -import { TaxRateService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/tax-rates - * operationId: "PostTaxRates" - * summary: "Create a Tax Rate" - * description: "Create a Tax Rate." - * parameters: - * - in: query - * name: fields - * description: "Comma-separated fields that should be included in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * - in: query - * name: expand - * description: "Comma-separated relations that should be expanded in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostTaxRatesReq" - * x-codegen: - * method: create - * queryParams: AdminPostTaxRatesParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.create({ - * code: "TEST", - * name: "New Tax Rate", - * region_id - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateTaxRate } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const CreateTaxRate = ({ regionId }: Props) => { - * const createTaxRate = useAdminCreateTaxRate() - * // ... - * - * const handleCreate = ( - * code: string, - * name: string, - * rate: number - * ) => { - * createTaxRate.mutate({ - * code, - * name, - * region_id: regionId, - * rate, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateTaxRate - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/tax-rates' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "code": "TEST", - * "name": "New Tax Rate", - * "region_id": "{region_id}" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Tax Rates - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminTaxRatesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const value = await validator(AdminPostTaxRatesReq, req.body) - - const query = await validator(AdminPostTaxRatesParams, req.query) - - const manager: EntityManager = req.scope.resolve("manager") - const rateService: TaxRateService = req.scope.resolve("taxRateService") - - let id: string | undefined - await manager.transaction(async (tx) => { - const txRateService = rateService.withTransaction(tx) - const created = await txRateService.create( - omit(value, ["products", "product_types", "shipping_options"]) - ) - id = created.id - - if (isDefined(value.products)) { - await txRateService.addToProduct(id, value.products) - } - - if (isDefined(value.product_types)) { - await txRateService.addToProductType(id, value.product_types) - } - - if (isDefined(value.shipping_options)) { - await txRateService.addToShippingOption(id, value.shipping_options) - } - }) - - if (typeof id === "undefined") { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Tax Rate was not created" - ) - } - - const config = getRetrieveConfig( - query.fields as (keyof TaxRate)[], - query.expand - ) - - const rate = await rateService.retrieve(id, config) - const data = pickByConfig(rate, config) - - res.json({ tax_rate: data }) -} - -/** - * @schema AdminPostTaxRatesReq - * type: object - * description: "The details of the tax rate to create." - * required: - * - code - * - name - * - region_id - * properties: - * code: - * type: string - * description: "The code of the tax rate." - * name: - * type: string - * description: "The name of the tax rate." - * region_id: - * type: string - * description: "The ID of the Region that the tax rate belongs to." - * rate: - * type: number - * description: "The numeric rate to charge." - * products: - * type: array - * description: "The IDs of the products associated with this tax rate." - * items: - * type: string - * shipping_options: - * type: array - * description: "The IDs of the shipping options associated with this tax rate" - * items: - * type: string - * product_types: - * type: array - * description: "The IDs of the types of products associated with this tax rate" - * items: - * type: string - */ -export class AdminPostTaxRatesReq { - @IsString() - code: string - - @IsString() - name: string - - @IsString() - region_id: string - - @IsOptional() - @IsNumber() - rate?: number | null - - @IsOptional() - @IsArray() - products?: string[] - - @IsOptional() - @IsArray() - shipping_options?: string[] - - @IsOptional() - @IsArray() - product_types?: string[] -} - -/** - * {@inheritDoc FindParams} - */ -export class AdminPostTaxRatesParams { - /** - * {@inheritDoc FindParams.expand} - */ - @IsArray() - @IsOptional() - expand?: string[] - - /** - * {@inheritDoc FindParams.fields} - */ - @IsArray() - @IsOptional() - fields?: string[] -} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/delete-tax-rate.ts b/packages/medusa/src/api/routes/admin/tax-rates/delete-tax-rate.ts deleted file mode 100644 index 96c97c60a7..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/delete-tax-rate.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { EntityManager } from "typeorm" -import { TaxRateService } from "../../../../services" - -/** - * @oas [delete] /admin/tax-rates/{id} - * operationId: "DeleteTaxRatesTaxRate" - * summary: "Delete a Tax Rate" - * description: "Delete a Tax Rate. Resources associated with the tax rate, such as products or product types, are not deleted." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the Shipping Option. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.delete(taxRateId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteTaxRate } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const deleteTaxRate = useAdminDeleteTaxRate(taxRateId) - * // ... - * - * const handleDelete = () => { - * deleteTaxRate.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/tax-rates/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Tax Rates - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminTaxRatesDeleteRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const taxRateService: TaxRateService = req.scope.resolve("taxRateService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await taxRateService.withTransaction(transactionManager).delete(id) - }) - - res.json({ - id: id, - object: "tax-rate", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/get-tax-rate.ts b/packages/medusa/src/api/routes/admin/tax-rates/get-tax-rate.ts deleted file mode 100644 index 3766b48e8d..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/get-tax-rate.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { IsArray, IsOptional } from "class-validator" -import { getRetrieveConfig, pickByConfig } from "./utils/get-query-config" - -import { TaxRate } from "../../../.." -import { TaxRateService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [get] /admin/tax-rates/{id} - * operationId: "GetTaxRatesTaxRate" - * summary: "Get a Tax Rate" - * description: "Retrieve a Tax Rate's details." - * parameters: - * - (path) id=* {string} ID of the tax rate. - * - in: query - * name: fields - * description: "Comma-separated fields that should be included in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * - in: query - * name: expand - * description: "Comma-separated relations that should be expanded in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * x-authenticated: true - * x-codegen: - * method: retrieve - * queryParams: AdminGetTaxRatesTaxRateParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.retrieve(taxRateId) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminTaxRate } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const { tax_rate, isLoading } = useAdminTaxRate(taxRateId) - * - * return ( - *
- * {isLoading && Loading...} - * {tax_rate && {tax_rate.code}} - *
- * ) - * } - * - * export default TaxRate - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/tax-rates/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Tax Rates - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminTaxRatesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const value = await validator(AdminGetTaxRatesTaxRateParams, req.query) - - const rateService: TaxRateService = req.scope.resolve("taxRateService") - const config = getRetrieveConfig( - value.fields as (keyof TaxRate)[], - value.expand - ) - const rate = await rateService.retrieve(req.params.id, config) - const data = pickByConfig(rate, config) - - res.json({ tax_rate: data }) -} - -/** - * {@inheritDoc FindParams} - */ -export class AdminGetTaxRatesTaxRateParams { - /** - * {@inheritDoc FindParams.expand} - */ - @IsArray() - @IsOptional() - expand?: string[] - - /** - * {@inheritDoc FindParams.fields} - */ - @IsArray() - @IsOptional() - fields?: string[] -} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/index.ts b/packages/medusa/src/api/routes/admin/tax-rates/index.ts deleted file mode 100644 index ea97a40b34..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/index.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { Router } from "express" -import { TaxRate } from "../../../.." -import { DeleteResponse, PaginatedResponse } from "../../../../types/common" -import middlewares from "../../../middlewares" - -const route = Router() - -export default (app) => { - app.use("/tax-rates", route) - - /** - * List tax rates - */ - route.get("/", middlewares.wrap(require("./list-tax-rates").default)) - - /** - * Get a tax rate - */ - route.get("/:id", middlewares.wrap(require("./get-tax-rate").default)) - - /** - * Create a tax rate - */ - route.post("/", middlewares.wrap(require("./create-tax-rate").default)) - - /** - * Update a tax rate - */ - route.post("/:id", middlewares.wrap(require("./update-tax-rate").default)) - - /** - * Remove products from tax rate - */ - route.delete( - "/:id/products/batch", - middlewares.wrap(require("./remove-from-products").default) - ) - - /** - * Remove product types from tax rate - */ - route.delete( - "/:id/product-types/batch", - middlewares.wrap(require("./remove-from-product-types").default) - ) - - /** - * Remove shipping options from tax rate - */ - route.delete( - "/:id/shipping-options/batch", - middlewares.wrap(require("./remove-from-shipping-options").default) - ) - - /** - * Add products to tax rate - */ - route.post( - "/:id/products/batch", - middlewares.wrap(require("./add-to-products").default) - ) - - /** - * Add product types to tax rate - */ - route.post( - "/:id/product-types/batch", - middlewares.wrap(require("./add-to-product-types").default) - ) - - /** - * Add to shipping options - */ - route.post( - "/:id/shipping-options/batch", - middlewares.wrap(require("./add-to-shipping-options").default) - ) - - /** - * Delete a tax rate - */ - route.delete("/:id", middlewares.wrap(require("./delete-tax-rate").default)) - - return app -} - -export const defaultAdminTaxRatesRelations = [] - -export const defaultAdminTaxRatesFields: (keyof TaxRate)[] = [ - "id", - "rate", - "code", - "name", - "region_id", - "created_at", - "updated_at", -] - -/** - * @schema AdminTaxRatesDeleteRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted Shipping Option. - * object: - * type: string - * description: The type of the object that was deleted. - * default: tax-rate - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminTaxRatesDeleteRes = DeleteResponse - -/** - * @schema AdminTaxRatesListRes - * type: object - * description: "The list of tax rates with pagination fields." - * required: - * - tax_rates - * - count - * - offset - * - limit - * properties: - * tax_rates: - * type: array - * description: "An array of tax rate details." - * items: - * $ref: "#/components/schemas/TaxRate" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of tax rates to skip when retrieving the tax rates. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminTaxRatesListRes = PaginatedResponse & { - tax_rates: TaxRate[] -} - -/** - * @schema AdminTaxRatesRes - * type: object - * description: "The tax rate's details." - * required: - * - tax_rate - * properties: - * tax_rate: - * description: "Tax rate details." - * $ref: "#/components/schemas/TaxRate" - */ -export type AdminTaxRatesRes = { - tax_rate: TaxRate -} - -export * from "./list-tax-rates" -export * from "./get-tax-rate" -export * from "./remove-from-product-types" -export * from "./remove-from-products" -export * from "./remove-from-shipping-options" -export * from "./add-to-product-types" -export * from "./add-to-products" -export * from "./add-to-shipping-options" -export * from "./create-tax-rate" -export * from "./delete-tax-rate" -export * from "./update-tax-rate" diff --git a/packages/medusa/src/api/routes/admin/tax-rates/list-tax-rates.ts b/packages/medusa/src/api/routes/admin/tax-rates/list-tax-rates.ts deleted file mode 100644 index f0e38f0be2..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/list-tax-rates.ts +++ /dev/null @@ -1,372 +0,0 @@ -import { - IsArray, - IsNumber, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { identity, omit, pickBy } from "lodash" -import { getListConfig, pickByConfig } from "./utils/get-query-config" - -import { isDefined } from "@medusajs/utils" -import { Type } from "class-transformer" -import { TaxRate } from "../../../.." -import { TaxRateService } from "../../../../services" -import { - DateComparisonOperator, - NumericalComparisonOperator, -} from "../../../../types/common" -import { validator } from "../../../../utils/validator" -import { IsType } from "../../../../utils/validators/is-type" - -/** - * @oas [get] /admin/tax-rates - * operationId: "GetTaxRates" - * summary: "List Tax Rates" - * description: "Retrieve a list of Tax Rates. The tax rates can be filtered by fields such as `name` or `rate`. The tax rates can also be paginated." - * x-authenticated: true - * parameters: - * - (query) name {string} Filter by name. - * - in: query - * name: region_id - * style: form - * explode: false - * description: Filter by Region IDs - * schema: - * oneOf: - * - type: string - * - type: array - * items: - * type: string - * - (query) code {string} Filter by code. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: deleted_at - * description: Filter by a deletion date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: rate - * style: form - * explode: false - * description: Filter by Rate - * schema: - * oneOf: - * - type: number - * - type: object - * properties: - * lt: - * type: number - * description: filter by rates less than this number - * gt: - * type: number - * description: filter by rates greater than this number - * lte: - * type: number - * description: filter by rates less than or equal to this number - * gte: - * type: number - * description: filter by rates greater than or equal to this number - * - (query) q {string} Term used to search tax rates by name. - * - (query) order {string} A tax rate field to sort-order the retrieved tax rates by. - * - (query) offset=0 {integer} The number of tax rates to skip when retrieving the tax rates. - * - (query) limit=50 {integer} Limit the number of tax rates returned. - * - in: query - * name: fields - * description: "Comma-separated fields that should be included in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * - in: query - * name: expand - * description: "Comma-separated relations that should be expanded in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * x-codegen: - * method: list - * queryParams: AdminGetTaxRatesParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.list() - * .then(({ tax_rates, limit, offset, count }) => { - * console.log(tax_rates.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminTaxRates } from "medusa-react" - * - * const TaxRates = () => { - * const { - * tax_rates, - * isLoading - * } = useAdminTaxRates() - * - * return ( - *
- * {isLoading && Loading...} - * {tax_rates && !tax_rates.length && ( - * No Tax Rates - * )} - * {tax_rates && tax_rates.length > 0 && ( - *
    - * {tax_rates.map((tax_rate) => ( - *
  • {tax_rate.code}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default TaxRates - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/tax-rates' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Tax Rates - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminTaxRatesListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const value = await validator(AdminGetTaxRatesParams, req.query) - - const rateService: TaxRateService = req.scope.resolve("taxRateService") - - const order = value.order - let orderBy: { [k: symbol]: "DESC" | "ASC" } | undefined - if (isDefined(order)) { - let orderField = order - if (order.startsWith("-")) { - const [, field] = order.split("-") - orderField = field - orderBy = { [field]: "DESC" } - } else { - orderBy = { [order]: "ASC" } - } - } else { - const defaultOrder: string = "created_at" - orderBy = { [defaultOrder]: "DESC" } - } - - const listConfig = getListConfig( - value.fields as (keyof TaxRate)[], - value.expand, - value.limit, - value.offset, - orderBy - ) - - const filterableFields = omit(value, [ - "limit", - "offset", - "expand", - "fields", - "order", - ]) - - const [rates, count] = await rateService.listAndCount( - pickBy(filterableFields, identity), - listConfig - ) - - const data = pickByConfig(rates, listConfig) - - res.json({ tax_rates: data, count, offset: value.offset, limit: value.limit }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved tax rates. - */ -export class AdminGetTaxRatesParams { - /** - * Filter tax rates by the IDs of their associates region. - */ - @IsOptional() - @IsType([String, [String]]) - region_id?: string | string[] - - /** - * Name to filter tax rates by. - */ - @IsString() - @IsOptional() - name?: string - - /** - * Code to filter tax rates by. - */ - @IsString() - @IsOptional() - code?: string - - /** - * Number filters to filter tax rates' `rate` field. - */ - @IsType([NumericalComparisonOperator, Number]) - @IsOptional() - rate?: number | NumericalComparisonOperator - - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - offset? = 0 - - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 50 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit? = 50 - - /** - * {@inheritDoc FindParams.expand} - */ - @IsArray() - @IsOptional() - expand?: string[] - - /** - * {@inheritDoc FindParams.fields} - */ - @IsArray() - @IsOptional() - fields?: string[] - - @IsOptional() - @IsString() - order?: string - - /** - * Date filters to apply on the tax rates' `update_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on the customer tax rates' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the tax rates' `deleted_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - deleted_at?: DateComparisonOperator - - /** - * Term used to search tax rates by name. - */ - @IsOptional() - @IsString() - q?: string -} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/remove-from-product-types.ts b/packages/medusa/src/api/routes/admin/tax-rates/remove-from-product-types.ts deleted file mode 100644 index 1c609d5298..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/remove-from-product-types.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { IsArray, IsOptional } from "class-validator" -import { getRetrieveConfig, pickByConfig } from "./utils/get-query-config" - -import { EntityManager } from "typeorm" -import { TaxRate } from "../../../.." -import { TaxRateService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [delete] /admin/tax-rates/{id}/product-types/batch - * operationId: "DeleteTaxRatesTaxRateProductTypes" - * summary: "Remove Product Types from Rate" - * description: "Remove product types from a tax rate. This only removes the association between the product types and the tax rate. It does not delete the product types." - * parameters: - * - (path) id=* {string} ID of the tax rate. - * - in: query - * name: fields - * description: "Comma-separated fields that should be included in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * - in: query - * name: expand - * description: "Comma-separated relations that should be expanded in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteTaxRatesTaxRateProductTypesReq" - * x-codegen: - * method: removeProductTypes - * queryParams: AdminDeleteTaxRatesTaxRateProductTypesParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.removeProductTypes(taxRateId, { - * product_types: [ - * productTypeId - * ] - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { - * useAdminDeleteProductTypeTaxRates, - * } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const removeProductTypes = useAdminDeleteProductTypeTaxRates( - * taxRateId - * ) - * // ... - * - * const handleRemoveProductTypes = ( - * productTypeIds: string[] - * ) => { - * removeProductTypes.mutate({ - * product_types: productTypeIds, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.product_types) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/tax-rates/{id}/product-types/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "product_types": [ - * "{product_type_id}" - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Tax Rates - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminTaxRatesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const value = await validator( - AdminDeleteTaxRatesTaxRateProductTypesReq, - req.body - ) - - const query = await validator( - AdminDeleteTaxRatesTaxRateProductTypesParams, - req.query - ) - - const rateService: TaxRateService = req.scope.resolve("taxRateService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await rateService - .withTransaction(transactionManager) - .removeFromProductType(req.params.id, value.product_types) - }) - - const config = getRetrieveConfig( - query.fields as (keyof TaxRate)[], - query.expand - ) - const rate = await rateService.retrieve(req.params.id, config) - const data = pickByConfig(rate, config) - - res.json({ tax_rate: data }) -} - -/** - * @schema AdminDeleteTaxRatesTaxRateProductTypesReq - * type: object - * description: "Product types to remove from the tax rates." - * required: - * - product_types - * properties: - * product_types: - * type: array - * description: "The IDs of the product types to remove their association with this tax rate." - * items: - * type: string - */ -export class AdminDeleteTaxRatesTaxRateProductTypesReq { - @IsArray() - product_types: string[] -} - -/** - * {@inheritDoc FindParams} - */ -export class AdminDeleteTaxRatesTaxRateProductTypesParams { - /** - * {@inheritDoc FindParams.expand} - */ - @IsArray() - @IsOptional() - expand?: string[] - - /** - * {@inheritDoc FindParams.fields} - */ - @IsArray() - @IsOptional() - fields?: string[] -} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/remove-from-products.ts b/packages/medusa/src/api/routes/admin/tax-rates/remove-from-products.ts deleted file mode 100644 index 9d71c033e0..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/remove-from-products.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { IsArray, IsOptional } from "class-validator" -import { getRetrieveConfig, pickByConfig } from "./utils/get-query-config" - -import { EntityManager } from "typeorm" -import { TaxRate } from "../../../.." -import { TaxRateService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [delete] /admin/tax-rates/{id}/products/batch - * operationId: "DeleteTaxRatesTaxRateProducts" - * summary: "Remove Products from Rate" - * description: "Remove products from a tax rate. This only removes the association between the products and the tax rate. It does not delete the products." - * parameters: - * - (path) id=* {string} ID of the tax rate. - * - in: query - * name: fields - * description: "Comma-separated fields that should be included in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * - in: query - * name: expand - * description: "Comma-separated relations that should be expanded in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteTaxRatesTaxRateProductsReq" - * x-codegen: - * method: removeProducts - * queryParams: AdminDeleteTaxRatesTaxRateProductsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.removeProducts(taxRateId, { - * products: [ - * productId - * ] - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteProductTaxRates } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const removeProduct = useAdminDeleteProductTaxRates(taxRateId) - * // ... - * - * const handleRemoveProduct = (productIds: string[]) => { - * removeProduct.mutate({ - * products: productIds, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.products) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/tax-rates/{id}/products/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "products": [ - * "{product_id}" - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Tax Rates - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminTaxRatesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const value = await validator(AdminDeleteTaxRatesTaxRateProductsReq, req.body) - - const query = await validator( - AdminDeleteTaxRatesTaxRateProductsParams, - req.query - ) - - const rateService: TaxRateService = req.scope.resolve("taxRateService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await rateService - .withTransaction(transactionManager) - .removeFromProduct(req.params.id, value.products) - }) - - const config = getRetrieveConfig( - query.fields as (keyof TaxRate)[], - query.expand - ) - const rate = await rateService.retrieve(req.params.id, config) - const data = pickByConfig(rate, config) - - res.json({ tax_rate: data }) -} - -/** - * @schema AdminDeleteTaxRatesTaxRateProductsReq - * type: object - * description: "The details of the products to remove their associated with the tax rate." - * required: - * - products - * properties: - * products: - * type: array - * description: "The IDs of the products to remove their association with this tax rate." - * items: - * type: string - */ -export class AdminDeleteTaxRatesTaxRateProductsReq { - @IsArray() - products: string[] -} - -/** - * {@inheritDoc FindParams} - */ -export class AdminDeleteTaxRatesTaxRateProductsParams { - /** - * {@inheritDoc FindParams.expand} - */ - @IsArray() - @IsOptional() - expand?: string[] - - /** - * {@inheritDoc FindParams.fields} - */ - @IsArray() - @IsOptional() - fields?: string[] -} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/remove-from-shipping-options.ts b/packages/medusa/src/api/routes/admin/tax-rates/remove-from-shipping-options.ts deleted file mode 100644 index 463e81cdb8..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/remove-from-shipping-options.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { IsArray, IsOptional } from "class-validator" -import { getRetrieveConfig, pickByConfig } from "./utils/get-query-config" - -import { EntityManager } from "typeorm" -import { TaxRate } from "../../../.." -import { TaxRateService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [delete] /admin/tax-rates/{id}/shipping-options/batch - * operationId: "DeleteTaxRatesTaxRateShippingOptions" - * summary: "Remove Shipping Options from Rate" - * description: "Remove shipping options from a tax rate. This only removes the association between the shipping options and the tax rate. It does not delete the shipping options." - * parameters: - * - (path) id=* {string} ID of the tax rate. - * - in: query - * name: fields - * description: "Comma-separated fields that should be included in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * - in: query - * name: expand - * description: "Comma-separated relations that should be expanded in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteTaxRatesTaxRateShippingOptionsReq" - * x-codegen: - * method: removeShippingOptions - * queryParams: AdminDeleteTaxRatesTaxRateShippingOptionsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.removeShippingOptions(taxRateId, { - * shipping_options: [ - * shippingOptionId - * ] - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteShippingTaxRates } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const removeShippingOptions = useAdminDeleteShippingTaxRates( - * taxRateId - * ) - * // ... - * - * const handleRemoveShippingOptions = ( - * shippingOptionIds: string[] - * ) => { - * removeShippingOptions.mutate({ - * shipping_options: shippingOptionIds, - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.shipping_options) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/tax-rates/{id}/shipping-options/batch' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "shipping_options": [ - * "{shipping_option_id}" - * ] - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Tax Rates - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminTaxRatesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const value = await validator( - AdminDeleteTaxRatesTaxRateShippingOptionsReq, - req.body - ) - - const query = await validator( - AdminDeleteTaxRatesTaxRateShippingOptionsParams, - req.query - ) - - const rateService: TaxRateService = req.scope.resolve("taxRateService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await rateService - .withTransaction(transactionManager) - .removeFromShippingOption(req.params.id, value.shipping_options) - }) - - const config = getRetrieveConfig( - query.fields as (keyof TaxRate)[], - query.expand - ) - const rate = await rateService.retrieve(req.params.id, config) - const data = pickByConfig(rate, config) - - res.json({ tax_rate: data }) -} - -/** - * @schema AdminDeleteTaxRatesTaxRateShippingOptionsReq - * type: object - * description: "The details of the shipping options to remove their associate with the tax rate." - * required: - * - shipping_options - * properties: - * shipping_options: - * type: array - * description: "The IDs of the shipping options to remove their association with this tax rate." - * items: - * type: string - */ -export class AdminDeleteTaxRatesTaxRateShippingOptionsReq { - @IsArray() - shipping_options: string[] -} - -/** - * {@inheritDoc FindParams} - */ -export class AdminDeleteTaxRatesTaxRateShippingOptionsParams { - /** - * {@inheritDoc FindParams.expand} - */ - @IsArray() - @IsOptional() - expand?: string[] - - /** - * {@inheritDoc FindParams.fields} - */ - @IsArray() - @IsOptional() - fields?: string[] -} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/update-tax-rate.ts b/packages/medusa/src/api/routes/admin/tax-rates/update-tax-rate.ts deleted file mode 100644 index d204eb70ef..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/update-tax-rate.ts +++ /dev/null @@ -1,250 +0,0 @@ -import { IsArray, IsNumber, IsOptional, IsString } from "class-validator" -import { getRetrieveConfig, pickByConfig } from "./utils/get-query-config" - -import { omit } from "lodash" -import { isDefined } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { TaxRate } from "../../../.." -import { TaxRateService } from "../../../../services" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /admin/tax-rates/{id} - * operationId: "PostTaxRatesTaxRate" - * summary: "Update a Tax Rate" - * description: "Update a Tax Rate's details." - * parameters: - * - (path) id=* {string} ID of the tax rate. - * - in: query - * name: fields - * description: "Comma-separated fields that should be included in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * - in: query - * name: expand - * description: "Comma-separated relations that should be expanded in the returned tax rate." - * style: form - * explode: false - * schema: - * type: array - * items: - * type: string - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostTaxRatesTaxRateReq" - * x-codegen: - * method: update - * queryParams: AdminPostTaxRatesTaxRateParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.taxRates.update(taxRateId, { - * name: "New Tax Rate" - * }) - * .then(({ tax_rate }) => { - * console.log(tax_rate.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateTaxRate } from "medusa-react" - * - * type Props = { - * taxRateId: string - * } - * - * const TaxRate = ({ taxRateId }: Props) => { - * const updateTaxRate = useAdminUpdateTaxRate(taxRateId) - * // ... - * - * const handleUpdate = ( - * name: string - * ) => { - * updateTaxRate.mutate({ - * name - * }, { - * onSuccess: ({ tax_rate }) => { - * console.log(tax_rate.name) - * } - * }) - * } - * - * // ... - * } - * - * export default TaxRate - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/tax-rates/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "name": "New Tax Rate" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Tax Rates - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminTaxRatesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const value = await validator(AdminPostTaxRatesTaxRateReq, req.body) - - const query = await validator(AdminPostTaxRatesTaxRateParams, req.query) - - const manager: EntityManager = req.scope.resolve("manager") - const rateService: TaxRateService = req.scope.resolve("taxRateService") - - await manager.transaction(async (tx) => { - const txRateService = rateService.withTransaction(tx) - await txRateService.update( - req.params.id, - omit(value, ["products", "product_types", "shipping_options"]) - ) - - if (isDefined(value.products)) { - await txRateService.addToProduct(req.params.id, value.products, true) - } - - if (isDefined(value.product_types)) { - await txRateService.addToProductType( - req.params.id, - value.product_types, - true - ) - } - - if (isDefined(value.shipping_options)) { - await txRateService.addToShippingOption( - req.params.id, - value.shipping_options, - true - ) - } - }) - - const config = getRetrieveConfig( - query.fields as (keyof TaxRate)[], - query.expand - ) - - const rate = await rateService.retrieve(req.params.id, config) - const data = pickByConfig(rate, config) - - res.json({ tax_rate: data }) -} - -/** - * @schema AdminPostTaxRatesTaxRateReq - * type: object - * description: "The details to update of the tax rate." - * properties: - * code: - * type: string - * description: "The code of the tax rate." - * name: - * type: string - * description: "The name of the tax rate." - * region_id: - * type: string - * description: "The ID of the Region that the tax rate belongs to." - * rate: - * type: number - * description: "The numeric rate to charge." - * products: - * type: array - * description: "The IDs of the products associated with this tax rate" - * items: - * type: string - * shipping_options: - * type: array - * description: "The IDs of the shipping options associated with this tax rate" - * items: - * type: string - * product_types: - * type: array - * description: "The IDs of the types of product types associated with this tax rate" - * items: - * type: string - */ -export class AdminPostTaxRatesTaxRateReq { - @IsOptional() - @IsString() - code?: string - - @IsOptional() - @IsString() - name?: string - - @IsOptional() - @IsString() - region_id?: string - - @IsOptional() - @IsNumber() - rate?: number | null - - @IsOptional() - @IsArray() - products?: string[] - - @IsOptional() - @IsArray() - shipping_options?: string[] - - @IsOptional() - @IsArray() - product_types?: string[] -} - -/** - * {@inheritDoc FindParams} - */ -export class AdminPostTaxRatesTaxRateParams { - /** - * {@inheritDoc FindParams.expand} - */ - @IsArray() - @IsOptional() - expand?: string[] - - /** - * {@inheritDoc FindParams.fields} - */ - @IsArray() - @IsOptional() - fields?: string[] -} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/utils/get-query-config.ts b/packages/medusa/src/api/routes/admin/tax-rates/utils/get-query-config.ts deleted file mode 100644 index 55a530c2f0..0000000000 --- a/packages/medusa/src/api/routes/admin/tax-rates/utils/get-query-config.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { pick } from "lodash" -import { defaultAdminTaxRatesFields, defaultAdminTaxRatesRelations } from "../" -import { TaxRate } from "../../../../.." -import { FindConfig } from "../../../../../types/common" -import { isDefined } from "medusa-core-utils" - -export function pickByConfig( - obj: T | T[], - config: FindConfig -): Partial | Partial[] { - const fields = [...(config.select ?? []), ...(config.relations ?? [])] - - if (fields.length) { - if (Array.isArray(obj)) { - return obj.map((o) => pick(o, fields)) - } else { - return pick(obj, fields) - } - } - return obj -} - -export function getRetrieveConfig( - fields?: (keyof TaxRate)[], - expand?: string[] -): FindConfig { - let includeFields: (keyof TaxRate)[] = [] - if (isDefined(fields)) { - const fieldSet = new Set(fields) - fieldSet.add("id") - includeFields = Array.from(fieldSet) as (keyof TaxRate)[] - } - - let expandFields: string[] = [] - if (isDefined(expand)) { - expandFields = expand - } - - return { - select: includeFields.length ? includeFields : defaultAdminTaxRatesFields, - relations: expandFields.length - ? expandFields - : defaultAdminTaxRatesRelations, - } -} - -export function getListConfig( - fields?: (keyof TaxRate)[], - expand?: string[], - limit = 50, - offset = 0, - order?: { [k: symbol]: "DESC" | "ASC" } -): FindConfig { - let includeFields: (keyof TaxRate)[] = [] - if (isDefined(fields)) { - const fieldSet = new Set(fields) - // Ensure created_at is included, since we are sorting on this - fieldSet.add("created_at") - fieldSet.add("id") - includeFields = Array.from(fieldSet) as (keyof TaxRate)[] - } - - let expandFields: string[] = [] - if (isDefined(expand)) { - expandFields = expand - } - - const orderBy: Record = order ?? { - created_at: "DESC", - } - - return { - select: includeFields.length ? includeFields : defaultAdminTaxRatesFields, - relations: expandFields.length - ? expandFields - : defaultAdminTaxRatesRelations, - skip: offset, - take: limit, - order: orderBy, - } -} diff --git a/packages/medusa/src/api/routes/admin/uploads/create-protected-upload.ts b/packages/medusa/src/api/routes/admin/uploads/create-protected-upload.ts deleted file mode 100644 index 2e286f0afa..0000000000 --- a/packages/medusa/src/api/routes/admin/uploads/create-protected-upload.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { promiseAll } from "@medusajs/utils" -import fs from "fs" -import { IFileService } from "../../../../interfaces" - -/** - * @oas [post] /admin/uploads/protected - * operationId: "PostUploadsProtected" - * summary: "Protected File Upload" - * description: "Upload at least one file to an ACL or a non-public bucket. The file upload is handled by the file service installed on the Medusa backend." - * x-authenticated: true - * requestBody: - * content: - * multipart/form-data: - * schema: - * type: object - * properties: - * files: - * type: string - * format: binary - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.uploads.createProtected(file) - * .then(({ uploads }) => { - * console.log(uploads.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUploadProtectedFile } from "medusa-react" - * - * const UploadFile = () => { - * const uploadFile = useAdminUploadProtectedFile() - * // ... - * - * const handleFileUpload = (file: File) => { - * uploadFile.mutate(file, { - * onSuccess: ({ uploads }) => { - * console.log(uploads[0].key) - * } - * }) - * } - * - * // ... - * } - * - * export default UploadFile - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/uploads/protected' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: image/jpeg' \ - * --form 'files=@""' \ - * --form 'files=@""' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Uploads - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminUploadsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const fileService: IFileService = req.scope.resolve("fileService") - - const result = await promiseAll( - req.files.map(async (f) => { - return fileService.uploadProtected(f).then((result) => { - fs.unlinkSync(f.path) - return result - }) - }) - ) - - res.status(200).json({ uploads: result }) -} - -export class IAdminPostUploadsFileReq { - originalName: string - path: string -} diff --git a/packages/medusa/src/api/routes/admin/uploads/create-upload.ts b/packages/medusa/src/api/routes/admin/uploads/create-upload.ts deleted file mode 100644 index cdc7755f02..0000000000 --- a/packages/medusa/src/api/routes/admin/uploads/create-upload.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { promiseAll } from "@medusajs/utils" -import fs from "fs" - -/** - * @oas [post] /admin/uploads - * operationId: "PostUploads" - * summary: "Upload Files" - * description: "Upload at least one file to a public bucket or storage. The file upload is handled by the file service installed on the Medusa backend." - * x-authenticated: true - * requestBody: - * content: - * multipart/form-data: - * schema: - * type: object - * properties: - * files: - * type: string - * format: binary - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.uploads.create(file) - * .then(({ uploads }) => { - * console.log(uploads.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUploadFile } from "medusa-react" - * - * const UploadFile = () => { - * const uploadFile = useAdminUploadFile() - * // ... - * - * const handleFileUpload = (file: File) => { - * uploadFile.mutate(file, { - * onSuccess: ({ uploads }) => { - * console.log(uploads[0].key) - * } - * }) - * } - * - * // ... - * } - * - * export default UploadFile - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/uploads' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: image/jpeg' \ - * --form 'files=@""' \ - * --form 'files=@""' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Uploads - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminUploadsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const fileService = req.scope.resolve("fileService") - - const result = await promiseAll( - req.files.map(async (f) => { - return fileService.upload(f).then((result) => { - fs.unlinkSync(f.path) - return result - }) - }) - ) - - res.status(200).json({ uploads: result }) -} - -export class IAdminPostUploadsFileReq { - originalName: string - path: string -} diff --git a/packages/medusa/src/api/routes/admin/uploads/delete-upload.ts b/packages/medusa/src/api/routes/admin/uploads/delete-upload.ts deleted file mode 100644 index 085bebe351..0000000000 --- a/packages/medusa/src/api/routes/admin/uploads/delete-upload.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { IsString } from "class-validator" -import { Request, Response } from "express" -import { IFileService } from "../../../../interfaces" -/** - * @oas [delete] /admin/uploads - * operationId: "DeleteUploads" - * summary: "Delete an Uploaded File" - * description: "Delete an uploaded file from storage. The file is deleted using the installed file service on the Medusa backend." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteUploadsReq" - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.uploads.delete({ - * file_key - * }) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteFile } from "medusa-react" - * - * const Image = () => { - * const deleteFile = useAdminDeleteFile() - * // ... - * - * const handleDeleteFile = (fileKey: string) => { - * deleteFile.mutate({ - * file_key: fileKey - * }, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default Image - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/uploads' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "file_key": "{file_key}" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Uploads - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteUploadsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const validated = req.validatedBody as AdminDeleteUploadsReq - - const fileService: IFileService = req.scope.resolve("fileService") - - await fileService.delete({ - fileKey: validated.file_key, - }) - - res - .status(200) - .send({ id: validated.file_key, object: "file", deleted: true }) -} - -/** - * @schema AdminDeleteUploadsReq - * type: object - * description: "The details of the file to delete." - * required: - * - file_key - * properties: - * file_key: - * description: "key of the file to delete. This is obtained when you first uploaded the file, or by the file service if you used it directly." - * type: string - */ -export class AdminDeleteUploadsReq { - @IsString() - file_key: string -} diff --git a/packages/medusa/src/api/routes/admin/uploads/get-download-url.ts b/packages/medusa/src/api/routes/admin/uploads/get-download-url.ts deleted file mode 100644 index 3b5c5af5bf..0000000000 --- a/packages/medusa/src/api/routes/admin/uploads/get-download-url.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { AbstractFileService } from "../../../../interfaces" -import { IsString } from "class-validator" - -/** - * @oas [post] /admin/uploads/download-url - * operationId: "PostUploadsDownloadUrl" - * summary: "Get a File's Download URL" - * description: "Create and retrieve a presigned or public download URL for a file. The URL creation is handled by the file service installed on the Medusa backend." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminPostUploadsDownloadUrlReq" - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.uploads.getPresignedDownloadUrl({ - * file_key - * }) - * .then(({ download_url }) => { - * console.log(download_url); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreatePresignedDownloadUrl } from "medusa-react" - * - * const Image = () => { - * const createPresignedUrl = useAdminCreatePresignedDownloadUrl() - * // ... - * - * const handlePresignedUrl = (fileKey: string) => { - * createPresignedUrl.mutate({ - * file_key: fileKey - * }, { - * onSuccess: ({ download_url }) => { - * console.log(download_url) - * } - * }) - * } - * - * // ... - * } - * - * export default Image - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/uploads/download-url' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "file_key": "{file_key}" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Uploads - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminUploadsDownloadUrlRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const fileService: AbstractFileService = req.scope.resolve("fileService") - - const url = await fileService.getPresignedDownloadUrl({ - fileKey: (req.validatedBody as AdminPostUploadsDownloadUrlReq).file_key, - }) - - res.status(200).send({ download_url: url }) -} - -/** - * @schema AdminPostUploadsDownloadUrlReq - * type: object - * description: "The details of the file to retrieve its download URL." - * required: - * - file_key - * properties: - * file_key: - * description: "key of the file to obtain the download link for. This is obtained when you first uploaded the file, or by the file service if you used it directly." - * type: string - */ -export class AdminPostUploadsDownloadUrlReq { - @IsString() - file_key: string -} diff --git a/packages/medusa/src/api/routes/admin/uploads/index.ts b/packages/medusa/src/api/routes/admin/uploads/index.ts deleted file mode 100644 index d7e27d3984..0000000000 --- a/packages/medusa/src/api/routes/admin/uploads/index.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Router } from "express" -import multer from "multer" -import { DeleteResponse } from "../../../../types/common" - -import middlewares, { transformBody } from "../../../middlewares" -import { AdminDeleteUploadsReq } from "./delete-upload" -import { AdminPostUploadsDownloadUrlReq } from "./get-download-url" -import { FileServiceUploadResult } from "@medusajs/types" - -const route = Router() -const upload = multer({ dest: "uploads/" }) - -export default (app) => { - app.use("/uploads", route) - - route.post( - "/", - upload.array("files"), - middlewares.wrap(require("./create-upload").default) - ) - - route.post( - "/protected", - upload.array("files"), - middlewares.wrap(require("./create-protected-upload").default) - ) - - route.delete( - "/", - transformBody(AdminDeleteUploadsReq), - middlewares.wrap(require("./delete-upload").default) - ) - - route.post( - "/download-url", - transformBody(AdminPostUploadsDownloadUrlReq), - middlewares.wrap(require("./get-download-url").default) - ) - - return app -} - -/** - * @schema AdminUploadsRes - * type: object - * description: "The list of uploaded files." - * required: - * - uploads - * properties: - * uploads: - * type: array - * description: "Uploaded files details." - * items: - * type: object - * required: - * - url - * - key - * properties: - * url: - * description: The URL of the uploaded file. - * type: string - * format: uri - * key: - * description: The key of the file that is identifiable by the file service. It can be used later to retrieve or manipulate the file. - * type: string - */ -export type AdminUploadsRes = { - uploads: FileServiceUploadResult[] -} - -/** - * @schema AdminDeleteUploadsRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The file key of the upload deleted - * object: - * type: string - * description: The type of the object that was deleted. - * default: file - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminDeleteUploadsRes = DeleteResponse - -/** - * @schema AdminUploadsDownloadUrlRes - * type: object - * description: "The download URL details." - * required: - * - download_url - * properties: - * download_url: - * description: The Download URL of the file - * type: string - */ -export type AdminUploadsDownloadUrlRes = { - download_url: string -} - -export * from "./create-upload" -export * from "./delete-upload" -export * from "./get-download-url" diff --git a/packages/medusa/src/api/routes/admin/users/__tests__/create-user.js b/packages/medusa/src/api/routes/admin/users/__tests__/create-user.js deleted file mode 100644 index 8da1e6c167..0000000000 --- a/packages/medusa/src/api/routes/admin/users/__tests__/create-user.js +++ /dev/null @@ -1,71 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { UserServiceMock } from "../../../../../services/__mocks__/user" - -describe("POST /admin/users", () => { - describe("successfully creates a user", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/users", { - payload: { - email: "oliver@test.dk", - password: "123456789", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls UserService create", () => { - expect(UserServiceMock.create).toHaveBeenCalledTimes(1) - expect(UserServiceMock.create).toHaveBeenCalledWith( - { - email: "oliver@test.dk", - }, - "123456789" - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the user", () => { - expect(subject.body.user.id).toEqual(IdMap.getId("test-user")) - }) - }) - - describe("handles failed create operation", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", "/admin/users", { - payload: { - email: "olivertest.dk", - password: "123456789", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 400 on invalid email", () => { - expect(subject.status).toEqual(400) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/users/__tests__/delete-user.js b/packages/medusa/src/api/routes/admin/users/__tests__/delete-user.js deleted file mode 100644 index 691a1900a2..0000000000 --- a/packages/medusa/src/api/routes/admin/users/__tests__/delete-user.js +++ /dev/null @@ -1,46 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { UserServiceMock } from "../../../../../services/__mocks__/user" - -describe("DELETE /admin/users/:id", () => { - describe("successfully deletes a user", () => { - let subject - - beforeAll(async () => { - subject = await request( - "DELETE", - `/admin/users/${IdMap.getId("delete-user")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls UserService create", () => { - expect(UserServiceMock.delete).toHaveBeenCalledTimes(1) - expect(UserServiceMock.delete).toHaveBeenCalledWith( - IdMap.getId("delete-user") - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns correct delete data", () => { - expect(subject.body).toEqual({ - id: IdMap.getId("delete-user"), - object: "user", - deleted: true, - }) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/users/__tests__/get-user.js b/packages/medusa/src/api/routes/admin/users/__tests__/get-user.js deleted file mode 100644 index 9b96d5bb7d..0000000000 --- a/packages/medusa/src/api/routes/admin/users/__tests__/get-user.js +++ /dev/null @@ -1,42 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { UserServiceMock } from "../../../../../services/__mocks__/user" - -describe("GET /admin/users/:id", () => { - describe("successfully gets a user", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/admin/users/${IdMap.getId("test-user")}`, - { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls UserService retrieve", () => { - expect(UserServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(UserServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("test-user") - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the user", () => { - expect(subject.body.user.id).toEqual(IdMap.getId("test-user")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/users/__tests__/list-users.js b/packages/medusa/src/api/routes/admin/users/__tests__/list-users.js deleted file mode 100644 index 8e84998988..0000000000 --- a/packages/medusa/src/api/routes/admin/users/__tests__/list-users.js +++ /dev/null @@ -1,35 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { UserServiceMock } from "../../../../../services/__mocks__/user" - -describe("GET /admin/users", () => { - describe("successful retrieval", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/admin/users`, { - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service retrieve", () => { - expect(UserServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(UserServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - expect.objectContaining({ - order: { created_at: "DESC" }, - skip: 0, - take: 50, - }) - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/users/__tests__/reset-password-token.js b/packages/medusa/src/api/routes/admin/users/__tests__/reset-password-token.js deleted file mode 100644 index 4d55b5226b..0000000000 --- a/packages/medusa/src/api/routes/admin/users/__tests__/reset-password-token.js +++ /dev/null @@ -1,37 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { UserServiceMock } from "../../../../../services/__mocks__/user" - -describe("POST /admin/users/password-token", () => { - describe("successfully generates reset password token", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/admin/users/password-token`, { - payload: { - email: "vandijk@test.dk", - }, - }) - }) - - it("calls UserService retrieve", () => { - expect(UserServiceMock.retrieveByEmail).toHaveBeenCalledTimes(1) - expect(UserServiceMock.retrieveByEmail).toHaveBeenCalledWith( - "vandijk@test.dk" - ) - }) - - it("calls UserService generateResetPasswordToken", () => { - expect(UserServiceMock.generateResetPasswordToken).toHaveBeenCalledTimes( - 1 - ) - expect(UserServiceMock.generateResetPasswordToken).toHaveBeenCalledWith( - IdMap.getId("vandijk") - ) - }) - - it("returns 204", () => { - expect(subject.status).toEqual(204) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/users/__tests__/reset-password.js b/packages/medusa/src/api/routes/admin/users/__tests__/reset-password.js deleted file mode 100644 index 1054578fb4..0000000000 --- a/packages/medusa/src/api/routes/admin/users/__tests__/reset-password.js +++ /dev/null @@ -1,51 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import jwt from "jsonwebtoken" -import { request } from "../../../../../helpers/test-request" -import { UserServiceMock } from "../../../../../services/__mocks__/user" - -describe("POST /admin/users/reset-password", () => { - describe("successfully resets password", () => { - let subject - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("calls UserService setPassword", async () => { - const exp = Math.floor(Date.now() / 1000) + 60 * 15 - - subject = await request("POST", `/admin/users/reset-password`, { - payload: { - email: "vandijk@test.dk", - token: jwt.sign( - { - user_id: IdMap.getId("vandijk"), - name: "Virgil Van Dijk", - email: "vandijk@test.dk", - exp, - }, - "1234" - ), - password: "new-password", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - }) - expect(UserServiceMock.setPassword_).toHaveBeenCalledTimes(1) - expect(UserServiceMock.setPassword_).toHaveBeenCalledWith( - IdMap.getId("vandijk"), - "new-password" - ) - }) - - it("returns updated user", () => { - expect(subject.body.user.id).toEqual(IdMap.getId("vandijk")) - }) - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/users/__tests__/update-user.js b/packages/medusa/src/api/routes/admin/users/__tests__/update-user.js deleted file mode 100644 index 15c461e881..0000000000 --- a/packages/medusa/src/api/routes/admin/users/__tests__/update-user.js +++ /dev/null @@ -1,42 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { UserServiceMock } from "../../../../../services/__mocks__/user" - -describe("POST /admin/users/:id", () => { - describe("successful update", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/admin/users/${IdMap.getId("test-user")}`, - { - payload: { - first_name: "Oliver", - last_name: "Juhl", - }, - adminSession: { - jwt: { - userId: IdMap.getId("admin_user"), - }, - }, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls service method", () => { - expect(UserServiceMock.update).toHaveBeenCalledTimes(1) - expect(UserServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("test-user"), - { - first_name: "Oliver", - last_name: "Juhl", - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/admin/users/create-user.ts b/packages/medusa/src/api/routes/admin/users/create-user.ts deleted file mode 100644 index b9d55a9285..0000000000 --- a/packages/medusa/src/api/routes/admin/users/create-user.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { IsEmail, IsEnum, IsOptional, IsString } from "class-validator" - -import { UserRoles } from "../../../../models/user" -import UserService from "../../../../services/user" -import _ from "lodash" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/users - * operationId: "PostUsers" - * summary: "Create a User" - * description: "Create an admin User. The user has the same privileges as all admin users, and will be able to authenticate and perform admin functionalities right after creation." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminCreateUserRequest" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.create({ - * email: "user@example.com", - * password: "supersecret" - * }) - * .then(({ user }) => { - * console.log(user.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminCreateUser } from "medusa-react" - * - * const CreateUser = () => { - * const createUser = useAdminCreateUser() - * // ... - * - * const handleCreateUser = () => { - * createUser.mutate({ - * email: "user@example.com", - * password: "supersecret", - * }, { - * onSuccess: ({ user }) => { - * console.log(user.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateUser - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/users' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com", - * "password": "supersecret" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Users - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminUserRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminCreateUserRequest, req.body) - - const userService: UserService = req.scope.resolve("userService") - const data = _.omit(validated, ["password"]) - - const manager: EntityManager = req.scope.resolve("manager") - const user = await manager.transaction(async (transactionManager) => { - return await userService - .withTransaction(transactionManager) - .create(data, validated.password) - }) - - res.status(200).json({ user: _.omit(user, ["password_hash"]) }) -} - -/** - * @schema AdminCreateUserRequest - * type: object - * required: - * - email - * - password - * properties: - * email: - * description: "The User's email." - * type: string - * format: email - * first_name: - * description: "The first name of the User." - * type: string - * last_name: - * description: "The last name of the User." - * type: string - * role: - * description: "The role assigned to the user. These roles don't provide any different privileges." - * type: string - * enum: [admin, member, developer] - * password: - * description: "The User's password." - * type: string - * format: password - */ -export class AdminCreateUserRequest { - @IsEmail() - email: string - - @IsOptional() - @IsString() - first_name?: string - - @IsOptional() - @IsString() - last_name?: string - - @IsEnum(UserRoles) - @IsOptional() - role?: UserRoles - - @IsString() - password: string -} diff --git a/packages/medusa/src/api/routes/admin/users/delete-user.ts b/packages/medusa/src/api/routes/admin/users/delete-user.ts deleted file mode 100644 index 586ec426db..0000000000 --- a/packages/medusa/src/api/routes/admin/users/delete-user.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { EntityManager } from "typeorm" -import UserService from "../../../../services/user" - -/** - * @oas [delete] /admin/users/{id} - * operationId: "DeleteUsersUser" - * summary: "Delete a User" - * description: "Delete a User. Once deleted, the user will not be able to authenticate or perform admin functionalities." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the User. - * x-codegen: - * method: delete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.delete(userId) - * .then(({ id, object, deleted }) => { - * console.log(id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminDeleteUser } from "medusa-react" - * - * type Props = { - * userId: string - * } - * - * const User = ({ userId }: Props) => { - * const deleteUser = useAdminDeleteUser(userId) - * // ... - * - * const handleDeleteUser = () => { - * deleteUser.mutate(void 0, { - * onSuccess: ({ id, object, deleted }) => { - * console.log(id) - * } - * }) - * } - * - * // ... - * } - * - * export default User - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/admin/users/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Users - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminDeleteUserRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { user_id } = req.params - - const userService: UserService = req.scope.resolve("userService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await userService.withTransaction(transactionManager).delete(user_id) - }) - - res.status(200).send({ - id: user_id, - object: "user", - deleted: true, - }) -} diff --git a/packages/medusa/src/api/routes/admin/users/get-user.ts b/packages/medusa/src/api/routes/admin/users/get-user.ts deleted file mode 100644 index 2c2781d137..0000000000 --- a/packages/medusa/src/api/routes/admin/users/get-user.ts +++ /dev/null @@ -1,86 +0,0 @@ -import UserService from "../../../../services/user" - -/** - * @oas [get] /admin/users/{id} - * operationId: "GetUsersUser" - * summary: "Get a User" - * description: "Retrieve an admin user's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the User. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.retrieve(userId) - * .then(({ user }) => { - * console.log(user.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUser } from "medusa-react" - * - * type Props = { - * userId: string - * } - * - * const User = ({ userId }: Props) => { - * const { user, isLoading } = useAdminUser( - * userId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {user && {user.first_name} {user.last_name}} - *
- * ) - * } - * - * export default User - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/users/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Users - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminUserRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { user_id } = req.params - - const userService: UserService = req.scope.resolve("userService") - - const user = await userService.retrieve(user_id) - res.json({ user }) -} diff --git a/packages/medusa/src/api/routes/admin/users/index.ts b/packages/medusa/src/api/routes/admin/users/index.ts deleted file mode 100644 index 0b62eb6c49..0000000000 --- a/packages/medusa/src/api/routes/admin/users/index.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { PaginatedResponse } from "@medusajs/types" -import { Router } from "express" -import { User } from "../../../../models/user" -import { DeleteResponse } from "../../../../types/common" -import middlewares, { transformQuery } from "../../../middlewares" -import { AdminGetUsersParams } from "./list-users" - -export const unauthenticatedUserRoutes = (app) => { - const route = Router() - app.use("/users", route) - - route.post( - "/password-token", - middlewares.wrap(require("./reset-password-token").default) - ) - - route.post( - "/reset-password", - middlewares.wrap(require("./reset-password").default) - ) -} - -export default (app) => { - const route = Router() - app.use("/users", route) - - route.get("/:user_id", middlewares.wrap(require("./get-user").default)) - - route.post("/", middlewares.wrap(require("./create-user").default)) - - route.post("/:user_id", middlewares.wrap(require("./update-user").default)) - - route.delete("/:user_id", middlewares.wrap(require("./delete-user").default)) - - route.get( - "/", - transformQuery(AdminGetUsersParams, { - defaultFields: defaultAdminUserFields, - isList: true, - }), - middlewares.wrap(require("./list-users").default) - ) - - return app -} - -export const defaultAdminUserFields: (keyof User)[] = [ - "id", - "email", - "first_name", - "last_name", - "role", - "api_token", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -/** - * @schema AdminUserRes - * type: object - * description: "The user's details." - * required: - * - user - * properties: - * user: - * description: "User details." - * $ref: "#/components/schemas/User" - */ -export type AdminUserRes = { - user: Omit -} - -/** - * @schema AdminUsersListRes - * type: object - * description: "The list of users." - * required: - * - users - * - count - * - offset - * - limit - * properties: - * users: - * type: array - * description: "An array of users details." - * items: - * $ref: "#/components/schemas/User" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of users skipped when retrieving the users. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminUsersListRes = PaginatedResponse & { - users: Omit[] -} - -/** - * @schema AdminDeleteUserRes - * type: object - * required: - * - id - * - object - * - deleted - * properties: - * id: - * type: string - * description: The ID of the deleted user. - * object: - * type: string - * description: The type of the object that was deleted. - * default: user - * deleted: - * type: boolean - * description: Whether or not the items were deleted. - * default: true - */ -export type AdminDeleteUserRes = DeleteResponse - -export * from "./reset-password" -export * from "./reset-password-token" - -export * from "./create-user" -export * from "./delete-user" -export * from "./get-user" -export * from "./list-users" -export * from "./update-user" diff --git a/packages/medusa/src/api/routes/admin/users/list-users.ts b/packages/medusa/src/api/routes/admin/users/list-users.ts deleted file mode 100644 index cd48cb5103..0000000000 --- a/packages/medusa/src/api/routes/admin/users/list-users.ts +++ /dev/null @@ -1,278 +0,0 @@ -import { Type } from "class-transformer" -import { IsEnum, IsOptional, IsString, ValidateNested } from "class-validator" -import { Request, Response } from "express" -import UserService from "../../../../services/user" -import { - DateComparisonOperator, - extendedFindParamsMixin, -} from "../../../../types/common" -import { UserRole } from "../../../../types/user" -import { IsType } from "../../../../utils" - -/** - * @oas [get] /admin/users - * operationId: "GetUsers" - * summary: "List Users" - * description: "Retrieves a list of users. The users can be filtered by fields such as `q` or `email`. The users can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) email {string} Filter by email. - * - (query) first_name {string} Filter by first name. - * - (query) last_name {string} Filter by last name. - * - (query) q {string} Term used to search users' first name, last name, and email. - * - (query) order {string} A user field to sort-order the retrieved users by. - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by user IDs. - * schema: - * oneOf: - * - type: string - * description: ID of the user. - * - type: array - * items: - * type: string - * description: ID of a user. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: deleted_at - * description: Filter by a deletion date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - (query) offset=0 {integer} The number of users to skip when retrieving the users. - * - (query) limit=20 {integer} Limit the number of users returned. - * - (query) fields {string} Comma-separated fields that should be included in the returned users. - * x-codegen: - * method: list - * queryParams: AdminGetUsersParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.list() - * .then(({ users, limit, offset, count }) => { - * console.log(users.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUsers } from "medusa-react" - * - * const Users = () => { - * const { users, isLoading } = useAdminUsers() - * - * return ( - *
- * {isLoading && Loading...} - * {users && !users.length && No Users} - * {users && users.length > 0 && ( - *
    - * {users.map((user) => ( - *
  • {user.email}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Users - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/users' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Users - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminUsersListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const userService: UserService = req.scope.resolve("userService") - - const listConfig = req.listConfig - const filterableFields = req.filterableFields - - const [users, count] = await userService.listAndCount( - filterableFields, - listConfig - ) - - res - .status(200) - .json({ users, count, offset: listConfig.skip, limit: listConfig.take }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved users. - */ -export class AdminGetUsersParams extends extendedFindParamsMixin({ - limit: 50, - offset: 0, -}) { - /** - * IDs to filter users by. - */ - @IsOptional() - @IsType([String, [String]]) - id?: string | string[] - - /** - * Search terms to search users' first name, last name, and email. - */ - @IsOptional() - @IsString() - q?: string - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string - - /** - * Date filters to apply on the users' `update_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on the customer users' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the users' `deleted_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - deleted_at?: DateComparisonOperator - - /** - * Filter to apply on the users' `email` field. - */ - @IsOptional() - @IsString() - email?: string - - /** - * Filter to apply on the users' `first_name` field. - */ - @IsOptional() - @IsString() - first_name?: string - - /** - * Filter to apply on the users' `last_name` field. - */ - @IsOptional() - @IsString() - last_name?: string - - /** - * Filter to apply on the users' `role` field. - */ - @IsOptional() - @IsEnum(UserRole, { each: true }) - role?: UserRole - - /** - * Comma-separated fields that should be included in the returned users. - */ - @IsOptional() - @IsString() - fields?: string -} diff --git a/packages/medusa/src/api/routes/admin/users/reset-password-token.ts b/packages/medusa/src/api/routes/admin/users/reset-password-token.ts deleted file mode 100644 index 071622c654..0000000000 --- a/packages/medusa/src/api/routes/admin/users/reset-password-token.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { IsEmail } from "class-validator" -import UserService from "../../../../services/user" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/users/password-token - * operationId: "PostUsersUserPasswordToken" - * summary: "Request Password Reset" - * description: "Generate a password token for an admin user with a given email. This also triggers the `user.password_reset` event. So, if you have a Notification Service installed - * that can handle this event, a notification, such as an email, will be sent to the user. The token is triggered as part of the `user.password_reset` event's payload. - * That token must be used later to reset the password using the [Reset Password](https://docs.medusajs.com/api/admin#users_postusersuserpassword) API Route." - * externalDocs: - * description: How to reset a user's password - * url: https://docs.medusajs.com/modules/users/admin/manage-profile#reset-password - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminResetPasswordTokenRequest" - * x-codegen: - * method: sendResetPasswordToken - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.sendResetPasswordToken({ - * email: "user@example.com" - * }) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // error occurred - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminSendResetPasswordToken } from "medusa-react" - * - * const Login = () => { - * const requestPasswordReset = useAdminSendResetPasswordToken() - * // ... - * - * const handleResetPassword = ( - * email: string - * ) => { - * requestPasswordReset.mutate({ - * email - * }, { - * onSuccess: () => { - * // successful - * } - * }) - * } - * - * // ... - * } - * - * export default Login - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/users/password-token' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Users - * responses: - * 204: - * description: OK - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminResetPasswordTokenRequest, req.body) - - const userService: UserService = req.scope.resolve("userService") - const user = await userService - .retrieveByEmail(validated.email) - .catch(() => undefined) - - if (user) { - // Should call a email service provider that sends the token to the user - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await userService - .withTransaction(transactionManager) - .generateResetPasswordToken(user.id) - }) - } - - res.sendStatus(204) -} - -/** - * @schema AdminResetPasswordTokenRequest - * type: object - * description: "The details of the password reset token request." - * required: - * - email - * properties: - * email: - * description: "The User's email." - * type: string - * format: email - */ -export class AdminResetPasswordTokenRequest { - @IsEmail() - email: string -} diff --git a/packages/medusa/src/api/routes/admin/users/reset-password.ts b/packages/medusa/src/api/routes/admin/users/reset-password.ts deleted file mode 100644 index cb4938c325..0000000000 --- a/packages/medusa/src/api/routes/admin/users/reset-password.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { IsEmail, IsOptional, IsString } from "class-validator" - -import { MedusaError } from "medusa-core-utils" -import { User } from "../../../.." -import UserService from "../../../../services/user" -import _ from "lodash" -import jwt from "jsonwebtoken" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/users/reset-password - * operationId: "PostUsersUserPassword" - * summary: "Reset Password" - * description: "Reset the password of an admin User using their reset password token. A user must request to reset their password first before attempting to reset their - * password with this request." - * externalDocs: - * description: How to reset a user's password - * url: https://docs.medusajs.com/modules/users/admin/manage-profile#reset-password - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminResetPasswordRequest" - * x-codegen: - * method: resetPassword - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.resetPassword({ - * token: "supersecrettoken", - * password: "supersecret" - * }) - * .then(({ user }) => { - * console.log(user.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminResetPassword } from "medusa-react" - * - * const ResetPassword = () => { - * const resetPassword = useAdminResetPassword() - * // ... - * - * const handleResetPassword = ( - * token: string, - * password: string - * ) => { - * resetPassword.mutate({ - * token, - * password, - * }, { - * onSuccess: ({ user }) => { - * console.log(user.id) - * } - * }) - * } - * - * // ... - * } - * - * export default ResetPassword - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/users/reset-password' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "token": "supersecrettoken", - * "password": "supersecret" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Users - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminUserRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(AdminResetPasswordRequest, req.body) - - try { - const userService: UserService = req.scope.resolve("userService") - - const decoded = jwt.decode(validated.token) as payload - - let user: User - try { - user = await userService.retrieveByEmail( - validated.email || decoded?.email, - { - select: ["id", "password_hash"], - } - ) - } catch (err) { - throw new MedusaError(MedusaError.Types.INVALID_DATA, "invalid token") - } - - const verifiedToken = jwt.verify( - validated.token, - user.password_hash - ) as payload - if (!verifiedToken || verifiedToken.user_id !== user.id) { - res.status(401).send("Invalid or expired password reset token") - return - } - - const manager: EntityManager = req.scope.resolve("manager") - const userResult = await manager.transaction(async (transactionManager) => { - return await userService - .withTransaction(transactionManager) - .setPassword_(user.id, validated.password) - }) - - res.status(200).json({ user: _.omit(userResult, ["password_hash"]) }) - } catch (error) { - if (error.message === "invalid token") { - throw new MedusaError(MedusaError.Types.INVALID_DATA, error.message) - } - throw error - } -} - -export type payload = { - email: string - user_id: string - password: string -} - -/** - * @schema AdminResetPasswordRequest - * type: object - * description: "The details of the password reset request." - * required: - * - token - * - password - * properties: - * email: - * description: "The User's email." - * type: string - * format: email - * token: - * description: "The password-reset token generated when the password reset was requested." - * type: string - * password: - * description: "The User's new password." - * type: string - * format: password - */ -export class AdminResetPasswordRequest { - @IsEmail() - @IsOptional() - email?: string - - @IsString() - token: string - - @IsString() - password: string -} diff --git a/packages/medusa/src/api/routes/admin/users/update-user.ts b/packages/medusa/src/api/routes/admin/users/update-user.ts deleted file mode 100644 index c374f351f5..0000000000 --- a/packages/medusa/src/api/routes/admin/users/update-user.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { IsEnum, IsObject, IsOptional, IsString } from "class-validator" - -import { UserRoles } from "../../../../models/user" -import UserService from "../../../../services/user" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /admin/users/{id} - * operationId: "PostUsersUser" - * summary: "Update a User" - * description: "Update an admin user's details." - * parameters: - * - (path) id=* {string} The ID of the User. - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminUpdateUserRequest" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.users.update(userId, { - * first_name: "Marcellus" - * }) - * .then(({ user }) => { - * console.log(user.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminUpdateUser } from "medusa-react" - * - * type Props = { - * userId: string - * } - * - * const User = ({ userId }: Props) => { - * const updateUser = useAdminUpdateUser(userId) - * // ... - * - * const handleUpdateUser = ( - * firstName: string - * ) => { - * updateUser.mutate({ - * first_name: firstName, - * }, { - * onSuccess: ({ user }) => { - * console.log(user.first_name) - * } - * }) - * } - * - * // ... - * } - * - * export default User - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/admin/users/{id}' \ - * -H 'x-medusa-access-token: {api_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "first_name": "Marcellus" - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Users - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminUserRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { user_id } = req.params - - const validated = await validator(AdminUpdateUserRequest, req.body) - - const userService: UserService = req.scope.resolve("userService") - const manager: EntityManager = req.scope.resolve("manager") - const data = await manager.transaction(async (transactionManager) => { - return await userService - .withTransaction(transactionManager) - .update(user_id, validated) - }) - - res.status(200).json({ user: data }) -} - -/** - * @schema AdminUpdateUserRequest - * type: object - * properties: - * first_name: - * description: "The first name of the User." - * type: string - * last_name: - * description: "The last name of the User." - * type: string - * role: - * description: "The role assigned to the user. These roles don't provide any different privileges." - * type: string - * enum: [admin, member, developer] - * api_token: - * description: "The API token of the User." - * type: string - * metadata: - * description: An optional set of key-value pairs with additional information. - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class AdminUpdateUserRequest { - @IsString() - @IsOptional() - first_name?: string - - @IsString() - @IsOptional() - last_name?: string - - @IsEnum(UserRoles) - @IsOptional() - role?: UserRoles - - @IsString() - @IsOptional() - api_token?: string - - @IsObject() - @IsOptional() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/admin/variants/get-inventory.ts b/packages/medusa/src/api/routes/admin/variants/get-inventory.ts deleted file mode 100644 index d5b2f348da..0000000000 --- a/packages/medusa/src/api/routes/admin/variants/get-inventory.ts +++ /dev/null @@ -1,268 +0,0 @@ -import { - IInventoryService, - InventoryItemDTO, - InventoryLevelDTO, -} from "@medusajs/types" -import { SalesChannel } from "../../../../models" -import { - SalesChannelLocationService, - SalesChannelService, -} from "../../../../services" -import ProductVariantService from "../../../../services/product-variant" -import ProductVariantInventoryService from "../../../../services/product-variant-inventory" -import { joinLevels } from "../inventory-items/utils/join-levels" -import { promiseAll } from "@medusajs/utils" - -/** - * @oas [get] /admin/variants/{id}/inventory - * operationId: "GetVariantsVariantInventory" - * summary: "Get Variant's Inventory" - * description: "Retrieve the available inventory of a Product Variant." - * x-authenticated: true - * parameters: - * - (path) id {string} The Product Variant ID. - * x-codegen: - * method: getInventory - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.variants.getInventory(variantId) - * .then(({ variant }) => { - * console.log(variant.inventory, variant.sales_channel_availability) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminVariantsInventory } from "medusa-react" - * - * type Props = { - * variantId: string - * } - * - * const VariantInventory = ({ variantId }: Props) => { - * const { variant, isLoading } = useAdminVariantsInventory( - * variantId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {variant && variant.inventory.length === 0 && ( - * Variant doesn't have inventory details - * )} - * {variant && variant.inventory.length > 0 && ( - *
    - * {variant.inventory.map((inventory) => ( - *
  • {inventory.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default VariantInventory - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/variants/{id}/inventory' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Variants - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminGetVariantsVariantInventoryRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const inventoryService: IInventoryService = - req.scope.resolve("inventoryService") - const channelLocationService: SalesChannelLocationService = req.scope.resolve( - "salesChannelLocationService" - ) - - const channelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - const variantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - - const variant = await variantService.retrieve(id, { select: ["id"] }) - - const responseVariant: VariantInventory = { - id: variant.id, - inventory: [], - sales_channel_availability: [], - } - - const [rawChannels] = await channelService.listAndCount({}) - const channels: SalesChannelDTO[] = await promiseAll( - rawChannels.map(async (channel) => { - const locationIds = await channelLocationService.listLocationIds( - channel.id - ) - return { - ...channel, - locations: locationIds, - } - }) - ) - - const variantInventoryItems = - await productVariantInventoryService.listByVariant(variant.id) - - const inventory = - await productVariantInventoryService.listInventoryItemsByVariant(variant.id) - responseVariant.inventory = await joinLevels(inventory, [], inventoryService) - - if (inventory.length) { - responseVariant.sales_channel_availability = await promiseAll( - channels.map(async (channel) => { - if (!channel.locations.length) { - return { - channel_name: channel.name as string, - channel_id: channel.id as string, - available_quantity: 0, - } - } - - const quantity = - // eslint-disable-next-line max-len - await productVariantInventoryService.getVariantQuantityFromVariantInventoryItems( - variantInventoryItems, - channel.id - ) - - return { - channel_name: channel.name as string, - channel_id: channel.id as string, - available_quantity: quantity, - } - }) - ) - } - - res.json({ - variant: responseVariant, - }) -} - -type SalesChannelDTO = Omit & { - locations: string[] -} - -export type LevelWithAvailability = InventoryLevelDTO & { - available_quantity: number -} - -/** - * @schema ResponseInventoryItem - * allOf: - * - $ref: "#/components/schemas/InventoryItemDTO" - * - type: object - * properties: - * location_levels: - * type: array - * description: The inventory's location levels. - * items: - * allOf: - * - $ref: "#/components/schemas/InventoryItemDTO" - * - type: object - * required: - * - available_quantity - * properties: - * available_quantity: - * description: The available quantity in the inventory location. - * type: number - */ -export type ResponseInventoryItem = Partial & { - location_levels?: LevelWithAvailability[] -} - -/** - * @schema VariantInventory - * type: object - * required: - * - id - * - inventory - * - sales_channel_availability - * properties: - * id: - * description: the ID of the variant - * type: string - * inventory: - * description: The inventory details. - * $ref: "#/components/schemas/ResponseInventoryItem" - * sales_channel_availability: - * type: array - * description: Details about the variant's inventory availability in sales channels. - * items: - * type: object - * required: - * - channel_name - * - channel_id - * - available_quantity - * properties: - * channel_name: - * description: Sales channel's name - * type: string - * channel_id: - * description: Sales channel's ID - * type: string - * available_quantity: - * description: Available quantity in the sales channel - * type: number - */ -export type VariantInventory = { - id: string - inventory: ResponseInventoryItem[] - sales_channel_availability: { - channel_name: string - channel_id: string - available_quantity: number - }[] -} - -/** - * @schema AdminGetVariantsVariantInventoryRes - * type: object - * description: "The variant's inventory details." - * properties: - * variant: - * type: object - * description: "The product variant's inventory details." - * $ref: "#/components/schemas/VariantInventory" - */ -export type AdminGetVariantsVariantInventoryRes = { - variant: VariantInventory -} diff --git a/packages/medusa/src/api/routes/admin/variants/get-variant.ts b/packages/medusa/src/api/routes/admin/variants/get-variant.ts deleted file mode 100644 index 226c7e1bc7..0000000000 --- a/packages/medusa/src/api/routes/admin/variants/get-variant.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { PricingService, ProductVariantService } from "../../../../services" - -import { FindParams } from "../../../../types/common" - -/** - * @oas [get] /admin/variants/{id} - * operationId: "GetVariantsVariant" - * summary: "Get a Product variant" - * description: "Retrieve a product variant's details." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The ID of the product variant. - * - (query) expand {string} "Comma-separated relations that should be expanded in the returned product variant." - * - (query) fields {string} "Comma-separated fields that should be included in the returned product variant." - * x-codegen: - * method: retrieve - * queryParams: AdminGetVariantParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.variants.retrieve(variantId) - * .then(({ variant }) => { - * console.log(variant.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminVariant } from "medusa-react" - * - * type Props = { - * variantId: string - * } - * - * const Variant = ({ variantId }: Props) => { - * const { variant, isLoading } = useAdminVariant( - * variantId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {variant && {variant.title}} - *
- * ) - * } - * - * export default Variant - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/variants/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Variants - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminVariantsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const productVariantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - const pricingService: PricingService = req.scope.resolve("pricingService") - - const rawVariant = await productVariantService.retrieve( - id, - req.retrieveConfig - ) - - const [variant] = await pricingService.setAdminVariantPricing([rawVariant]) - - res.status(200).json({ variant }) -} - -export class AdminGetVariantParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/variants/index.ts b/packages/medusa/src/api/routes/admin/variants/index.ts deleted file mode 100644 index b9cf659863..0000000000 --- a/packages/medusa/src/api/routes/admin/variants/index.ts +++ /dev/null @@ -1,135 +0,0 @@ -import middlewares, { transformQuery } from "../../../middlewares" - -import { AdminGetVariantParams } from "./get-variant" -import { AdminGetVariantsParams } from "./list-variants" -import { PaginatedResponse } from "../../../../types/common" -import { PricedVariant } from "../../../../types/pricing" -import { ProductVariant } from "../../../../models/product-variant" -import { Router } from "express" -import { checkRegisteredModules } from "../../../middlewares/check-registered-modules" - -const route = Router() - -export default (app) => { - app.use("/variants", route) - - route.get( - "/", - transformQuery(AdminGetVariantsParams, { - defaultRelations: defaultAdminVariantRelations, - defaultFields: defaultAdminVariantFields, - isList: true, - }), - middlewares.wrap(require("./list-variants").default) - ) - - route.get( - "/:id", - transformQuery(AdminGetVariantParams, { - defaultRelations: defaultAdminVariantRelations, - defaultFields: defaultAdminVariantFields, - isList: false, - }), - middlewares.wrap(require("./get-variant").default) - ) - - route.get( - "/:id/inventory", - checkRegisteredModules({ - inventoryService: - "Inventory is not enabled. Please add an Inventory module to enable this functionality.", - }), - middlewares.wrap(require("./get-inventory").default) - ) - - return app -} - -export const defaultAdminVariantRelations = ["product", "prices", "options"] - -export const defaultAdminVariantFields: (keyof ProductVariant)[] = [ - "id", - "title", - "product_id", - "sku", - "barcode", - "ean", - "upc", - "inventory_quantity", - "allow_backorder", - "weight", - "length", - "height", - "width", - "hs_code", - "origin_country", - "mid_code", - "material", - "created_at", - "updated_at", - "metadata", - "deleted_at", - "manage_inventory", -] - -/** - * @schema AdminVariantsListRes - * type: object - * description: "The list of variants with pagination fields." - * x-expanded-relations: - * field: variants - * relations: - * - options - * - prices - * - product - * totals: - * - purchasable - * required: - * - variants - * - count - * - offset - * - limit - * properties: - * variants: - * type: array - * description: "An array of product variant details." - * items: - * $ref: "#/components/schemas/PricedVariant" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of product variants skipped when retrieving the product variants. - * limit: - * type: integer - * description: The number of items per page - */ -export type AdminVariantsListRes = PaginatedResponse & { - variants: PricedVariant[] -} - -/** - * @schema AdminVariantsRes - * type: object - * description: "The product variant's details." - * x-expanded-relations: - * field: variant - * relations: - * - options - * - prices - * - product - * required: - * - variant - * properties: - * variant: - * description: "Product variant's details." - * $ref: "#/components/schemas/PricedVariant" - */ -export type AdminVariantsRes = { - variant: PricedVariant -} - -export * from "./list-variants" -export * from "./get-variant" -export * from "./get-inventory" diff --git a/packages/medusa/src/api/routes/admin/variants/list-variants.ts b/packages/medusa/src/api/routes/admin/variants/list-variants.ts deleted file mode 100644 index f69faaebda..0000000000 --- a/packages/medusa/src/api/routes/admin/variants/list-variants.ts +++ /dev/null @@ -1,350 +0,0 @@ -import { IsBoolean, IsInt, IsOptional, IsString } from "class-validator" -import { - CartService, - PricingService, - ProductVariantInventoryService, - RegionService, - SalesChannelService, -} from "../../../../services" - -import { IInventoryService } from "@medusajs/types" -import { Transform, Type } from "class-transformer" -import { omit } from "lodash" -import ProductVariantService from "../../../../services/product-variant" -import { NumericalComparisonOperator } from "../../../../types/common" -import { AdminPriceSelectionParams } from "../../../../types/price-selection" -import { PricedVariant } from "../../../../types/pricing" -import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean" -import { IsType } from "../../../../utils/validators/is-type" - -/** - * @oas [get] /admin/variants - * operationId: "GetVariants" - * summary: "List Product Variants" - * description: "Retrieve a list of Product Variants. The product variant can be filtered by fields such as `id` or `title`. The product variant can also be paginated." - * x-authenticated: true - * parameters: - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by product variant IDs. - * schema: - * oneOf: - * - type: string - * description: A product variant ID. - * - type: array - * description: An array of product variant IDs. - * items: - * type: string - * - (query) expand {string} "Comma-separated relations that should be expanded in the returned product variants." - * - (query) fields {string} "Comma-separated fields that should be included in the returned product variants." - * - (query) offset=0 {number} The number of product variants to skip when retrieving the product variants. - * - (query) limit=100 {number} Limit the number of product variants returned. - * - (query) order {string} The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - * - (query) manage_inventory {boolean} Filter product variants by whether their inventory is managed or not. - * - (query) allow_backorder {boolean} Filter product variants by whether they are allowed to be backordered or not. - * - in: query - * name: cart_id - * style: form - * explode: false - * description: The ID of the cart to use for the price selection context. - * schema: - * type: string - * - in: query - * name: region_id - * style: form - * explode: false - * description: The ID of the region to use for the price selection context. - * schema: - * type: string - * externalDocs: - * description: "Price selection context overview" - * url: "https://docs.medusajs.com/modules/price-lists/price-selection-strategy#context-object" - * - in: query - * name: currency_code - * style: form - * explode: false - * description: The 3 character ISO currency code to use for the price selection context. - * schema: - * type: string - * externalDocs: - * description: "Price selection context overview" - * url: "https://docs.medusajs.com/modules/price-lists/price-selection-strategy#context-object" - * - in: query - * name: customer_id - * style: form - * explode: false - * description: The ID of the customer to use for the price selection context. - * schema: - * type: string - * externalDocs: - * description: "Price selection context overview" - * url: "https://docs.medusajs.com/modules/price-lists/price-selection-strategy#context-object" - * - in: query - * name: title - * style: form - * explode: false - * description: Filter by title. - * schema: - * oneOf: - * - type: string - * description: a single title to filter by - * - type: array - * description: multiple titles to filter by - * items: - * type: string - * - in: query - * name: inventory_quantity - * description: Filter by available inventory quantity - * schema: - * oneOf: - * - type: number - * description: a specific number to filter by. - * - type: object - * description: filter using less and greater than comparisons. - * properties: - * lt: - * type: number - * description: filter by inventory quantity less than this number - * gt: - * type: number - * description: filter by inventory quantity greater than this number - * lte: - * type: number - * description: filter by inventory quantity less than or equal to this number - * gte: - * type: number - * description: filter by inventory quantity greater than or equal to this number - * x-codegen: - * method: list - * queryParams: AdminGetVariantsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.admin.variants.list() - * .then(({ variants, limit, offset, count }) => { - * console.log(variants.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAdminVariants } from "medusa-react" - * - * const Variants = () => { - * const { variants, isLoading } = useAdminVariants() - * - * return ( - *
- * {isLoading && Loading...} - * {variants && !variants.length && ( - * No Variants - * )} - * {variants && variants.length > 0 && ( - *
    - * {variants.map((variant) => ( - *
  • {variant.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Variants - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/admin/variants' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Variants - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/AdminVariantsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const variantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - - const pricingService: PricingService = req.scope.resolve("pricingService") - const cartService: CartService = req.scope.resolve("cartService") - const regionService: RegionService = req.scope.resolve("regionService") - - // We need to remove the price selection params from the array of fields - const cleanFilterableFields = omit(req.filterableFields, [ - "cart_id", - "region_id", - "currency_code", - "customer_id", - ]) - - const [rawVariants, count] = await variantService.listAndCount( - cleanFilterableFields, - req.listConfig - ) - - let regionId = req.validatedQuery.region_id - let currencyCode = req.validatedQuery.currency_code - if (req.validatedQuery.cart_id) { - const cart = await cartService.retrieve(req.validatedQuery.cart_id, { - select: ["id", "region_id"], - }) - const region = await regionService.retrieve(cart.region_id, { - select: ["id", "currency_code"], - }) - regionId = region.id - currencyCode = region.currency_code - } - - let variants = await pricingService.setAdminVariantPricing(rawVariants, { - cart_id: req.validatedQuery.cart_id, - region_id: regionId, - currency_code: currencyCode, - customer_id: req.validatedQuery.customer_id, - include_discount_prices: true, - ignore_cache: true, - }) - - const inventoryService: IInventoryService | undefined = - req.scope.resolve("inventoryService") - - const salesChannelService: SalesChannelService = req.scope.resolve( - "salesChannelService" - ) - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - if (inventoryService) { - const [salesChannelsIds] = await salesChannelService.listAndCount( - {}, - { select: ["id"] } - ) - - variants = (await productVariantInventoryService.setVariantAvailability( - variants, - salesChannelsIds.map((salesChannel) => salesChannel.id) - )) as PricedVariant[] - } - - res.json({ - variants, - count, - offset: req.listConfig.offset, - limit: req.listConfig.limit, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved product variants. - */ -export class AdminGetVariantsParams extends AdminPriceSelectionParams { - /** - * Search term to search product variants' IDs. - */ - @IsOptional() - @IsString() - q?: string - - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 20 - */ - @IsOptional() - @IsInt() - @Type(() => Number) - limit?: number = 20 - - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsOptional() - @IsInt() - @Type(() => Number) - offset?: number = 0 - - /** - * {@inheritDoc FindParams.expand} - */ - @IsOptional() - @IsString() - expand?: string - - /** - * {@inheritDoc FindParams.fields} - */ - @IsString() - @IsOptional() - fields?: string - - /** - * IDs to filter product variants by. - */ - @IsOptional() - @IsType([String, [String]]) - id?: string | string[] - - /** - * Titles to filter product variants by. - */ - @IsOptional() - @IsType([String, [String]]) - title?: string | string[] - - /** - * Number filters to apply on product variants' `inventory_quantity` field. - */ - @IsOptional() - @IsType([Number, NumericalComparisonOperator]) - inventory_quantity?: number | NumericalComparisonOperator - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string - - /** - * Filter product variants by whether their inventory is managed or not. - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value.toLowerCase())) - manage_inventory?: boolean - - /** - * Filter product variants by whether they are allowed to be backordered or not. - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value.toLowerCase())) - allow_backorder?: boolean -} diff --git a/packages/medusa/src/api/routes/admin/workflows-executions/get-execution.ts b/packages/medusa/src/api/routes/admin/workflows-executions/get-execution.ts deleted file mode 100644 index 41315fba68..0000000000 --- a/packages/medusa/src/api/routes/admin/workflows-executions/get-execution.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { IWorkflowEngineService } from "@medusajs/workflows-sdk" -import { MedusaRequest, MedusaResponse } from "../../../../types/routing" - -export default async (req: MedusaRequest, res: MedusaResponse) => { - const workflowEngineService: IWorkflowEngineService = req.scope.resolve( - ModuleRegistrationName.WORKFLOW_ENGINE - ) - - const { id, workflow_id, transaction_id } = req.params - - const execution = await workflowEngineService.retrieveWorkflowExecution( - id ?? { - workflow_id, - transaction_id, - }, - { - select: req.retrieveConfig.select, - relations: req.retrieveConfig.relations, - } - ) - - res.status(200).json({ - workflow_execution: execution, - }) -} diff --git a/packages/medusa/src/api/routes/admin/workflows-executions/index.ts b/packages/medusa/src/api/routes/admin/workflows-executions/index.ts deleted file mode 100644 index c539ae5431..0000000000 --- a/packages/medusa/src/api/routes/admin/workflows-executions/index.ts +++ /dev/null @@ -1,84 +0,0 @@ -import middlewares, { - transformBody, - transformQuery, -} from "../../../middlewares" - -import { Router } from "express" -import { - allowedAdminWorkflowExecutionsRelations, - defaultAdminWorkflowExecutionDetailFields, - defaultAdminWorkflowExecutionsFields, - defaultAdminWorkflowExecutionsRelations, -} from "./query-config" -import { - AdminGetWorkflowExecutionDetailsParams, - AdminGetWorkflowExecutionsParams, - AdminPostWorkflowsAsyncResponseReq, - AdminPostWorkflowsRunReq, -} from "./validators" - -const route = Router() - -const retrieveTransformQueryConfig = { - defaultFields: defaultAdminWorkflowExecutionDetailFields, - defaultRelations: defaultAdminWorkflowExecutionsRelations, - allowedRelations: allowedAdminWorkflowExecutionsRelations, - isList: false, -} - -const listTransformQueryConfig = { - ...retrieveTransformQueryConfig, - defaultFields: defaultAdminWorkflowExecutionsFields, - isList: true, -} - -export default (app) => { - app.use("/workflows-executions", route) - - route.get( - "/", - transformQuery(AdminGetWorkflowExecutionsParams, listTransformQueryConfig), - middlewares.wrap(require("./list-execution").default) - ) - - route.get( - "/:id", - transformQuery( - AdminGetWorkflowExecutionDetailsParams, - retrieveTransformQueryConfig - ), - middlewares.wrap(require("./get-execution").default) - ) - - route.get( - "/:workflow_id/:transaction_id", - transformQuery( - AdminGetWorkflowExecutionDetailsParams, - retrieveTransformQueryConfig - ), - middlewares.wrap(require("./get-execution").default) - ) - - route.post( - "/:id/steps/success", - transformBody(AdminPostWorkflowsAsyncResponseReq), - middlewares.wrap(require("./set-step-success").default) - ) - - route.post( - "/:id/steps/failure", - transformBody(AdminPostWorkflowsAsyncResponseReq), - middlewares.wrap(require("./set-step-failure").default) - ) - - route.post( - "/:id/run", - transformBody(AdminPostWorkflowsRunReq), - middlewares.wrap(require("./run-workflow").default) - ) - - return app -} - -export * from "./query-config" -export * from "./validators" diff --git a/packages/medusa/src/api/routes/admin/workflows-executions/list-execution.ts b/packages/medusa/src/api/routes/admin/workflows-executions/list-execution.ts deleted file mode 100644 index eb9e5adebc..0000000000 --- a/packages/medusa/src/api/routes/admin/workflows-executions/list-execution.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { IWorkflowEngineService } from "@medusajs/workflows-sdk" -import { MedusaRequest, MedusaResponse } from "../../../../types/routing" - -export default async (req: MedusaRequest, res: MedusaResponse) => { - const workflowEngineService: IWorkflowEngineService = req.scope.resolve( - ModuleRegistrationName.WORKFLOW_ENGINE - ) - - const listConfig = req.listConfig - - const [workflow_executions, count] = - await workflowEngineService.listAndCountWorkflowExecution( - req.filterableFields, - { - select: req.listConfig.select, - relations: req.listConfig.relations, - skip: listConfig.skip, - take: listConfig.take, - } - ) - - res.json({ - workflow_executions, - count, - offset: listConfig.skip, - limit: listConfig.take, - }) -} diff --git a/packages/medusa/src/api/routes/admin/workflows-executions/query-config.ts b/packages/medusa/src/api/routes/admin/workflows-executions/query-config.ts deleted file mode 100644 index 8fe26626be..0000000000 --- a/packages/medusa/src/api/routes/admin/workflows-executions/query-config.ts +++ /dev/null @@ -1,23 +0,0 @@ -export const defaultAdminWorkflowExecutionsRelations = [] -export const allowedAdminWorkflowExecutionsRelations = [] -export const defaultAdminWorkflowExecutionsFields = [ - "id", - "workflow_id", - "transaction_id", - "state", - "created_at", - "updated_at", - "deleted_at", -] - -export const defaultAdminWorkflowExecutionDetailFields = [ - "id", - "workflow_id", - "transaction_id", - "context", - "execution", - "state", - "created_at", - "updated_at", - "deleted_at", -] diff --git a/packages/medusa/src/api/routes/admin/workflows-executions/run-workflow.ts b/packages/medusa/src/api/routes/admin/workflows-executions/run-workflow.ts deleted file mode 100644 index 95768397b0..0000000000 --- a/packages/medusa/src/api/routes/admin/workflows-executions/run-workflow.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { - IWorkflowEngineService, - WorkflowOrchestratorTypes, -} from "@medusajs/workflows-sdk" - -import { MedusaRequest, MedusaResponse } from "../../../../types/routing" -import { AdminPostWorkflowsRunReq } from "./validators" - -export default async (req: MedusaRequest, res: MedusaResponse) => { - const workflowEngineService: IWorkflowEngineService = req.scope.resolve( - ModuleRegistrationName.WORKFLOW_ENGINE - ) - - const { id: workflow_id } = req.params - - const { transaction_id, input } = - req.validatedBody as AdminPostWorkflowsRunReq - - const options = { - transactionId: transaction_id, - input, - context: { - requestId: req.requestId, - }, - throwOnError: false, - } as WorkflowOrchestratorTypes.WorkflowOrchestratorRunDTO - - const { acknowledgement } = await workflowEngineService.run( - workflow_id, - options - ) - - return res.status(200).json({ acknowledgement }) -} diff --git a/packages/medusa/src/api/routes/admin/workflows-executions/set-step-failure.ts b/packages/medusa/src/api/routes/admin/workflows-executions/set-step-failure.ts deleted file mode 100644 index 5ff902b81a..0000000000 --- a/packages/medusa/src/api/routes/admin/workflows-executions/set-step-failure.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { TransactionHandlerType, isDefined } from "@medusajs/utils" -import { IWorkflowEngineService, StepResponse } from "@medusajs/workflows-sdk" -import { MedusaRequest, MedusaResponse } from "../../../../types/routing" -import { AdminPostWorkflowsAsyncResponseReq } from "./validators" - -export default async (req: MedusaRequest, res: MedusaResponse) => { - const workflowEngineService: IWorkflowEngineService = req.scope.resolve( - ModuleRegistrationName.WORKFLOW_ENGINE - ) - - const { id: workflow_id } = req.params - - const body = req.validatedBody as AdminPostWorkflowsAsyncResponseReq - - const { transaction_id, step_id } = body - - const compensateInput = body.compensate_input - const stepResponse = isDefined(body.response) - ? new StepResponse(body.response, compensateInput) - : undefined - const stepAction = body.action || TransactionHandlerType.INVOKE - - await workflowEngineService.setStepFailure({ - idempotencyKey: { - action: stepAction, - transactionId: transaction_id, - stepId: step_id, - workflowId: workflow_id, - }, - stepResponse, - options: { - container: req.scope, - context: { - requestId: req.requestId, - }, - }, - }) - - return res.status(200).json({ success: true }) -} diff --git a/packages/medusa/src/api/routes/admin/workflows-executions/set-step-success.ts b/packages/medusa/src/api/routes/admin/workflows-executions/set-step-success.ts deleted file mode 100644 index e2b854358a..0000000000 --- a/packages/medusa/src/api/routes/admin/workflows-executions/set-step-success.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { TransactionHandlerType, isDefined } from "@medusajs/utils" -import { IWorkflowEngineService, StepResponse } from "@medusajs/workflows-sdk" -import { MedusaRequest, MedusaResponse } from "../../../../types/routing" -import { AdminPostWorkflowsAsyncResponseReq } from "./validators" - -export default async (req: MedusaRequest, res: MedusaResponse) => { - const workflowEngineService: IWorkflowEngineService = req.scope.resolve( - ModuleRegistrationName.WORKFLOW_ENGINE - ) - - const { id: workflow_id } = req.params - - const body = req.validatedBody as AdminPostWorkflowsAsyncResponseReq - - const { transaction_id, step_id } = body - - const compensateInput = body.compensate_input - const stepResponse = isDefined(body.response) - ? new StepResponse(body.response, compensateInput) - : undefined - const stepAction = body.action || TransactionHandlerType.INVOKE - - await workflowEngineService.setStepSuccess({ - idempotencyKey: { - action: stepAction, - transactionId: transaction_id, - stepId: step_id, - workflowId: workflow_id, - }, - stepResponse, - options: { - container: req.scope, - context: { - requestId: req.requestId, - }, - }, - }) - - return res.status(200).json({ success: true }) -} diff --git a/packages/medusa/src/api/routes/admin/workflows-executions/subscribe.ts b/packages/medusa/src/api/routes/admin/workflows-executions/subscribe.ts deleted file mode 100644 index 8c9131af6c..0000000000 --- a/packages/medusa/src/api/routes/admin/workflows-executions/subscribe.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { IWorkflowEngineService } from "@medusajs/workflows-sdk" -import { MedusaRequest, MedusaResponse } from "../../../../types/routing" - -export default async (req: MedusaRequest, res: MedusaResponse) => { - const workflowEngineService: IWorkflowEngineService = req.scope.resolve( - ModuleRegistrationName.WORKFLOW_ENGINE - ) - - const { id: workflow_id, transaction_id } = req.query as any - - const subscriberId = "__sub__" + Math.random().toString(36).substring(2, 9) - res.writeHead(200, { - "Content-Type": "text/event-stream", - "Cache-Control": "no-cache", - Connection: "keep-alive", - }) - - req.on("close", () => { - res.end() - - void workflowEngineService.unsubscribe({ - workflowId: workflow_id, - transactionId: transaction_id, - subscriberOrId: subscriberId, - }) - }) - - req.on("error", (err: any) => { - if (err.code === "ECONNRESET") { - res.end() - } - }) - - void workflowEngineService.subscribe({ - workflowId: workflow_id, - transactionId: transaction_id, - subscriber: async (args) => { - const { - eventType, - workflowId, - transactionId, - step, - response, - result, - errors, - } = args - - const data = { - event_type: eventType, - workflow_id: workflowId, - transaction_id: transactionId, - step, - response, - result, - errors, - } - res.write(`event: ${eventType}\ndata: ${JSON.stringify(data)}\n\n`) - }, - subscriberId, - }) -} diff --git a/packages/medusa/src/api/routes/admin/workflows-executions/validators.ts b/packages/medusa/src/api/routes/admin/workflows-executions/validators.ts deleted file mode 100644 index 50b8cb565a..0000000000 --- a/packages/medusa/src/api/routes/admin/workflows-executions/validators.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { TransactionHandlerType } from "@medusajs/utils" -import { Transform } from "class-transformer" -import { IsEnum, IsOptional, IsString } from "class-validator" -import { FindParams, extendedFindParamsMixin } from "../../../../types/common" -import { IsType } from "../../../../utils" - -export class AdminGetWorkflowExecutionDetailsParams extends FindParams {} - -export class AdminGetWorkflowExecutionsParams extends extendedFindParamsMixin({ - limit: 100, - offset: 0, -}) { - /** - * transaction id(s) to filter workflow executions by transaction_id. - */ - @IsOptional() - @IsType([String, [String]]) - transaction_id?: string | string[] - - /** - * workflow id(s) to filter workflow executions by workflow_id - */ - @IsOptional() - @IsType([String, [String]]) - workflow_id?: string | string[] -} - -export class AdminPostWorkflowsRunReq { - @IsOptional() - input?: unknown - - @IsOptional() - @IsString() - transaction_id?: string -} - -export class AdminPostWorkflowsAsyncResponseReq { - @IsString() - transaction_id: string - - @IsString() - step_id: string - - @IsOptional() - response?: unknown - - @IsOptional() - compensate_input?: unknown - - @IsOptional() - @Transform(({ value }) => (value + "").toLowerCase()) - @IsEnum(TransactionHandlerType) - action?: TransactionHandlerType -} diff --git a/packages/medusa/src/api/routes/store/auth/create-session.ts b/packages/medusa/src/api/routes/store/auth/create-session.ts deleted file mode 100644 index 9540e98bdc..0000000000 --- a/packages/medusa/src/api/routes/store/auth/create-session.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { IsEmail, IsNotEmpty } from "class-validator" -import { EntityManager } from "typeorm" -import { defaultRelations } from "." -import AuthService from "../../../../services/auth" -import CustomerService from "../../../../services/customer" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /store/auth - * operationId: "PostAuth" - * summary: "Customer Login" - * description: "Log a customer in and includes the Cookie session in the response header. The cookie session can be used in subsequent requests to authenticate the customer. - * When using Medusa's JS or Medusa React clients, the cookie is automatically attached to subsequent requests." - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostAuthReq" - * x-codegen: - * method: authenticate - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.auth.authenticate({ - * email: "user@example.com", - * password: "user@example.com" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/auth' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com", - * "password": "supersecret" - * }' - * tags: - * - Auth - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreAuthRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/incorrect_credentials" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(StorePostAuthReq, req.body) - - const authService: AuthService = req.scope.resolve("authService") - const manager: EntityManager = req.scope.resolve("manager") - const result = await manager.transaction(async (transactionManager) => { - return await authService - .withTransaction(transactionManager) - .authenticateCustomer(validated.email, validated.password) - }) - - if (!result.success) { - res.sendStatus(401) - return - } - - // Set customer id on session, this is stored on the server. - req.session.customer_id = result.customer?.id - - const customerService: CustomerService = req.scope.resolve("customerService") - const customer = await customerService.retrieve(result.customer?.id || "", { - relations: defaultRelations, - }) - - res.json({ customer }) -} - -/** - * @schema StorePostAuthReq - * type: object - * required: - * - email - * - password - * properties: - * email: - * type: string - * description: The Customer's email. - * password: - * type: string - * description: The Customer's password. - */ -export class StorePostAuthReq { - @IsEmail() - email: string - - @IsNotEmpty() - password: string -} diff --git a/packages/medusa/src/api/routes/store/auth/delete-session.ts b/packages/medusa/src/api/routes/store/auth/delete-session.ts deleted file mode 100644 index 02c25887a3..0000000000 --- a/packages/medusa/src/api/routes/store/auth/delete-session.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @oas [delete] /store/auth - * operationId: "DeleteAuth" - * summary: "Customer Log out" - * description: "Delete the current session for the logged in customer." - * x-authenticated: true - * x-codegen: - * method: deleteSession - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.auth.deleteSession() - * .then(() => { - * // customer logged out successfully - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/store/auth' \ - * -H 'Authorization: Bearer {access_token}' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Auth - * responses: - * "200": - * description: OK - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - if (req.session.user_id) { - // if we are also logged in as a user, persist that session - delete req.session.customer_id - } else { - // otherwise, destroy the session - req.session.destroy() - } - - res.sendStatus(200) -} diff --git a/packages/medusa/src/api/routes/store/auth/exists.ts b/packages/medusa/src/api/routes/store/auth/exists.ts deleted file mode 100644 index 2b11f1a66e..0000000000 --- a/packages/medusa/src/api/routes/store/auth/exists.ts +++ /dev/null @@ -1,62 +0,0 @@ -import CustomerService from "../../../../services/customer" - -/** - * @oas [get] /store/auth/{email} - * operationId: "GetAuthEmail" - * summary: "Check if Email Exists" - * description: "Check if there's a customer already registered with the provided email." - * parameters: - * - in: path - * name: email - * schema: - * type: string - * format: email - * required: true - * description: The email to check. - * x-codegen: - * method: exists - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.auth.exists("user@example.com") - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/auth/user@example.com' - * tags: - * - Auth - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreGetAuthEmailRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { email } = req.params - - try { - const customerService: CustomerService = - req.scope.resolve("customerService") - const customer = await customerService.retrieveRegisteredByEmail(email, { - select: ["id", "has_account"], - }) - res.status(200).json({ exists: customer.has_account }) - } catch (err) { - res.status(200).json({ exists: false }) - } -} diff --git a/packages/medusa/src/api/routes/store/auth/get-session.ts b/packages/medusa/src/api/routes/store/auth/get-session.ts deleted file mode 100644 index 654ba31aa6..0000000000 --- a/packages/medusa/src/api/routes/store/auth/get-session.ts +++ /dev/null @@ -1,61 +0,0 @@ -import CustomerService from "../../../../services/customer" -import { defaultRelations } from "." - -/** - * @oas [get] /store/auth - * operationId: "GetAuth" - * summary: "Get Current Customer" - * description: "Retrieve the currently logged in Customer's details." - * x-authenticated: true - * x-codegen: - * method: getSession - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.auth.getSession() - * .then(({ customer }) => { - * console.log(customer.id); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/auth' \ - * -H 'Authorization: Bearer {access_token}' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Auth - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreAuthRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const customerService: CustomerService = req.scope.resolve("customerService") - - const customer = await customerService.retrieve(req.user.customer_id, { - relations: defaultRelations, - }) - - res.json({ customer }) -} diff --git a/packages/medusa/src/api/routes/store/auth/get-token.ts b/packages/medusa/src/api/routes/store/auth/get-token.ts deleted file mode 100644 index 6930ffff5c..0000000000 --- a/packages/medusa/src/api/routes/store/auth/get-token.ts +++ /dev/null @@ -1,99 +0,0 @@ -import jwt from "jsonwebtoken" -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import AuthService from "../../../../services/auth" -import { validator } from "../../../../utils/validator" -import { StorePostAuthReq } from "./create-session" - -/** - * @oas [post] /store/auth/token - * operationId: "PostToken" - * summary: "Customer Login (JWT)" - * x-authenticated: false - * description: "After a successful login, a JWT token is returned, which can be used to send authenticated requests." - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostAuthReq" - * x-codegen: - * method: getToken - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.auth.getToken({ - * email: 'user@example.com', - * password: 'supersecret' - * }) - * .then(({ access_token }) => { - * console.log(access_token); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/auth/token' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com", - * "password": "supersecret" - * }' - * tags: - * - Auth - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreBearerAuthRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/incorrect_credentials" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { - projectConfig: { jwt_secret }, - } = req.scope.resolve("configModule") - if (!jwt_secret) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - "Please configure jwt_secret in your environment" - ) - } - const validated = await validator(StorePostAuthReq, req.body) - - const authService: AuthService = req.scope.resolve("authService") - const manager: EntityManager = req.scope.resolve("manager") - const result = await manager.transaction(async (transactionManager) => { - return await authService - .withTransaction(transactionManager) - .authenticateCustomer(validated.email, validated.password) - }) - - if (result.success && result.customer) { - // Create jwt token to send back - const token = jwt.sign( - { customer_id: result.customer.id, domain: "store" }, - jwt_secret, - { - expiresIn: "30d", - } - ) - - res.json({ access_token: token }) - } else { - res.sendStatus(401) - } -} diff --git a/packages/medusa/src/api/routes/store/auth/index.ts b/packages/medusa/src/api/routes/store/auth/index.ts deleted file mode 100644 index 6f329c824c..0000000000 --- a/packages/medusa/src/api/routes/store/auth/index.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Router } from "express" -import middlewares from "../../../middlewares" -import { Customer } from "./../../../.." - -const route = Router() - -export default (app) => { - app.use("/auth", route) - - route.get( - "/", - middlewares.requireCustomerAuthentication(), - middlewares.wrap(require("./get-session").default) - ) - route.get("/:email", middlewares.wrap(require("./exists").default)) - route.delete("/", middlewares.wrap(require("./delete-session").default)) - route.post("/", middlewares.wrap(require("./create-session").default)) - route.post("/token", middlewares.wrap(require("./get-token").default)) - - return app -} - -export const defaultRelations = ["orders", "orders.items", "shipping_addresses"] - -/** - * @schema StoreAuthRes - * type: object - * description: "The customer's details." - * x-expanded-relations: - * field: customer - * relations: - * - orders - * - orders.items - * - shipping_addresses - * required: - * - customer - * properties: - * customer: - * description: "Customer's details." - * $ref: "#/components/schemas/Customer" - */ -export type StoreAuthRes = { - customer: Customer -} - -/** - * @schema StoreBearerAuthRes - * type: object - * description: "The access token details." - * properties: - * access_token: - * description: Access token that can be used to send authenticated requests. - * type: string - */ -export type StoreBearerAuthRes = { - access_token: string -} - -/** - * @schema StoreGetAuthEmailRes - * type: object - * description: "Details on whether the email exists." - * required: - * - exists - * properties: - * exists: - * description: Whether email exists or not. - * type: boolean - */ -export type StoreGetAuthEmailRes = { - exists: boolean -} - -export * from "./create-session" -export * from "./delete-session" -export * from "./exists" -export * from "./get-session" -export * from "./get-token" diff --git a/packages/medusa/src/api/routes/store/carts/__tests__/add-shipping-method.js b/packages/medusa/src/api/routes/store/carts/__tests__/add-shipping-method.js deleted file mode 100644 index ada1f5a0b0..0000000000 --- a/packages/medusa/src/api/routes/store/carts/__tests__/add-shipping-method.js +++ /dev/null @@ -1,141 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { CartServiceMock } from "../../../../../services/__mocks__/cart" - -describe("POST /store/carts/:id/shipping-methods", () => { - describe("successfully adds a shipping method", () => { - let subject - - beforeAll(async () => { - const cartId = IdMap.getId("fr-cart") - subject = await request( - "POST", - `/store/carts/${cartId}/shipping-methods`, - { - payload: { - option_id: IdMap.getId("freeShipping"), - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CartService addShippingMethod", () => { - expect(CartServiceMock.addShippingMethod).toHaveBeenCalledTimes(1) - expect(CartServiceMock.addShippingMethod).toHaveBeenCalledWith( - IdMap.getId("fr-cart"), - IdMap.getId("freeShipping"), - {} - ) - }) - - it("calls CartService retrieve", () => { - expect(CartServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("fr-cart")) - }) - }) - - describe("successfully adds a shipping method", () => { - let subject - - beforeAll(async () => { - const cartId = IdMap.getId("swap-cart") - subject = await request( - "POST", - `/store/carts/${cartId}/shipping-methods`, - { - payload: { - option_id: IdMap.getId("freeShipping"), - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CartService addShippingMethod", () => { - expect(CartServiceMock.addShippingMethod).toHaveBeenCalledTimes(1) - expect(CartServiceMock.addShippingMethod).toHaveBeenCalledWith( - IdMap.getId("swap-cart"), - IdMap.getId("freeShipping"), - {} - ) - }) - - it("calls CartService retrieve", () => { - expect(CartServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart).toEqual( - expect.objectContaining({ type: "swap", id: IdMap.getId("test-swap") }) - ) - }) - }) - - describe("successfully adds a shipping method with additional data", () => { - let subject - - beforeAll(async () => { - const cartId = IdMap.getId("fr-cart") - subject = await request( - "POST", - `/store/carts/${cartId}/shipping-methods`, - { - payload: { - option_id: IdMap.getId("freeShipping"), - data: { - extra_id: "id", - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CartService addShippingMethod", () => { - expect(CartServiceMock.addShippingMethod).toHaveBeenCalledTimes(1) - expect(CartServiceMock.addShippingMethod).toHaveBeenCalledWith( - IdMap.getId("fr-cart"), - IdMap.getId("freeShipping"), - { - extra_id: "id", - } - ) - }) - - it("calls CartService retrieve", () => { - expect(CartServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("fr-cart")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/carts/__tests__/complete-cart.js b/packages/medusa/src/api/routes/store/carts/__tests__/complete-cart.js deleted file mode 100644 index db57d0a320..0000000000 --- a/packages/medusa/src/api/routes/store/carts/__tests__/complete-cart.js +++ /dev/null @@ -1,56 +0,0 @@ -import { request } from "../../../../../helpers/test-request" -import { CompletionStrategyMock } from "../../../../../strategies/__mocks__/cart-completion" - -describe("POST /store/carts/:id/complete", () => { - describe("successfully calls completion strategy - Legacy Endpoint", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/store/carts/test-cart/complete-cart`) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls completion strat", () => { - expect(CompletionStrategyMock.complete).toHaveBeenCalledTimes(1) - expect(CompletionStrategyMock.complete).toHaveBeenCalledWith( - "test-cart", - { idempotency_key: "testkey", recovery_point: "started" }, - undefined - ) - }) - - it("responds correctly", () => { - expect(subject.status).toEqual(200) - expect(subject.body).toEqual({}) - }) - }) - - describe("successfully calls completion strategy", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/store/carts/test-cart/complete`) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls completion strat", () => { - expect(CompletionStrategyMock.complete).toHaveBeenCalledTimes(1) - expect(CompletionStrategyMock.complete).toHaveBeenCalledWith( - "test-cart", - { idempotency_key: "testkey", recovery_point: "started" }, - undefined - ) - }) - - it("responds correctly", () => { - expect(subject.status).toEqual(200) - expect(subject.body).toEqual({}) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/carts/__tests__/create-cart.js b/packages/medusa/src/api/routes/store/carts/__tests__/create-cart.js deleted file mode 100644 index 0cb66d6023..0000000000 --- a/packages/medusa/src/api/routes/store/carts/__tests__/create-cart.js +++ /dev/null @@ -1,154 +0,0 @@ -import { CartServiceMock } from "../../../../../services/__mocks__/cart" -import { IdMap } from "medusa-test-utils" -import { LineItemServiceMock } from "../../../../../services/__mocks__/line-item" -import { request } from "../../../../../helpers/test-request" - -describe("POST /store/carts", () => { - describe("successfully creates a cart", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/store/carts`, { - payload: { - region_id: IdMap.getId("testRegion"), - context: { - clientId: "test", - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CartService create", () => { - expect(CartServiceMock.create).toHaveBeenCalledTimes(1) - expect(CartServiceMock.create).toHaveBeenCalledWith({ - context: { - ip: "::ffff:127.0.0.1", - user_agent: "node-superagent/3.8.3", - clientId: "test", - }, - region_id: IdMap.getId("testRegion"), - }) - }) - - it("calls CartService retrieve", () => { - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("regionCart")) - }) - }) - - describe("handles failed create operation", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/store/carts`, { - payload: { - region_id: IdMap.getId("fail"), - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns error", () => { - expect(subject.status).toEqual(400) - expect(subject.body.message).toEqual("Region not found") - }) - }) - - describe("creates cart with line items", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/store/carts`, { - payload: { - region_id: IdMap.getId("testRegion"), - items: [ - { - variant_id: IdMap.getId("testVariant"), - quantity: 3, - }, - { - variant_id: IdMap.getId("testVariant1"), - quantity: 1, - }, - ], - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls line item generate", () => { - expect(CartServiceMock.addOrUpdateLineItems).toHaveBeenCalledTimes(1) - - expect(LineItemServiceMock.generate).toHaveBeenCalledWith( - [ - { - variantId: IdMap.getId("testVariant"), - quantity: 3, - }, - { - variantId: IdMap.getId("testVariant1"), - quantity: 1, - }, - ], - { - region_id: IdMap.getId("testRegion"), - customer_id: undefined, - } - ) - }) - - it("returns cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("regionCart")) - }) - }) - - describe("fails if line items are not formatted correctly", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/store/carts`, { - payload: { - region_id: IdMap.getId("testRegion"), - items: [ - { - quantity: 3, - }, - { - variant_id: IdMap.getId("testVariant1"), - quantity: 1, - }, - ], - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/carts/__tests__/create-line-item.js b/packages/medusa/src/api/routes/store/carts/__tests__/create-line-item.js deleted file mode 100644 index 8966a445f5..0000000000 --- a/packages/medusa/src/api/routes/store/carts/__tests__/create-line-item.js +++ /dev/null @@ -1,89 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { CartServiceMock } from "../../../../../services/__mocks__/cart" -import { LineItemServiceMock } from "../../../../../services/__mocks__/line-item" - -describe("POST /store/carts/:id", () => { - describe("successfully creates a line item", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/store/carts/${IdMap.getId("emptyCart")}/line-items`, - { - payload: { - variant_id: IdMap.getId("testVariant"), - quantity: 3, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CartService retrieve", () => { - expect(CartServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(2) - }) - - it("calls LineItemService generate", () => { - expect(LineItemServiceMock.generate).toHaveBeenCalledTimes(1) - expect(LineItemServiceMock.generate).toHaveBeenCalledWith( - IdMap.getId("testVariant"), - IdMap.getId("testRegion"), - 3, - { metadata: undefined } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("emptyCart")) - }) - }) - - describe("handles unsuccessful line item generation", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/store/carts/${IdMap.getId("emptyCart")}/line-items`, - { - payload: { - variant_id: IdMap.getId("fail"), - quantity: 3, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls LineItemService generate", () => { - expect(LineItemServiceMock.generate).toHaveBeenCalledTimes(1) - expect(LineItemServiceMock.generate).toHaveBeenCalledWith( - IdMap.getId("fail"), - IdMap.getId("testRegion"), - 3, - { metadata: undefined } - ) - }) - - it("returns 400", () => { - expect(subject.status).toEqual(400) - }) - - it("returns error", () => { - expect(subject.body.message).toEqual("Doesn't exist") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/carts/__tests__/create-payment-sessions.js b/packages/medusa/src/api/routes/store/carts/__tests__/create-payment-sessions.js deleted file mode 100644 index b0f3762b07..0000000000 --- a/packages/medusa/src/api/routes/store/carts/__tests__/create-payment-sessions.js +++ /dev/null @@ -1,36 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { CartServiceMock } from "../../../../../services/__mocks__/cart" - -describe("POST /store/carts/:id/payment-sessions", () => { - describe("creates payment sessions", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/store/carts/${IdMap.getId("emptyCart")}/payment-sessions` - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls Cart service set payment sessions", () => { - expect(CartServiceMock.setPaymentSessions).toHaveBeenCalledTimes(1) - }) - - it("calls Cart service retrieve", () => { - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(2) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("emptyCart")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/carts/__tests__/get-cart.js b/packages/medusa/src/api/routes/store/carts/__tests__/get-cart.js deleted file mode 100644 index 477d2eeed2..0000000000 --- a/packages/medusa/src/api/routes/store/carts/__tests__/get-cart.js +++ /dev/null @@ -1,53 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { CartServiceMock } from "../../../../../services/__mocks__/cart" - -describe("GET /store/carts", () => { - describe("successfully gets a cart", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/store/carts/${IdMap.getId("emptyCart")}`) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls retrieve from CartService", () => { - expect(CartServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - }) - - it("returns cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("emptyCart")) - }) - - it("returns 200 status", () => { - expect(subject.status).toEqual(200) - }) - }) - - describe("returns 404 on undefined cart", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/store/carts/none`) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls get product from productSerice", () => { - expect(CartServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(CartServiceMock.retrieve).toHaveBeenCalledWith("none", { - select: ["id", "customer_id"], - }) - }) - - it("returns 404 status", () => { - expect(subject.status).toEqual(404) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/carts/__tests__/refresh-payment-session.js b/packages/medusa/src/api/routes/store/carts/__tests__/refresh-payment-session.js deleted file mode 100644 index 08585002ae..0000000000 --- a/packages/medusa/src/api/routes/store/carts/__tests__/refresh-payment-session.js +++ /dev/null @@ -1,42 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { CartServiceMock } from "../../../../../services/__mocks__/cart" - -describe("POST /store/carts/:id/payment-session/update", () => { - describe("successfully updates the payment session", () => { - let subject - - beforeAll(async () => { - const cartId = IdMap.getId("cartWithPaySessions") - subject = await request( - "POST", - `/store/carts/${cartId}/payment-sessions/stripe/refresh`, - {} - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CartService updatePaymentSession", () => { - expect(CartServiceMock.refreshPaymentSession).toHaveBeenCalledTimes(1) - expect(CartServiceMock.refreshPaymentSession).toHaveBeenCalledWith( - IdMap.getId("cartWithPaySessions"), - "stripe" - ) - }) - - it("calls CartService retrieve", () => { - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("cartWithPaySessions")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/carts/__tests__/update-cart.js b/packages/medusa/src/api/routes/store/carts/__tests__/update-cart.js deleted file mode 100644 index 8c43b7bcb3..0000000000 --- a/packages/medusa/src/api/routes/store/carts/__tests__/update-cart.js +++ /dev/null @@ -1,105 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { defaultStoreCartFields, defaultStoreCartRelations } from ".." -import { request } from "../../../../../helpers/test-request" -import { CartServiceMock } from "../../../../../services/__mocks__/cart" - -describe("POST /store/carts/:id", () => { - describe("successfully updates all fields", () => { - let subject - const address = { - first_name: "LeBron", - last_name: "James", - country_code: "US", - address_1: "24 Dunk Dr", - address_2: "Ball Ave", - city: "Los Angeles", - province: "CA", - postal_code: "91092", - phone: "+1 (222) 333 4444", - } - - beforeAll(async () => { - subject = await request( - "POST", - `/store/carts/${IdMap.getId("emptyCart")}`, - { - payload: { - region_id: IdMap.getId("testRegion"), - email: "test@admin.com", - shipping_address: address, - billing_address: address, - discounts: [ - { - code: "TESTCODE", - }, - ], - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("Call CartService update", () => { - expect(CartServiceMock.update).toHaveBeenCalledTimes(1) - expect(CartServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("emptyCart"), - { - region_id: IdMap.getId("testRegion"), - email: "test@admin.com", - shipping_address: address, - billing_address: address, - discounts: [ - { - code: "TESTCODE", - }, - ], - } - ) - }) - - it("calls get product from productService", () => { - expect(CartServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - expect(CartServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("emptyCart"), - { - relations: ["payment_sessions", "shipping_methods"], - } - ) - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledWith( - IdMap.getId("emptyCart"), - { - relations: defaultStoreCartRelations, - select: defaultStoreCartFields, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("emptyCart")) - }) - }) - - describe("returns 404 on undefined cart", () => { - let subject - - beforeAll(async () => { - subject = await request("POST", `/store/carts/none`) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns 404", () => { - expect(subject.status).toEqual(404) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/carts/__tests__/update-line-item.js b/packages/medusa/src/api/routes/store/carts/__tests__/update-line-item.js deleted file mode 100644 index 36b87dcc44..0000000000 --- a/packages/medusa/src/api/routes/store/carts/__tests__/update-line-item.js +++ /dev/null @@ -1,234 +0,0 @@ -import { CartServiceMock } from "../../../../../services/__mocks__/cart" -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" - -describe("POST /store/carts/:id/line-items/:line_id", () => { - describe("successfully updates a line item", () => { - let subject - - beforeAll(async () => { - const cartId = IdMap.getId("fr-cart") - const lineId = IdMap.getId("existingLine") - subject = await request( - "POST", - `/store/carts/${cartId}/line-items/${lineId}`, - { - payload: { - quantity: 3, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls cartService.updateLineItem", () => { - expect(CartServiceMock.updateLineItem).toHaveBeenCalledTimes(1) - expect(CartServiceMock.updateLineItem).toHaveBeenCalledWith( - IdMap.getId("fr-cart"), - IdMap.getId("existingLine"), - { - variant_id: IdMap.getId("eur-10-us-12"), - region_id: IdMap.getId("region-france"), - quantity: 3, - metadata: {}, - should_calculate_prices: true, - } - ) - }) - - it("calls CartService retrieve", () => { - expect(CartServiceMock.retrieve).toHaveBeenCalledTimes(2) - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("fr-cart")) - }) - }) - - describe("removes line item on quantity 0", () => { - let subject - - beforeAll(async () => { - const cartId = IdMap.getId("fr-cart") - const lineId = IdMap.getId("existingLine") - subject = await request( - "POST", - `/store/carts/${cartId}/line-items/${lineId}`, - { - payload: { - quantity: 0, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CartService removeLineItem", () => { - expect(CartServiceMock.removeLineItem).toHaveBeenCalledTimes(1) - expect(CartServiceMock.removeLineItem).toHaveBeenCalledWith( - IdMap.getId("fr-cart"), - IdMap.getId("existingLine") - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("fr-cart")) - }) - }) - - describe("updates metadata if included in request body", () => { - let subject - - beforeAll(async () => { - const cartId = IdMap.getId("fr-cart") - const lineId = IdMap.getId("existingLine") - subject = await request( - "POST", - `/store/carts/${cartId}/line-items/${lineId}`, - { - payload: { - quantity: 3, - metadata: { - potato: "tomato", - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CartService updateLineItem", () => { - expect(CartServiceMock.updateLineItem).toHaveBeenCalledTimes(1) - expect(CartServiceMock.updateLineItem).toHaveBeenCalledWith( - IdMap.getId("fr-cart"), - IdMap.getId("existingLine"), - { - metadata: { - potato: "tomato", - }, - quantity: 3, - region_id: expect.any(String), - variant_id: expect.any(String), - should_calculate_prices: true, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("fr-cart")) - }) - }) - - describe("uses empty metadata if no metadata in request body", () => { - let subject - - beforeAll(async () => { - const cartId = IdMap.getId("cartLineItemMetadata") - const lineId = IdMap.getId("lineWithMetadata") - subject = await request( - "POST", - `/store/carts/${cartId}/line-items/${lineId}`, - { - payload: { - quantity: 3, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CartService updateLineItem", () => { - expect(CartServiceMock.updateLineItem).toHaveBeenCalledTimes(1) - expect(CartServiceMock.updateLineItem).toHaveBeenCalledWith( - IdMap.getId("cartLineItemMetadata"), - IdMap.getId("lineWithMetadata"), - { - metadata: {}, - quantity: 3, - region_id: expect.any(String), - variant_id: expect.any(String), - should_calculate_prices: true, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("cartLineItemMetadata")) - }) - }) - - describe("uses metadata if in request body", () => { - let subject - - beforeAll(async () => { - const cartId = IdMap.getId("cartLineItemMetadata") - const lineId = IdMap.getId("lineWithMetadata") - subject = await request( - "POST", - `/store/carts/${cartId}/line-items/${lineId}`, - { - payload: { - quantity: 3, - metadata: { test: "this" }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CartService updateLineItem", () => { - expect(CartServiceMock.updateLineItem).toHaveBeenCalledTimes(1) - expect(CartServiceMock.updateLineItem).toHaveBeenCalledWith( - IdMap.getId("cartLineItemMetadata"), - IdMap.getId("lineWithMetadata"), - { - metadata: { test: "this" }, - quantity: 3, - region_id: expect.any(String), - variant_id: expect.any(String), - should_calculate_prices: true, - } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("cartLineItemMetadata")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/carts/__tests__/update-payment-session.js b/packages/medusa/src/api/routes/store/carts/__tests__/update-payment-session.js deleted file mode 100644 index e0a30e1884..0000000000 --- a/packages/medusa/src/api/routes/store/carts/__tests__/update-payment-session.js +++ /dev/null @@ -1,56 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { CartServiceMock } from "../../../../../services/__mocks__/cart" - -describe("POST /store/carts/:id/payment-session/update", () => { - describe("successfully updates the payment session", () => { - let subject - - beforeAll(async () => { - const cartId = IdMap.getId("cartWithPaySessions") - subject = await request( - "POST", - `/store/carts/${cartId}/payment-sessions/default_provider`, - { - payload: { - data: { - data: "Something", - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CartService updatePaymentSession", () => { - expect(CartServiceMock.setPaymentSession).toHaveBeenCalledTimes(1) - expect(CartServiceMock.setPaymentSession).toHaveBeenCalledWith( - IdMap.getId("cartWithPaySessions"), - "default_provider" - ) - - expect(CartServiceMock.updatePaymentSession).toHaveBeenCalledTimes(1) - expect(CartServiceMock.updatePaymentSession).toHaveBeenCalledWith( - IdMap.getId("cartWithPaySessions"), - { - data: "Something", - } - ) - }) - - it("calls CartService retrieve", () => { - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the cart", () => { - expect(subject.body.cart.id).toEqual(IdMap.getId("cartWithPaySessions")) - }) - }) -}) 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 deleted file mode 100644 index 3577770a58..0000000000 --- a/packages/medusa/src/api/routes/store/carts/add-shipping-method.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { - CartService, - ProductVariantInventoryService, -} from "../../../../services" -import { IsOptional, IsString } from "class-validator" -import { defaultStoreCartFields, defaultStoreCartRelations } from "." - -import { EntityManager } from "typeorm" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [post] /store/carts/{id}/shipping-methods - * operationId: "PostCartsCartShippingMethod" - * summary: "Add Shipping Method" - * description: "Add a Shipping Method to the Cart. The validation of the `data` field is handled by the fulfillment provider of the chosen shipping option." - * parameters: - * - (path) id=* {string} The cart ID. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCartsCartShippingMethodReq" - * x-codegen: - * method: addShippingMethod - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.addShippingMethod(cartId, { - * option_id - * }) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAddShippingMethodToCart } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const addShippingMethod = useAddShippingMethodToCart(cartId) - * - * const handleAddShippingMethod = ( - * optionId: string - * ) => { - * addShippingMethod.mutate({ - * option_id: optionId, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.shipping_methods) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/carts/{id}/shipping-methods' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "option_id": "{option_id}", - * }' - * tags: - * - Carts - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = req.validatedBody - - const manager: EntityManager = req.scope.resolve("manager") - const cartService: CartService = req.scope.resolve("cartService") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - await manager.transaction(async (m) => { - const txCartService = cartService.withTransaction(m) - - await txCartService.addShippingMethod( - id, - validated.option_id, - validated.data - ) - - const updated = await txCartService.retrieve(id, { - select: ["id"], - relations: ["payment_sessions"], - }) - - if (updated.payment_sessions?.length) { - await txCartService.setPaymentSessions(id) - } - }) - - const data = await cartService.retrieveWithTotals(id, { - select: defaultStoreCartFields, - relations: defaultStoreCartRelations, - }) - - await productVariantInventoryService.setVariantAvailability( - data.items.map((i) => i.variant), - data.sales_channel_id! - ) - - res.status(200).json({ cart: cleanResponseData(data, []) }) -} - -/** - * @schema StorePostCartsCartShippingMethodReq - * type: object - * description: "The details of the shipping method to add to the cart." - * required: - * - option_id - * properties: - * option_id: - * type: string - * description: ID of the shipping option to create the method from. - * data: - * type: object - * description: Used to hold any data that the shipping method may need to process the fulfillment of the order. This depends on the fulfillment provider you're using. - */ -export class StorePostCartsCartShippingMethodReq { - @IsString() - option_id: string - - @IsOptional() - data?: Record = {} -} diff --git a/packages/medusa/src/api/routes/store/carts/calculate-taxes.ts b/packages/medusa/src/api/routes/store/carts/calculate-taxes.ts deleted file mode 100644 index d178cb8ff8..0000000000 --- a/packages/medusa/src/api/routes/store/carts/calculate-taxes.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { CartService, IdempotencyKeyService } from "../../../../services" - -import { EntityManager } from "typeorm" -import { IdempotencyKey } from "../../../../models/idempotency-key" -import { cleanResponseData } from "../../../../utils/clean-response-data" -import { Logger } from "@medusajs/types" - -/** - * @oas [post] /store/carts/{id}/taxes - * operationId: "PostCartsCartTaxes" - * summary: "Calculate Cart Taxes" - * description: "Calculate the taxes for a cart. This is useful if the `automatic_taxes` field of the cart's region is set to `false`. If the cart's region uses a tax provider other than - * Medusa's system provider, this may lead to sending requests to third-party services." - * externalDocs: - * description: "How to calculate taxes manually during checkout" - * url: "https://docs.medusajs.com/modules/taxes/storefront/manual-calculation" - * parameters: - * - (path) id=* {String} The Cart ID. - * x-codegen: - * method: calculateTaxes - * x-codeSamples: - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/carts/{id}/taxes' - * tags: - * - Carts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve( - "idempotencyKeyService" - ) - const manager: EntityManager = req.scope.resolve("manager") - const logger: Logger = req.scope.resolve("logger") - - const headerKey = req.get("Idempotency-Key") || "" - - let idempotencyKey: IdempotencyKey - - try { - idempotencyKey = await manager.transaction(async (transactionManager) => { - return await idempotencyKeyService - .withTransaction(transactionManager) - .initializeRequest(headerKey, req.method, req.params, req.path) - }) - } catch (error) { - logger.log(error) - res.status(409).send("Failed to create idempotency key") - return - } - - res.setHeader("Access-Control-Expose-Headers", "Idempotency-Key") - res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key) - - const cartService: CartService = req.scope.resolve("cartService") - - let inProgress = true - let err: unknown = false - - while (inProgress) { - switch (idempotencyKey.recovery_point) { - case "started": { - await manager - .transaction("SERIALIZABLE", async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .workStage(idempotencyKey.idempotency_key, async (manager) => { - const cart = await cartService - .withTransaction(manager) - .retrieveWithTotals(id, {}, { force_taxes: true }) - - return { - response_code: 200, - response_body: { cart }, - } - }) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "finished": { - inProgress = false - break - } - - default: - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .update(idempotencyKey.idempotency_key, { - recovery_point: "finished", - response_code: 500, - response_body: { message: "Unknown recovery point" }, - }) - }) - break - } - } - - if (err) { - 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 deleted file mode 100644 index 9c4902e7fc..0000000000 --- a/packages/medusa/src/api/routes/store/carts/complete-cart.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { EntityManager } from "typeorm" -import { AbstractCartCompletionStrategy } from "../../../../interfaces" -import { IdempotencyKey } from "../../../../models" -import { IdempotencyKeyService } from "../../../../services" -import { cleanResponseData } from "../../../../utils/clean-response-data" -import { Logger } from "@medusajs/types" - -/** - * @oas [post] /store/carts/{id}/complete - * summary: "Complete a Cart" - * operationId: "PostCartsCartComplete" - * description: | - * Complete a cart and place an order or create a swap, based on the cart's type. This includes attempting to authorize the cart's payment. - * If authorizing the payment requires more action, the cart will not be completed and the order will not be placed or the swap will not be created. - * - * An idempotency key will be generated if none is provided in the header `Idempotency-Key` and added to - * the response. If an error occurs during cart completion or the request is interrupted for any reason, the cart completion can be retried by passing the idempotency - * key in the `Idempotency-Key` header. - * externalDocs: - * description: "Cart completion overview" - * url: "https://docs.medusajs.com/modules/carts-and-checkout/cart#cart-completion" - * parameters: - * - (path) id=* {String} The Cart ID. - * x-codegen: - * method: complete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.complete(cartId) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCompleteCart } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const completeCart = useCompleteCart(cartId) - * - * const handleComplete = () => { - * completeCart.mutate(void 0, { - * onSuccess: ({ data, type }) => { - * console.log(data.id, type) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/carts/{id}/complete' - * tags: - * - Carts - * responses: - * 200: - * description: "If the payment of the cart was successfully authorized, but requires further - * action from the customer, the response body will contain the cart with an - * updated payment session. Otherwise, if the payment was authorized and the cart was successfully completed, the - * response body will contain either the newly created order or swap, depending on what the cart was created for." - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCompleteCartRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const manager: EntityManager = req.scope.resolve("manager") - const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve( - "idempotencyKeyService" - ) - const logger: Logger = req.scope.resolve("logger") - - const headerKey = req.get("Idempotency-Key") || "" - - let idempotencyKey: IdempotencyKey - try { - idempotencyKey = await manager.transaction(async (transactionManager) => { - return await idempotencyKeyService - .withTransaction(transactionManager) - .initializeRequest(headerKey, req.method, req.params, req.path) - }) - } catch (error) { - logger.log(error) - res.status(409).send("Failed to create idempotency key") - return - } - - res.setHeader("Access-Control-Expose-Headers", "Idempotency-Key") - res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key) - - const completionStrat: AbstractCartCompletionStrategy = req.scope.resolve( - "cartCompletionStrategy" - ) - - const { response_code, response_body } = await completionStrat.complete( - id, - idempotencyKey, - 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 deleted file mode 100644 index 18b12233bb..0000000000 --- a/packages/medusa/src/api/routes/store/carts/create-cart.ts +++ /dev/null @@ -1,301 +0,0 @@ -import { - IsArray, - IsInt, - IsNotEmpty, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { MedusaError, isDefined } from "medusa-core-utils" -import { defaultStoreCartFields, defaultStoreCartRelations } from "." -import { - CartService, - LineItemService, - ProductVariantInventoryService, - RegionService, -} from "../../../../services" - -import { FlagRouter } from "@medusajs/utils" -import { Type } from "class-transformer" -import reqIp from "request-ip" -import { EntityManager } from "typeorm" -import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" -import { LineItem } from "../../../../models" -import { CartCreateProps } from "../../../../types/cart" -import { cleanResponseData } from "../../../../utils/clean-response-data" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" - -/** - * @oas [post] /store/carts - * operationId: "PostCart" - * summary: "Create a Cart" - * description: | - * Create a Cart. Although optional, specifying the cart's region and sales channel can affect the cart's pricing and - * the products that can be added to the cart respectively. So, make sure to set those early on and change them if necessary, such as when the customer changes their region. - * - * If a customer is logged in, make sure to pass its ID or email within the cart's details so that the cart is attached to the customer. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCartReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.create() - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCreateCart } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Cart = ({ regionId }: Props) => { - * const createCart = useCreateCart() - * - * const handleCreate = () => { - * createCart.mutate({ - * region_id: regionId - * // creates an empty cart - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.items) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/carts' - * tags: - * - Carts - * responses: - * 200: - * description: "Successfully created a new Cart" - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const entityManager: EntityManager = req.scope.resolve("manager") - const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter") - const cartService: CartService = req.scope.resolve("cartService") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - const validated = req.validatedBody as StorePostCartReq - - const reqContext = { - ip: reqIp.getClientIp(req), - user_agent: req.get("user-agent"), - } - - const lineItemService: LineItemService = req.scope.resolve("lineItemService") - const regionService: RegionService = req.scope.resolve("regionService") - - let regionId!: string - if (isDefined(validated.region_id)) { - regionId = validated.region_id as string - } else { - const regions = await regionService.list({}) - - if (!regions?.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `A region is required to create a cart` - ) - } - - regionId = regions[0].id - } - - const toCreate: Partial = { - region_id: regionId, - sales_channel_id: validated.sales_channel_id, - context: { - ...reqContext, - ...validated.context, - }, - } - - if (req.user && req.user.customer_id) { - const customerService = req.scope.resolve("customerService") - const customer = await customerService.retrieve(req.user.customer_id) - toCreate["customer_id"] = customer.id - toCreate["email"] = customer.email - } - - if (validated.country_code) { - toCreate["shipping_address"] = { - country_code: validated.country_code.toLowerCase(), - } - } - - if ( - !toCreate.sales_channel_id && - req.publishableApiKeyScopes?.sales_channel_ids.length - ) { - if (req.publishableApiKeyScopes.sales_channel_ids.length > 1) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "The PublishableApiKey provided in the request header has multiple associated sales channels." - ) - } - - toCreate.sales_channel_id = req.publishableApiKeyScopes.sales_channel_ids[0] - } - - let cart = await entityManager.transaction(async (manager) => { - const cartServiceTx = cartService.withTransaction(manager) - const lineItemServiceTx = lineItemService.withTransaction(manager) - - const createdCart = await cartServiceTx.create(toCreate) - - if (validated.items?.length) { - const generateInputData = validated.items.map((item) => { - return { - variantId: item.variant_id, - quantity: item.quantity, - } - }) - const generatedLineItems: LineItem[] = await lineItemServiceTx.generate( - generateInputData, - { - region_id: regionId, - customer_id: req.user?.customer_id, - } - ) - - await cartServiceTx.addOrUpdateLineItems( - createdCart.id, - generatedLineItems, - { - validateSalesChannels: - featureFlagRouter.isFeatureEnabled("sales_channels"), - } - ) - } - - return createdCart - }) - - cart = await cartService.retrieveWithTotals(cart.id, { - select: defaultStoreCartFields, - relations: defaultStoreCartRelations, - }) - - await productVariantInventoryService.setVariantAvailability( - cart.items.map((i) => i.variant), - cart.sales_channel_id! - ) - - res.status(200).json({ cart: cleanResponseData(cart, []) }) -} - -export class Item { - @IsNotEmpty() - @IsString() - variant_id: string - - @IsNotEmpty() - @IsInt() - quantity: number -} - -/** - * @schema StorePostCartReq - * type: object - * description: "The details of the cart to be created." - * properties: - * region_id: - * type: string - * description: "The ID of the Region to create the Cart in. Setting the cart's region can affect the pricing of the items in the cart as well as the used currency. - * If this parameter is not provided, the first region in the store is used by default." - * sales_channel_id: - * type: string - * description: "The ID of the Sales channel to create the Cart in. The cart's sales channel affects which products can be added to the cart. If a product does not - * exist in the cart's sales channel, it cannot be added to the cart. If you add a publishable API key in the header of this request and specify a sales channel ID, - * the specified sales channel must be within the scope of the publishable API key's resources. If you add a publishable API key in the header of this request, - * you don't specify a sales channel ID, and the publishable API key is associated with one sales channel, that sales channel will be attached to the cart. - * If no sales channel is passed and no publishable API key header is passed or the publishable API key isn't associated with any sales channel, - * the cart will not be associated with any sales channel." - * country_code: - * type: string - * description: "The two character ISO country code to create the Cart in. Setting this parameter will set the country code of the shipping address." - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements - * description: See a list of codes. - * items: - * description: "An array of product variants to generate line items from." - * type: array - * items: - * type: object - * required: - * - variant_id - * - quantity - * properties: - * variant_id: - * description: The ID of the Product Variant. - * type: string - * quantity: - * description: The quantity to add into the cart. - * type: integer - * context: - * description: >- - * An object to provide context to the Cart. The `context` field is automatically populated with `ip` and `user_agent` - * type: object - * example: - * ip: "::1" - * user_agent: "Chrome" - */ -export class StorePostCartReq { - @IsOptional() - @IsString() - region_id?: string - - @IsOptional() - @IsString() - country_code?: string - - @IsOptional() - @IsArray() - @ValidateNested({ each: true }) - @Type(() => Item) - items?: Item[] - - @IsOptional() - context?: object - - @FeatureFlagDecorators(SalesChannelFeatureFlag.key, [ - IsString(), - IsOptional(), - ]) - sales_channel_id?: string -} 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 deleted file mode 100644 index b23ec04533..0000000000 --- a/packages/medusa/src/api/routes/store/carts/create-line-item/index.ts +++ /dev/null @@ -1,259 +0,0 @@ -import { IsInt, IsOptional, IsString } from "class-validator" -import { EntityManager } from "typeorm" -import { validator } from "../../../../../utils/validator" -import { - addOrUpdateLineItem, - CreateLineItemSteps, - setPaymentSessions, - setVariantAvailability, -} from "./utils/handler-steps" -import { IdempotencyKey } from "../../../../../models" -import { initializeIdempotencyRequest } from "../../../../../utils/idempotency" -import { cleanResponseData } from "../../../../../utils/clean-response-data" -import IdempotencyKeyService from "../../../../../services/idempotency-key" -import { defaultStoreCartFields, defaultStoreCartRelations } from "../index" -import { CartService } from "../../../../../services" - -/** - * @oas [post] /store/carts/{id}/line-items - * operationId: PostCartsCartLineItems - * summary: "Add a Line Item" - * description: "Generates a Line Item with a given Product Variant and adds it - * to the Cart" - * parameters: - * - (path) id=* {string} The id of the Cart to add the Line Item to. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCartsCartLineItemsReq" - * x-codegen: - * method: createLineItem - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.lineItems.create(cart_id, { - * variant_id, - * quantity: 1 - * }) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCreateLineItem } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const createLineItem = useCreateLineItem(cartId) - * - * const handleAddItem = ( - * variantId: string, - * quantity: number - * ) => { - * createLineItem.mutate({ - * variant_id: variantId, - * quantity, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.items) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/carts/{id}/line-items' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "variant_id": "{variant_id}", - * "quantity": 1 - * }' - * tags: - * - Carts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const customerId: string | undefined = req.user?.customer_id - const validated = await validator(StorePostCartsCartLineItemsReq, req.body) - - const manager: EntityManager = req.scope.resolve("manager") - - let idempotencyKey!: IdempotencyKey - try { - idempotencyKey = await initializeIdempotencyRequest(req, res) - } catch { - res.status(409).send("Failed to create idempotency key") - return - } - - let inProgress = true - let err: unknown = false - - const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve( - "idempotencyKeyService" - ) - - while (inProgress) { - switch (idempotencyKey.recovery_point) { - case CreateLineItemSteps.STARTED: { - try { - const cartId = id - const data = { - customer_id: customerId, - metadata: validated.metadata, - quantity: validated.quantity, - variant_id: validated.variant_id, - } - - await addOrUpdateLineItem({ - cartId, - container: req.scope, - manager, - data, - }) - - idempotencyKey = await idempotencyKeyService - .withTransaction(manager) - .update(idempotencyKey.idempotency_key, { - recovery_point: CreateLineItemSteps.SET_PAYMENT_SESSIONS, - }) - } catch (e) { - inProgress = false - err = e - } - - break - } - - case CreateLineItemSteps.SET_PAYMENT_SESSIONS: { - try { - const cartService: CartService = req.scope.resolve("cartService") - const getCart = async () => { - return await cartService - .withTransaction(manager) - .retrieveWithTotals(id, { - select: defaultStoreCartFields, - relations: [ - ...defaultStoreCartRelations, - "region.tax_rates", - "customer", - ], - }) - } - - const cart = await getCart() - - await manager.transaction(async (transactionManager) => { - await setPaymentSessions({ - cart, - container: req.scope, - manager: transactionManager, - }) - }) - - const freshCart = await getCart() - await setVariantAvailability({ - cart: freshCart, - container: req.scope, - manager, - }) - - idempotencyKey = await idempotencyKeyService - .withTransaction(manager) - .update(idempotencyKey.idempotency_key, { - recovery_point: CreateLineItemSteps.FINISHED, - response_code: 200, - response_body: { cart: freshCart }, - }) - } catch (e) { - inProgress = false - err = e - } - - break - } - - case CreateLineItemSteps.FINISHED: { - inProgress = false - break - } - } - } - - if (err) { - 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) -} - -/** - * @schema StorePostCartsCartLineItemsReq - * type: object - * description: "The details of the line item to create." - * required: - * - variant_id - * - quantity - * properties: - * variant_id: - * type: string - * description: The id of the Product Variant to generate the Line Item from. - * quantity: - * type: number - * description: The quantity of the Product Variant to add to the Line Item. - * metadata: - * type: object - * description: An optional key-value map with additional details about the Line Item. - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class StorePostCartsCartLineItemsReq { - @IsString() - variant_id: string - - @IsInt() - quantity: number - - @IsOptional() - metadata?: Record | undefined -} diff --git a/packages/medusa/src/api/routes/store/carts/create-line-item/utils/handler-steps.ts b/packages/medusa/src/api/routes/store/carts/create-line-item/utils/handler-steps.ts deleted file mode 100644 index d2860f3b1c..0000000000 --- a/packages/medusa/src/api/routes/store/carts/create-line-item/utils/handler-steps.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Cart } from "../../../../../../models" -import { - CartService, - LineItemService, - ProductVariantInventoryService, -} from "../../../../../../services" -import { WithRequiredProperty } from "../../../../../../types/common" -import SalesChannelFeatureFlag from "../../../../../../loaders/feature-flags/sales-channels" -import { featureFlagRouter } from "../../../../../../loaders/feature-flags" - -export const CreateLineItemSteps = { - STARTED: "started", - SET_PAYMENT_SESSIONS: "set-payment-sessions", - FINISHED: "finished", -} - -export async function addOrUpdateLineItem({ - cartId, - container, - manager, - data, -}) { - const cartService: CartService = container.resolve("cartService") - const lineItemService: LineItemService = container.resolve("lineItemService") - - const cart = await cartService.retrieve(cartId, { - select: ["id", "region_id", "customer_id"], - }) - - const line = await lineItemService - .withTransaction(manager) - .generate(data.variant_id, cart.region_id, data.quantity, { - customer_id: data.customer_id || cart.customer_id, - metadata: data.metadata, - }) - - await manager.transaction(async (transactionManager) => { - const txCartService = cartService.withTransaction(transactionManager) - - await txCartService.addOrUpdateLineItems(cart.id, line, { - validateSalesChannels: - featureFlagRouter.isFeatureEnabled("sales_channels"), - }) - }) -} - -export async function setPaymentSessions({ cart, container, manager }) { - const cartService: CartService = container.resolve("cartService") - - const txCartService = cartService.withTransaction(manager) - - if (!cart.payment_sessions?.length) { - return - } - - return await txCartService.setPaymentSessions( - cart as WithRequiredProperty - ) -} - -export async function setVariantAvailability({ cart, container, manager }) { - const productVariantInventoryService: ProductVariantInventoryService = - container.resolve("productVariantInventoryService") - - const shouldSetAvailability = - cart.items?.some((item) => !!item.variant) && - featureFlagRouter.isFeatureEnabled(SalesChannelFeatureFlag.key) - - if (!shouldSetAvailability) { - return - } - - return await productVariantInventoryService - .withTransaction(manager) - .setVariantAvailability( - cart.items.map((i) => i.variant), - cart.sales_channel_id! - ) -} 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 deleted file mode 100644 index 0e73e95945..0000000000 --- a/packages/medusa/src/api/routes/store/carts/create-payment-sessions.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { CartService } from "../../../../services" -import { defaultStoreCartFields, defaultStoreCartRelations } from "." - -import { EntityManager } from "typeorm" -import IdempotencyKeyService from "../../../../services/idempotency-key" -import { cleanResponseData } from "../../../../utils/clean-response-data" -import { setVariantAvailability } from "./create-line-item/utils/handler-steps" -import { WithRequiredProperty } from "../../../../types/common" -import { Cart } from "../../../../models" - -/** - * @oas [post] /store/carts/{id}/payment-sessions - * operationId: "PostCartsCartPaymentSessions" - * summary: "Create Payment Sessions" - * description: "Create Payment Sessions for each of the available Payment Providers in the Cart's Region. If there's only one payment session created, - * it will be selected by default. The creation of the payment session uses the payment provider and may require sending requests to third-party services." - * parameters: - * - (path) id=* {string} The ID of the Cart. - * x-codegen: - * method: createPaymentSessions - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.createPaymentSessions(cartId) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCreatePaymentSession } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const createPaymentSession = useCreatePaymentSession(cartId) - * - * const handleComplete = () => { - * createPaymentSession.mutate(void 0, { - * onSuccess: ({ cart }) => { - * console.log(cart.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/carts/{id}/payment-sessions' - * tags: - * - Carts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve( - "idempotencyKeyService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - - const headerKey = req.get("Idempotency-Key") || "" - - let idempotencyKey - try { - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .initializeRequest(headerKey, req.method, req.params, req.path) - }) - } catch (error) { - res.status(409).send("Failed to create idempotency key") - return - } - - res.setHeader("Access-Control-Expose-Headers", "Idempotency-Key") - res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key) - - let inProgress = true - let err: unknown = false - - while (inProgress) { - switch (idempotencyKey.recovery_point) { - case "started": { - try { - const cartService: CartService = req.scope.resolve("cartService") - const getCart = async () => { - return await cartService - .withTransaction(manager) - .retrieveWithTotals( - id, - { - select: defaultStoreCartFields, - relations: [ - ...defaultStoreCartRelations, - "region.tax_rates", - "customer", - ], - }, - { force_taxes: true } - ) - } - - const cart = await getCart() - - await manager.transaction(async (transactionManager) => { - const txCartService = - cartService.withTransaction(transactionManager) - await txCartService.setPaymentSessions( - cart as WithRequiredProperty - ) - }) - - const freshCart = await getCart() - await setVariantAvailability({ - cart: freshCart, - container: req.scope, - manager, - }) - - idempotencyKey = await idempotencyKeyService - .withTransaction(manager) - .update(idempotencyKey.idempotency_key, { - recovery_point: "finished", - response_code: 200, - response_body: { cart: freshCart }, - }) - } catch (e) { - inProgress = false - err = e - } - break - } - - case "finished": { - inProgress = false - break - } - - default: - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .update(idempotencyKey.idempotency_key, { - recovery_point: "finished", - response_code: 500, - response_body: { message: "Unknown recovery point" }, - }) - }) - break - } - } - - if (err) { - 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 deleted file mode 100644 index 2439576ddd..0000000000 --- a/packages/medusa/src/api/routes/store/carts/delete-discount.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { - CartService, - ProductVariantInventoryService, -} from "../../../../services" -import { defaultStoreCartFields, defaultStoreCartRelations } from "." - -import { EntityManager } from "typeorm" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [delete] /store/carts/{id}/discounts/{code} - * operationId: DeleteCartsCartDiscountsDiscount - * summary: "Remove Discount" - * description: "Remove a Discount from a Cart. This only removes the application of the discount, and not completely deletes it. The totals will be re-calculated and the payment sessions - * will be refreshed after the removal." - * parameters: - * - (path) id=* {string} The ID of the Cart. - * - (path) code=* {string} The unique discount code. - * x-codegen: - * method: deleteDiscount - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.deleteDiscount(cartId, code) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/store/carts/{id}/discounts/{code}' - * tags: - * - Carts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, code } = req.params - - const manager: EntityManager = req.scope.resolve("manager") - const cartService: CartService = req.scope.resolve("cartService") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - await manager.transaction(async (m) => { - // Remove the discount - await cartService.withTransaction(m).removeDiscount(id, code) - - // If the cart has payment sessions update these - const updated = await cartService.withTransaction(m).retrieve(id, { - relations: ["payment_sessions"], - }) - - if (updated.payment_sessions?.length) { - await cartService.withTransaction(m).setPaymentSessions(id) - } - }) - - const data = await cartService.retrieveWithTotals(id, { - select: defaultStoreCartFields, - relations: defaultStoreCartRelations, - }) - - await productVariantInventoryService.setVariantAvailability( - data.items.map((i) => i.variant), - data.sales_channel_id! - ) - - 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 deleted file mode 100644 index 6a7b593e78..0000000000 --- a/packages/medusa/src/api/routes/store/carts/delete-line-item.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { - CartService, - ProductVariantInventoryService, -} from "../../../../services" -import { defaultStoreCartFields, defaultStoreCartRelations } from "." - -import { EntityManager } from "typeorm" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [delete] /store/carts/{id}/line-items/{line_id} - * operationId: DeleteCartsCartLineItemsItem - * summary: Delete a Line Item - * description: "Delete a Line Item from a Cart. The payment sessions will be updated and the totals will be recalculated." - * parameters: - * - (path) id=* {string} The ID of the Cart. - * - (path) line_id=* {string} The ID of the Line Item. - * x-codegen: - * method: deleteLineItem - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.lineItems.delete(cartId, lineId) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useDeleteLineItem } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const deleteLineItem = useDeleteLineItem(cartId) - * - * const handleDeleteItem = ( - * lineItemId: string - * ) => { - * deleteLineItem.mutate({ - * lineId: lineItemId, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.items) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/store/carts/{id}/line-items/{line_id}' - * tags: - * - Carts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, line_id } = req.params - - const manager: EntityManager = req.scope.resolve("manager") - const cartService: CartService = req.scope.resolve("cartService") - - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - await manager.transaction(async (m) => { - const cartServiceTx = cartService.withTransaction(m) - - // Remove the line item - await cartServiceTx.removeLineItem(id, line_id) - - // If the cart has payment sessions update these - const updated = await cartServiceTx.retrieve(id, { - relations: ["payment_sessions"], - }) - - if (updated.payment_sessions?.length) { - await cartServiceTx.setPaymentSessions(id) - } - }) - - const data = await cartService.retrieveWithTotals(id, { - select: defaultStoreCartFields, - relations: defaultStoreCartRelations, - }) - - await productVariantInventoryService.setVariantAvailability( - data.items.map((i) => i.variant), - data.sales_channel_id! - ) - - 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 deleted file mode 100644 index b047de3803..0000000000 --- a/packages/medusa/src/api/routes/store/carts/delete-payment-session.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { - CartService, - ProductVariantInventoryService, -} from "../../../../services" -import { defaultStoreCartFields, defaultStoreCartRelations } from "." - -import { EntityManager } from "typeorm" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [delete] /store/carts/{id}/payment-sessions/{provider_id} - * operationId: DeleteCartsCartPaymentSessionsSession - * summary: "Delete a Payment Session" - * description: "Delete a Payment Session in a Cart. May be useful if a payment has failed. The totals will be recalculated." - * parameters: - * - (path) id=* {string} The ID of the Cart. - * - (path) provider_id=* {string} The ID of the Payment Provider used to create the Payment Session to be deleted. - * x-codegen: - * method: deletePaymentSession - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.deletePaymentSession(cartId, "manual") - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useDeletePaymentSession } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const deletePaymentSession = useDeletePaymentSession(cartId) - * - * const handleDeletePaymentSession = ( - * providerId: string - * ) => { - * deletePaymentSession.mutate({ - * provider_id: providerId, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/store/carts/{id}/payment-sessions/{provider_id}' - * tags: - * - Carts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, provider_id } = req.params - - const cartService: CartService = req.scope.resolve("cartService") - - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await cartService - .withTransaction(transactionManager) - .deletePaymentSession(id, provider_id) - }) - - const data = await cartService.retrieveWithTotals(id, { - select: defaultStoreCartFields, - relations: defaultStoreCartRelations, - }) - - await productVariantInventoryService.setVariantAvailability( - data.items.map((i) => i.variant), - data.sales_channel_id! - ) - - 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 deleted file mode 100644 index 193c3c2a59..0000000000 --- a/packages/medusa/src/api/routes/store/carts/get-cart.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { - CartService, - ProductVariantInventoryService, -} from "../../../../services" - -import { EntityManager } from "typeorm" -import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [get] /store/carts/{id} - * operationId: "GetCartsCart" - * summary: "Get a Cart" - * description: "Retrieve a Cart's details. This includes recalculating its totals." - * parameters: - * - (path) id=* {string} The ID of the Cart. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.retrieve(cartId) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useGetCart } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const { cart, isLoading } = useGetCart(cartId) - * - * return ( - *
- * {isLoading && Loading...} - * {cart && cart.items.length === 0 && ( - * Cart is empty - * )} - * {cart && cart.items.length > 0 && ( - *
    - * {cart.items.map((item) => ( - *
  • {item.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/carts/{id}' - * tags: - * - Carts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const cartService: CartService = req.scope.resolve("cartService") - const manager: EntityManager = req.scope.resolve("manager") - const featureFlagRouter = req.scope.resolve("featureFlagRouter") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - const cart = await cartService.retrieve(id, { - select: ["id", "customer_id"], - }) - - // If there is a logged in user add the user to the cart - if (req.user && req.user.customer_id) { - if ( - !cart.customer_id || - !cart.email || - cart.customer_id !== req.user.customer_id - ) { - await manager.transaction(async (transctionManager) => { - await cartService.withTransaction(transctionManager).update(id, { - customer_id: req.user.customer_id, - }) - }) - } - } - const shouldSetAvailability = req.retrieveConfig.relations?.some((rel) => - rel.includes("variant") - ) - - const select = [...(req.retrieveConfig.select ?? [])] - const salesChannelsEnabled = featureFlagRouter.isFeatureEnabled( - SalesChannelFeatureFlag.key - ) - - if (salesChannelsEnabled) { - select.push("sales_channel_id") - } - - const data = await cartService.retrieveWithTotals(id, req.retrieveConfig) - - if (shouldSetAvailability) { - await productVariantInventoryService.setVariantAvailability( - data.items.map((i) => i.variant), - data.sales_channel_id! - ) - } - - 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 deleted file mode 100644 index deb98e2cec..0000000000 --- a/packages/medusa/src/api/routes/store/carts/index.ts +++ /dev/null @@ -1,366 +0,0 @@ -import "reflect-metadata" -import { Router } from "express" - -import { Cart, Order, Swap } from "../../../../" -import { FindParams } from "../../../../types/common" -import middlewares, { - transformBody, - transformStoreQuery, -} from "../../../middlewares" -import { StorePostCartsCartReq } from "./update-cart" -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" -import { MedusaV2Flag } from "@medusajs/utils" - -const route = Router() - -export default (app, container) => { - const middlewareService = container.resolve("middlewareService") - const featureFlagRouter = container.resolve("featureFlagRouter") - - app.use("/carts", route) - - if (featureFlagRouter.isFeatureEnabled(SalesChannelFeatureFlag.key)) { - if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) { - defaultStoreCartRelations.push("sales_channels") - } else { - defaultStoreCartRelations.push("sales_channel") - } - } - - // Inject plugin routes - const routers = middlewareService.getRouters("store/carts") - for (const router of routers) { - route.use("/", router) - } - - route.get( - "/:id", - transformStoreQuery(FindParams, { - defaultRelations: defaultStoreCartRelations, - defaultFields: defaultStoreCartFields, - isList: false, - }), - middlewares.wrap(require("./get-cart").default) - ) - - const createMiddlewares = [ - middlewareService.usePreCartCreation(), - transformStoreQuery(FindParams, { - defaultRelations: defaultStoreCartRelations, - defaultFields: defaultStoreCartFields, - isList: false, - }), - transformBody(StorePostCartReq), - extendRequestParams, - validateSalesChannelParam, - ] - - route.post( - "/", - ...createMiddlewares, - middlewares.wrap(require("./create-cart").default) - ) - - 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) - ) - - return app -} - -export const defaultStoreCartFields: (keyof Cart)[] = [] - -export const defaultStoreCartRelations = [ - "gift_cards", - "region", - "items", - "items.variant", - "items.adjustments", - "payment", - "shipping_address", - "billing_address", - "region.countries", - "region.payment_providers", - "shipping_methods", - "payment_sessions", - "shipping_methods.shipping_option", - "discounts", - "discounts.rule", -] - -/** - * @schema StoreCartsRes - * type: object - * description: "The cart's details." - * x-expanded-relations: - * field: cart - * relations: - * - billing_address - * - discounts - * - discounts.rule - * - gift_cards - * - items - * - items.adjustments - * - items.variant - * - payment - * - payment_sessions - * - region - * - region.countries - * - region.payment_providers - * - shipping_address - * - shipping_methods - * eager: - * - region.fulfillment_providers - * - region.payment_providers - * - shipping_methods.shipping_option - * implicit: - * - items - * - items.variant - * - items.variant.product - * - items.variant.product.profiles - * - items.tax_lines - * - items.adjustments - * - gift_cards - * - discounts - * - discounts.rule - * - shipping_methods - * - shipping_methods.tax_lines - * - shipping_address - * - region - * - region.tax_rates - * totals: - * - discount_total - * - gift_card_tax_total - * - gift_card_total - * - item_tax_total - * - refundable_amount - * - refunded_total - * - shipping_tax_total - * - shipping_total - * - subtotal - * - tax_total - * - total - * - items.discount_total - * - items.gift_card_total - * - items.original_tax_total - * - items.original_total - * - items.refundable - * - items.subtotal - * - items.tax_total - * - items.total - * required: - * - cart - * properties: - * cart: - * description: "Cart details." - * $ref: "#/components/schemas/Cart" - */ -export type StoreCartsRes = { - cart: Omit -} - -/** - * @schema StoreCompleteCartRes - * type: object - * description: "If the cart is completed successfully, this will have the created order or the swap's details, based on the cart's type. Otherwise, it'll be the cart's details." - * required: - * - type - * - data - * properties: - * type: - * type: string - * description: >- - * The type of the data property. If the cart completion fails, type will be `cart` and the data object will be the cart's details. - * If the cart completion is successful and the cart is used for checkout, type will be `order` and the data object will be the order's details. - * If the cart completion is successful and the cart is used for swap creation, type will be `swap` and the data object will be the swap's details. - * enum: [order, cart, swap] - * data: - * type: object - * description: The data of the result object. Its type depends on the type field. - * oneOf: - * - type: object - * allOf: - * - description: Cart was successfully authorized and order was placed successfully. - * - $ref: "#/components/schemas/Order" - * - type: object - * allOf: - * - description: Cart was successfully authorized but requires further actions. - * - $ref: "#/components/schemas/Cart" - * - type: object - * allOf: - * - description: Cart was used for a swap and it has been completed successfully. - * - $ref: "#/components/schemas/Swap" - */ -export type StoreCompleteCartRes = - | { - type: "cart" - data: Cart - } - | { - type: "order" - data: Order - } - | { - type: "swap" - data: Swap - } - -export * from "./add-shipping-method" -export * from "./create-cart" -export * from "./create-line-item" -export * from "./create-payment-sessions" -export * from "./set-payment-session" -export * from "./update-cart" -export * from "./update-line-item" -export * from "./update-payment-session" 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 deleted file mode 100644 index 138cc486c1..0000000000 --- a/packages/medusa/src/api/routes/store/carts/refresh-payment-session.ts +++ /dev/null @@ -1,101 +0,0 @@ -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 - * operationId: PostCartsCartPaymentSessionsSession - * summary: Refresh a Payment Session - * description: "Refresh a Payment Session to ensure that it is in sync with the Cart. This is usually not necessary, but is provided for edge cases." - * parameters: - * - (path) id=* {string} The ID of the Cart. - * - (path) provider_id=* {string} The ID of the Payment Provider that created the Payment Session to be refreshed. - * x-codegen: - * method: refreshPaymentSession - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.refreshPaymentSession(cartId, "manual") - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useRefreshPaymentSession } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const refreshPaymentSession = useRefreshPaymentSession(cartId) - * - * const handleRefresh = ( - * providerId: string - * ) => { - * refreshPaymentSession.mutate({ - * provider_id: providerId, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/carts/{id}/payment-sessions/{provider_id}/refresh' - * tags: - * - Carts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, provider_id } = req.params - - const cartService: CartService = req.scope.resolve("cartService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await cartService - .withTransaction(transactionManager) - .refreshPaymentSession(id, provider_id) - }) - const data = await cartService.retrieveWithTotals(id, { - relations: [ - "region", - "region.countries", - "region.payment_providers", - "shipping_methods", - "payment_sessions", - "shipping_methods.shipping_option", - ], - }) - - 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 deleted file mode 100644 index c63059f9b5..0000000000 --- a/packages/medusa/src/api/routes/store/carts/set-payment-session.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { - CartService, - ProductVariantInventoryService, -} from "../../../../services" -import { defaultStoreCartFields, defaultStoreCartRelations } from "." - -import { EntityManager } from "typeorm" -import { IsString } from "class-validator" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [post] /store/carts/{id}/payment-session - * operationId: PostCartsCartPaymentSession - * summary: Select a Payment Session - * description: "Select the Payment Session that will be used to complete the cart. This is typically used when the customer chooses their preferred payment method during checkout. - * The totals of the cart will be recalculated." - * parameters: - * - (path) id=* {string} The ID of the Cart. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCartsCartPaymentSessionReq" - * x-codegen: - * method: setPaymentSession - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.setPaymentSession(cartId, { - * provider_id: "manual" - * }) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useSetPaymentSession } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const setPaymentSession = useSetPaymentSession(cartId) - * - * const handleSetPaymentSession = ( - * providerId: string - * ) => { - * setPaymentSession.mutate({ - * provider_id: providerId, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.payment_session) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/carts/{id}/payment-sessions' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "provider_id": "manual" - * }' - * tags: - * - Carts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = req.validatedBody - - const cartService: CartService = req.scope.resolve("cartService") - - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await cartService - .withTransaction(transactionManager) - .setPaymentSession(id, validated.provider_id) - }) - - const data = await cartService.retrieveWithTotals(id, { - select: defaultStoreCartFields, - relations: defaultStoreCartRelations, - }) - - await productVariantInventoryService.setVariantAvailability( - data.items.map((i) => i.variant), - data.sales_channel_id! - ) - - res.status(200).json({ cart: cleanResponseData(data, []) }) -} - -/** - * @schema StorePostCartsCartPaymentSessionReq - * type: object - * description: "The details of the payment session to set." - * required: - * - provider_id - * properties: - * provider_id: - * type: string - * description: The ID of the Payment Provider. - */ -export class StorePostCartsCartPaymentSessionReq { - @IsString() - provider_id: string -} diff --git a/packages/medusa/src/api/routes/store/carts/update-cart.ts b/packages/medusa/src/api/routes/store/carts/update-cart.ts deleted file mode 100644 index cda94322f0..0000000000 --- a/packages/medusa/src/api/routes/store/carts/update-cart.ts +++ /dev/null @@ -1,332 +0,0 @@ -import { - IsArray, - IsEmail, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { defaultStoreCartFields, defaultStoreCartRelations } from "." -import { - CartService, - ProductVariantInventoryService, -} from "../../../../services" - -import { MedusaV2Flag } from "@medusajs/utils" -import { Type } from "class-transformer" -import { EntityManager } from "typeorm" -import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" -import { AddressPayload } from "../../../../types/common" -import { cleanResponseData } from "../../../../utils/clean-response-data" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" -import { IsType } from "../../../../utils/validators/is-type" - -/** - * @oas [post] /store/carts/{id} - * operationId: PostCartsCart - * summary: Update a Cart - * description: "Update a Cart's details. If the cart has payment sessions and the region was not changed, the payment sessions are updated. The cart's totals are also recalculated." - * parameters: - * - (path) id=* {string} The ID of the Cart. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCartsCartReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.update(cartId, { - * email: "user@example.com" - * }) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useUpdateCart } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const updateCart = useUpdateCart(cartId) - * - * const handleUpdate = ( - * email: string - * ) => { - * updateCart.mutate({ - * email - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.email) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/carts/{id}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com" - * }' - * tags: - * - Carts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const validated = req.validatedBody as StorePostCartsCartReq - - const cartService: CartService = req.scope.resolve("cartService") - const featureFlagRouter = req.scope.resolve("featureFlagRouter") - const manager: EntityManager = req.scope.resolve("manager") - - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - if (req.user?.customer_id) { - validated.customer_id = req.user.customer_id - } - - let cart - if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) { - cart = await retrieveCartWithIsolatedProductModule(req, id) - } - - await manager.transaction(async (transactionManager) => { - await cartService - .withTransaction(transactionManager) - .update(cart ?? id, validated) - - const updated = await cartService - .withTransaction(transactionManager) - .retrieve(id, { - relations: ["payment_sessions", "shipping_methods"], - }) - - if (updated.payment_sessions?.length && !validated.region_id) { - await cartService - .withTransaction(transactionManager) - .setPaymentSessions(id) - } - }) - - const data = await cartService.retrieveWithTotals(id, { - select: defaultStoreCartFields, - relations: defaultStoreCartRelations, - }) - - await productVariantInventoryService.setVariantAvailability( - data.items.map((i) => i.variant), - data.sales_channel_id! - ) - - res.json({ cart: cleanResponseData(data, []) }) -} - -async function retrieveCartWithIsolatedProductModule(req, id: string) { - const cartService = req.scope.resolve("cartService") - const remoteQuery = req.scope.resolve("remoteQuery") - - const relations = [ - "items", - "shipping_methods", - "shipping_methods.shipping_option", - "shipping_address", - "billing_address", - "gift_cards", - "customer", - "region", - "payment_sessions", - "region.countries", - "discounts", - "discounts.rule", - ] - - const cart = await cartService.retrieve(id, { - relations, - }) - - const products = await remoteQuery({ - products: { - __args: { - id: cart.items.map((i) => i.product_id), - }, - fields: ["id"], - variants: { - fields: ["id"], - }, - }, - }) - - const variantsMap = new Map( - products.flatMap((p) => p.variants).map((v) => [v.id, v]) - ) - - cart.items.forEach((item) => { - if (!item.variant_id) { - return - } - - item.variant = variantsMap.get(item.variant_id) - }) - - return cart -} - -class GiftCard { - @IsString() - code: string -} - -class Discount { - @IsString() - code: string -} - -/** - * @schema StorePostCartsCartReq - * type: object - * description: "The details to update of the cart." - * properties: - * region_id: - * type: string - * description: "The ID of the Region to create the Cart in. Setting the cart's region can affect the pricing of the items in the cart as well as the used currency." - * country_code: - * type: string - * description: "The 2 character ISO country code to create the Cart in. Setting this parameter will set the country code of the shipping address." - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements - * description: See a list of codes. - * email: - * type: string - * description: "An email to be used on the Cart." - * format: email - * sales_channel_id: - * type: string - * description: "The ID of the Sales channel to create the Cart in. The cart's sales channel affects which products can be added to the cart. If a product does not - * exist in the cart's sales channel, it cannot be added to the cart. If you add a publishable API key in the header of this request and specify a sales channel ID, - * the specified sales channel must be within the scope of the publishable API key's resources." - * billing_address: - * description: "The Address to be used for billing purposes." - * anyOf: - * - $ref: "#/components/schemas/AddressPayload" - * description: A full billing address object. - * - type: string - * description: The billing address ID - * shipping_address: - * description: "The Address to be used for shipping purposes." - * anyOf: - * - $ref: "#/components/schemas/AddressPayload" - * description: A full shipping address object. - * - type: string - * description: The shipping address ID - * gift_cards: - * description: "An array of Gift Card codes to add to the Cart." - * type: array - * items: - * type: object - * required: - * - code - * properties: - * code: - * description: "The code of a gift card." - * type: string - * discounts: - * description: "An array of Discount codes to add to the Cart." - * type: array - * items: - * type: object - * required: - * - code - * properties: - * code: - * description: "The code of the discount." - * type: string - * customer_id: - * description: "The ID of the Customer to associate the Cart with." - * type: string - * context: - * description: >- - * An object to provide context to the Cart. The `context` field is automatically populated with `ip` and `user_agent` - * type: object - * example: - * ip: "::1" - * user_agent: "Chrome" - */ -export class StorePostCartsCartReq { - @IsOptional() - @IsString() - region_id?: string - - @IsOptional() - @IsString() - country_code?: string - - @IsEmail() - @IsOptional() - email?: string - - @IsOptional() - @IsType([AddressPayload, String]) - billing_address?: AddressPayload | string - - @IsOptional() - @IsType([AddressPayload, String]) - shipping_address?: AddressPayload | string - - @IsOptional() - @IsArray() - @ValidateNested({ each: true }) - @Type(() => GiftCard) - gift_cards?: GiftCard[] - - @IsOptional() - @IsArray() - @ValidateNested({ each: true }) - @Type(() => Discount) - discounts?: Discount[] - - @IsString() - @IsOptional() - customer_id?: string - - @IsOptional() - context?: object - - @FeatureFlagDecorators(SalesChannelFeatureFlag.key, [ - IsString(), - IsOptional(), - ]) - sales_channel_id?: string -} 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 deleted file mode 100644 index c492c48b29..0000000000 --- a/packages/medusa/src/api/routes/store/carts/update-line-item.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { - CartService, - ProductVariantInventoryService, -} from "../../../../services" -import { IsInt, IsOptional } from "class-validator" -import { defaultStoreCartFields, defaultStoreCartRelations } from "." - -import { EntityManager } from "typeorm" -import { MedusaError } from "medusa-core-utils" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [post] /store/carts/{id}/line-items/{line_id} - * operationId: PostCartsCartLineItemsItem - * summary: Update a Line Item - * description: "Update a line item's quantity." - * parameters: - * - (path) id=* {string} The ID of the Cart. - * - (path) line_id=* {string} The ID of the Line Item. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCartsCartLineItemsItemReq" - * x-codegen: - * method: updateLineItem - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.lineItems.update(cartId, lineId, { - * quantity: 1 - * }) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useUpdateLineItem } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const updateLineItem = useUpdateLineItem(cartId) - * - * const handleUpdateItem = ( - * lineItemId: string, - * quantity: number - * ) => { - * updateLineItem.mutate({ - * lineId: lineItemId, - * quantity, - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.items) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/carts/{id}/line-items/{line_id}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "quantity": 1 - * }' - * tags: - * - Carts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, line_id } = req.params - - const validated = req.validatedBody - - const manager: EntityManager = req.scope.resolve("manager") - const cartService: CartService = req.scope.resolve("cartService") - - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - await manager.transaction(async (m) => { - // If the quantity is 0 that is effectively deletion - if (validated.quantity === 0) { - await cartService.withTransaction(m).removeLineItem(id, line_id) - } else { - const cart = await cartService.withTransaction(m).retrieve(id, { - relations: ["items", "items.variant", "shipping_methods"], - }) - - const existing = cart.items.find((i) => i.id === line_id) - if (!existing) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Could not find the line item" - ) - } - - const lineItemUpdate = { - variant_id: existing.variant.id, - region_id: cart.region_id, - quantity: validated.quantity, - metadata: validated.metadata || {}, - should_calculate_prices: true, - } - - await cartService - .withTransaction(m) - .updateLineItem(id, line_id, lineItemUpdate) - } - - // If the cart has payment sessions update these - const updated = await cartService.withTransaction(m).retrieve(id, { - relations: ["payment_sessions"], - }) - - if (updated.payment_sessions?.length) { - await cartService.withTransaction(m).setPaymentSessions(id) - } - }) - - const data = await cartService.retrieveWithTotals(id, { - select: defaultStoreCartFields, - relations: defaultStoreCartRelations, - }) - - await productVariantInventoryService.setVariantAvailability( - data.items.map((i) => i.variant), - data.sales_channel_id! - ) - - res.status(200).json({ cart: cleanResponseData(data, []) }) -} - -/** - * @schema StorePostCartsCartLineItemsItemReq - * type: object - * description: "The details to update of the line item." - * required: - * - quantity - * properties: - * quantity: - * type: number - * description: The quantity of the line item in the cart. - * metadata: - * type: object - * description: An optional key-value map with additional details about the Line Item. If omitted, the metadata will remain unchanged." - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class StorePostCartsCartLineItemsItemReq { - @IsInt() - quantity: number - - @IsOptional() - metadata?: Record | undefined -} 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 deleted file mode 100644 index 645277b74a..0000000000 --- a/packages/medusa/src/api/routes/store/carts/update-payment-session.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { - CartService, - ProductVariantInventoryService, -} from "../../../../services" -import { defaultStoreCartFields, defaultStoreCartRelations } from "." - -import { EntityManager } from "typeorm" -import { IsObject } from "class-validator" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [post] /store/carts/{id}/payment-sessions/{provider_id} - * operationId: PostCartsCartPaymentSessionUpdate - * summary: Update a Payment Session - * description: "Update a Payment Session with additional data. This can be useful depending on the payment provider used. - * All payment sessions are updated and cart totals are recalculated afterwards." - * parameters: - * - (path) id=* {string} The ID of the Cart. - * - (path) provider_id=* {string} The ID of the payment provider. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCartsCartPaymentSessionUpdateReq" - * x-codegen: - * method: updatePaymentSession - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.carts.updatePaymentSession(cartId, "manual", { - * data: { - * - * } - * }) - * .then(({ cart }) => { - * console.log(cart.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useUpdatePaymentSession } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Cart = ({ cartId }: Props) => { - * const updatePaymentSession = useUpdatePaymentSession(cartId) - * - * const handleUpdate = ( - * providerId: string, - * data: Record - * ) => { - * updatePaymentSession.mutate({ - * provider_id: providerId, - * data - * }, { - * onSuccess: ({ cart }) => { - * console.log(cart.payment_session) - * } - * }) - * } - * - * // ... - * } - * - * export default Cart - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/carts/{id}/payment-sessions/manual' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "data": {} - * }' - * tags: - * - Carts - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, provider_id } = req.params - - const validated = req.validatedBody - - const cartService: CartService = req.scope.resolve("cartService") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - await cartService - .withTransaction(transactionManager) - .setPaymentSession(id, provider_id) - await cartService - .withTransaction(transactionManager) - .updatePaymentSession(id, validated.data) - }) - - const data = await cartService.retrieveWithTotals(id, { - select: defaultStoreCartFields, - relations: defaultStoreCartRelations, - }) - - await productVariantInventoryService.setVariantAvailability( - data.items.map((i) => i.variant), - data.sales_channel_id! - ) - - res.status(200).json({ cart: cleanResponseData(data, []) }) -} - -/** - * @schema StorePostCartsCartPaymentSessionUpdateReq - * type: object - * required: - * - data - * properties: - * data: - * type: object - * description: The data to update the payment session with. - */ -export class StorePostCartsCartPaymentSessionUpdateReq { - @IsObject() - data: Record -} diff --git a/packages/medusa/src/api/routes/store/collections/__tests__/get-collection.js b/packages/medusa/src/api/routes/store/collections/__tests__/get-collection.js deleted file mode 100644 index 73d56f421f..0000000000 --- a/packages/medusa/src/api/routes/store/collections/__tests__/get-collection.js +++ /dev/null @@ -1,27 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ProductCollectionServiceMock } from "../../../../../services/__mocks__/product-collection" - -describe("GET /store/categories/:id", () => { - describe("get collection by id successfully", () => { - let subject - beforeAll(async () => { - subject = await request("GET", `/store/collections/${IdMap.getId("col")}`) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls retrieve from product collection service", () => { - expect(ProductCollectionServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(ProductCollectionServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("col") - ) - }) - - it("returns variant decorated", () => { - expect(subject.body.collection.id).toEqual(IdMap.getId("col")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/collections/__tests__/list-collections.js b/packages/medusa/src/api/routes/store/collections/__tests__/list-collections.js deleted file mode 100644 index f275838bf8..0000000000 --- a/packages/medusa/src/api/routes/store/collections/__tests__/list-collections.js +++ /dev/null @@ -1,108 +0,0 @@ -import { request } from "../../../../../helpers/test-request" -import { ProductCollectionServiceMock } from "../../../../../services/__mocks__/product-collection" - -describe("GET /store/collections", () => { - describe("successful retrieval", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("GET", `/store/collections`) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls product collection service list", () => { - expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledTimes(1) - }) - }) - - describe("can pass a limit query param and offset default is used", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("GET", `/store/collections?limit=5`) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls product collection service list with the right params", () => { - expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - { - order: { - created_at: "DESC", - }, - relations: [], - select: undefined, - skip: 0, - take: 5, - } - ) - }) - }) - - describe("can pass an offset query param and limit default is used", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("GET", `/store/collections?offset=10`) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls product collection service list with the right params", () => { - expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - { - order: { - created_at: "DESC", - }, - relations: [], - select: undefined, - skip: 10, - take: 10, - } - ) - }) - }) - - describe("can pass an offset and limit query params", () => { - let subject - - beforeAll(async () => { - jest.clearAllMocks() - subject = await request("GET", `/store/collections?offset=10&limit=20`) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("calls product collection service list with the right params", () => { - expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - { - order: { - created_at: "DESC", - }, - relations: [], - select: undefined, - skip: 10, - take: 20, - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/collections/get-collection.ts b/packages/medusa/src/api/routes/store/collections/get-collection.ts deleted file mode 100644 index 1f14851422..0000000000 --- a/packages/medusa/src/api/routes/store/collections/get-collection.ts +++ /dev/null @@ -1,77 +0,0 @@ -import ProductCollectionService from "../../../../services/product-collection" - -/** - * @oas [get] /store/collections/{id} - * operationId: "GetCollectionsCollection" - * summary: "Get a Collection" - * description: "Retrieve a Product Collection's details." - * parameters: - * - (path) id=* {string} The id of the Product Collection - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.collections.retrieve(collectionId) - * .then(({ collection }) => { - * console.log(collection.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCollection } from "medusa-react" - * - * type Props = { - * collectionId: string - * } - * - * const ProductCollection = ({ collectionId }: Props) => { - * const { collection, isLoading } = useCollection(collectionId) - * - * return ( - *
- * {isLoading && Loading...} - * {collection && {collection.title}} - *
- * ) - * } - * - * export default ProductCollection - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/collections/{id}' - * tags: - * - Product Collections - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCollectionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ - -export default async (req, res) => { - const { id } = req.params - const productCollectionService: ProductCollectionService = req.scope.resolve( - "productCollectionService" - ) - - const collection = await productCollectionService.retrieve(id) - res.status(200).json({ collection }) -} diff --git a/packages/medusa/src/api/routes/store/collections/index.ts b/packages/medusa/src/api/routes/store/collections/index.ts deleted file mode 100644 index 90376494f6..0000000000 --- a/packages/medusa/src/api/routes/store/collections/index.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Router } from "express" -import { PaginatedResponse } from "../../../../types/common" -import { ProductCollection } from "../../../../" -import middlewares, { transformStoreQuery } from "../../../middlewares" -import { StoreGetCollectionsParams } from "./list-collections" - -const route = Router() - -export default (app) => { - app.use("/collections", route) - - route.get( - "/", - transformStoreQuery(StoreGetCollectionsParams, { - allowedFields, - isList: true, - }), - middlewares.wrap(require("./list-collections").default) - ) - route.get("/:id", middlewares.wrap(require("./get-collection").default)) - - return app -} - -export const defaultStoreCollectionRelations = [] -export const allowedFields = [ - "id", - "title", - "handle", - "products", - "metadata", - "created_at", - "updated_at", - "deleted_at", - ...defaultStoreCollectionRelations, -] - -/** - * @schema StoreCollectionsListRes - * type: object - * description: "The list of product collections with pagination fields." - * required: - * - collections - * - count - * - offset - * - limit - * properties: - * collections: - * type: array - * description: "An array of product collections details" - * items: - * $ref: "#/components/schemas/ProductCollection" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of product collections skipped when retrieving the product collections. - * limit: - * type: integer - * description: The number of items per page - */ -export type StoreCollectionsListRes = PaginatedResponse & { - collections: ProductCollection[] -} - -/** - * @schema StoreCollectionsRes - * type: object - * description: "The details of the product collection." - * required: - * - collection - * properties: - * collection: - * description: "Product collection details." - * $ref: "#/components/schemas/ProductCollection" - */ -export type StoreCollectionsRes = { - collection: ProductCollection -} - -export * from "./get-collection" -export * from "./list-collections" diff --git a/packages/medusa/src/api/routes/store/collections/list-collections.ts b/packages/medusa/src/api/routes/store/collections/list-collections.ts deleted file mode 100644 index 53b8572768..0000000000 --- a/packages/medusa/src/api/routes/store/collections/list-collections.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { IsArray, IsInt, IsOptional, ValidateNested } from "class-validator" - -import { DateComparisonOperator } from "../../../../types/common" -import ProductCollectionService from "../../../../services/product-collection" -import { Type } from "class-transformer" - -/** - * @oas [get] /store/collections - * operationId: "GetCollections" - * summary: "List Collections" - * description: "Retrieve a list of product collections. The product collections can be filtered by fields such as `handle` or `created_at`. The product collections can also be paginated." - * parameters: - * - (query) offset=0 {integer} The number of product collections to skip when retrieving the product collections. - * - (query) limit=10 {integer} Limit the number of product collections returned. - * - in: query - * name: handle - * style: form - * explode: false - * description: Filter by handles - * schema: - * type: array - * items: - * type: string - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: list - * queryParams: StoreGetCollectionsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.collections.list() - * .then(({ collections, limit, offset, count }) => { - * console.log(collections.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCollections } from "medusa-react" - * - * const ProductCollections = () => { - * const { collections, isLoading } = useCollections() - * - * return ( - *
- * {isLoading && Loading...} - * {collections && collections.length === 0 && ( - * No Product Collections - * )} - * {collections && collections.length > 0 && ( - *
    - * {collections.map((collection) => ( - *
  • {collection.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ProductCollections - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/collections' - * tags: - * - Product Collections - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCollectionsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const productCollectionService: ProductCollectionService = req.scope.resolve( - "productCollectionService" - ) - - const { listConfig, filterableFields } = req - const { skip, take } = req.listConfig - - const [collections, count] = await productCollectionService.listAndCount( - filterableFields, - listConfig - ) - - res.status(200).json({ collections, count, limit: take, offset: skip }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved product collections. - */ -export class StoreGetCollectionsParams { - /** - * Handles to filter product collections by. - */ - @IsOptional() - @IsArray() - handle?: string[] - - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 10 - */ - @IsOptional() - @IsInt() - @Type(() => Number) - limit?: number = 10 - - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsOptional() - @IsInt() - @Type(() => Number) - offset?: number = 0 - - /** - * Date filters to apply on the product collections' `created_at` date - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the product collections' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator -} diff --git a/packages/medusa/src/api/routes/store/customers/__tests__/create-customer.js b/packages/medusa/src/api/routes/store/customers/__tests__/create-customer.js deleted file mode 100644 index c94095baa3..0000000000 --- a/packages/medusa/src/api/routes/store/customers/__tests__/create-customer.js +++ /dev/null @@ -1,73 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { - defaultStoreCustomersFields, - defaultStoreCustomersRelations, -} from "../" -import { request } from "../../../../../helpers/test-request" -import { CustomerServiceMock } from "../../../../../services/__mocks__/customer" - -describe("POST /store/customers", () => { - describe("successfully creates a customer", () => { - let subject - beforeAll(async () => { - subject = await request("POST", `/store/customers`, { - payload: { - email: "lebron@james.com", - first_name: "LeBron", - last_name: "James", - password: "TheGame", - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CustomerService create", () => { - expect(CustomerServiceMock.create).toHaveBeenCalledTimes(1) - expect(CustomerServiceMock.create).toHaveBeenCalledWith({ - email: "lebron@james.com", - first_name: "LeBron", - last_name: "James", - password: "TheGame", - }) - }) - - it("calls CustomerService retrieve", () => { - expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(CustomerServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("lebron"), - { - relations: defaultStoreCustomersRelations, - select: defaultStoreCustomersFields, - } - ) - }) - - it("returns customer", () => { - expect(subject.body.customer.email).toEqual("lebron@james.com") - }) - }) - - describe("fails if missing field", () => { - let subject - beforeAll(async () => { - subject = await request("POST", `/store/customers`, { - payload: { - first_name: "LeBron", - last_name: "James", - password: "TheGame", - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("returns product decorated", () => { - expect(subject.body.type).toEqual("invalid_data") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/customers/__tests__/reset-password-token.js b/packages/medusa/src/api/routes/store/customers/__tests__/reset-password-token.js deleted file mode 100644 index 07d86d9252..0000000000 --- a/packages/medusa/src/api/routes/store/customers/__tests__/reset-password-token.js +++ /dev/null @@ -1,42 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { CustomerServiceMock } from "../../../../../services/__mocks__/customer" - -describe("POST /store/customers/password-token", () => { - describe("successfully creates a customer", () => { - let subject - beforeAll(async () => { - subject = await request("POST", `/store/customers/password-token`, { - payload: { - email: "lebron@james1.com", - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CustomerService retrieve", () => { - expect( - CustomerServiceMock.retrieveRegisteredByEmail - ).toHaveBeenCalledTimes(1) - expect( - CustomerServiceMock.retrieveRegisteredByEmail - ).toHaveBeenCalledWith("lebron@james1.com") - }) - - it("calls CustomerService retrieve", () => { - expect( - CustomerServiceMock.generateResetPasswordToken - ).toHaveBeenCalledTimes(1) - expect( - CustomerServiceMock.generateResetPasswordToken - ).toHaveBeenCalledWith(IdMap.getId("lebron")) - }) - - it("returns success", () => { - expect(subject.status).toEqual(204) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/customers/__tests__/reset-password.js b/packages/medusa/src/api/routes/store/customers/__tests__/reset-password.js deleted file mode 100644 index f11231eeef..0000000000 --- a/packages/medusa/src/api/routes/store/customers/__tests__/reset-password.js +++ /dev/null @@ -1,65 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import jwt from "jsonwebtoken" -import { request } from "../../../../../helpers/test-request" -import { CustomerServiceMock } from "../../../../../services/__mocks__/customer" - -describe("POST /store/customers/password-reset", () => { - describe("successfully udates customer password", () => { - let subject - beforeAll(async () => { - subject = await request("POST", `/store/customers/password-reset`, { - payload: { - email: "lebron@james1.com", - token: jwt.sign({ customer_id: IdMap.getId("lebron") }, "1234"), - password: "TheGame", - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CustomerService update", () => { - expect(CustomerServiceMock.update).toHaveBeenCalledTimes(1) - expect(CustomerServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("lebron"), - { - password: "TheGame", - } - ) - }) - - it("calls CustomerService retrieve", () => { - expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(CustomerServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("lebron") - ) - }) - - it("returns customer ", () => { - expect(subject.body.customer.email).toEqual("lebron@james.com") - }) - }) - - describe("fails if id in webtoken not matching", () => { - let subject - beforeAll(async () => { - subject = await request("POST", `/store/customers/password-reset`, { - payload: { - email: "lebron@james1.com", - token: jwt.sign({ customer_id: IdMap.getId("not-lebron") }, "1234"), - password: "TheGame", - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("fails", () => { - expect(subject.status).toEqual(401) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/customers/__tests__/update-customer.js b/packages/medusa/src/api/routes/store/customers/__tests__/update-customer.js deleted file mode 100644 index 17a55d61cc..0000000000 --- a/packages/medusa/src/api/routes/store/customers/__tests__/update-customer.js +++ /dev/null @@ -1,174 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { - defaultStoreCustomersFields, - defaultStoreCustomersRelations, -} from "../" -import { request } from "../../../../../helpers/test-request" -import { CustomerServiceMock } from "../../../../../services/__mocks__/customer" - -describe("POST /store/customers/me", () => { - describe("successfully updates a customer", () => { - let subject - beforeAll(async () => { - subject = await request("POST", `/store/customers/me`, { - payload: { - first_name: "LeBron", - last_name: "James", - email: "test@email.com", - }, - clientSession: { - jwt: { - customer_id: IdMap.getId("lebron"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CustomerService update", () => { - expect(CustomerServiceMock.update).toHaveBeenCalledTimes(1) - expect(CustomerServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("lebron"), - { - first_name: "LeBron", - last_name: "James", - email: "test@email.com", - } - ) - }) - - it("calls CustomerService retrieve", () => { - expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(CustomerServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("lebron"), - { - relations: defaultStoreCustomersRelations, - select: defaultStoreCustomersFields, - } - ) - }) - - it("returns customer", () => { - expect(subject.body.customer.id).toEqual(IdMap.getId("lebron")) - }) - - it("status code 200", () => { - expect(subject.status).toEqual(200) - }) - }) - - describe("fails update a customer with a billing address with an invalid type", () => { - let subject - beforeAll(async () => { - subject = await request("POST", `/store/customers/me`, { - payload: { - billing_address: 42, - }, - clientSession: { - jwt: { - customer_id: IdMap.getId("lebron"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CustomerService update 0 times", () => { - expect(CustomerServiceMock.update).toHaveBeenCalledTimes(0) - }) - - it("status code 400", () => { - expect(subject.status).toEqual(400) - }) - }) - - describe("successfully updates a customer with billing address id", () => { - let subject - beforeAll(async () => { - subject = await request("POST", `/store/customers/me`, { - payload: { - billing_address: "test", - }, - clientSession: { - jwt: { - customer_id: IdMap.getId("lebron"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CustomerService update", () => { - expect(CustomerServiceMock.update).toHaveBeenCalledTimes(1) - expect(CustomerServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("lebron"), - { - billing_address: "test", - } - ) - }) - - it("status code 200", () => { - expect(subject.status).toEqual(200) - }) - }) - - describe("successfully updates a customer with billing address object", () => { - let subject - beforeAll(async () => { - subject = await request("POST", `/store/customers/me`, { - payload: { - billing_address: { - first_name: "Olli", - last_name: "Juhl", - address_1: "Laksegade", - city: "Copenhagen", - country_code: "dk", - postal_code: "2100", - phone: "+1 (222) 333 4444", - }, - }, - clientSession: { - jwt: { - customer_id: IdMap.getId("lebron"), - }, - }, - }) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CustomerService update", () => { - expect(CustomerServiceMock.update).toHaveBeenCalledTimes(1) - expect(CustomerServiceMock.update).toHaveBeenCalledWith( - IdMap.getId("lebron"), - { - billing_address: { - first_name: "Olli", - last_name: "Juhl", - address_1: "Laksegade", - city: "Copenhagen", - country_code: "dk", - postal_code: "2100", - phone: "+1 (222) 333 4444", - }, - } - ) - }) - - it("status code 200", () => { - expect(subject.status).toEqual(200) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/customers/create-address.ts b/packages/medusa/src/api/routes/store/customers/create-address.ts deleted file mode 100644 index e34121b657..0000000000 --- a/packages/medusa/src/api/routes/store/customers/create-address.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { Type } from "class-transformer" -import { ValidateNested } from "class-validator" -import { EntityManager } from "typeorm" -import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "." -import CustomerService from "../../../../services/customer" -import { AddressCreatePayload } from "../../../../types/common" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /store/customers/me/addresses - * operationId: PostCustomersCustomerAddresses - * summary: "Add a Shipping Address" - * description: "Add a Shipping Address to a Customer's saved addresses." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCustomersCustomerAddressesReq" - * x-codegen: - * method: addAddress - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.addresses.addAddress({ - * address: { - * first_name: "Celia", - * last_name: "Schumm", - * address_1: "225 Bednar Curve", - * city: "Danielville", - * country_code: "US", - * postal_code: "85137", - * phone: "981-596-6748 x90188", - * company: "Wyman LLC", - * province: "Georgia", - * } - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/customers/me/addresses' \ - * -H 'Authorization: Bearer {access_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "address": { - * "first_name": "Celia", - * "last_name": "Schumm", - * "address_1": "225 Bednar Curve", - * "city": "Danielville", - * "country_code": "US", - * "postal_code": "85137" - * } - * }' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customers - * responses: - * "200": - * description: "A successful response" - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCustomersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const id = req.user.customer_id - - const validated = await validator( - StorePostCustomersCustomerAddressesReq, - req.body - ) - - const customerService: CustomerService = req.scope.resolve("customerService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await customerService - .withTransaction(transactionManager) - .addAddress(id, validated.address) - }) - - const customer = await customerService.retrieve(id, { - relations: defaultStoreCustomersRelations, - select: defaultStoreCustomersFields, - }) - - res.status(200).json({ customer }) -} - -/** - * @schema StorePostCustomersCustomerAddressesReq - * type: object - * required: - * - address - * properties: - * address: - * description: "The Address to add to the Customer's saved addresses." - * $ref: "#/components/schemas/AddressCreatePayload" - */ -export class StorePostCustomersCustomerAddressesReq { - @ValidateNested() - @Type(() => AddressCreatePayload) - address: AddressCreatePayload -} diff --git a/packages/medusa/src/api/routes/store/customers/create-customer.ts b/packages/medusa/src/api/routes/store/customers/create-customer.ts deleted file mode 100644 index 3b1d98aeb1..0000000000 --- a/packages/medusa/src/api/routes/store/customers/create-customer.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { IsEmail, IsOptional, IsString } from "class-validator" -import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "." - -import jwt from "jsonwebtoken" -import { EntityManager } from "typeorm" -import { Customer } from "../../../.." -import CustomerService from "../../../../services/customer" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /store/customers - * operationId: PostCustomers - * summary: Create a Customer - * description: "Register a new customer. This will also automatically authenticate the customer and set their login session in the response Cookie header. - * The cookie session can be used in subsequent requests to authenticate the customer. - * When using Medusa's JS or Medusa React clients, the cookie is automatically attached to subsequent requests." - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCustomersReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.customers.create({ - * first_name: "Alec", - * last_name: "Reynolds", - * email: "user@example.com", - * password: "supersecret" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCreateCustomer } from "medusa-react" - * - * const RegisterCustomer = () => { - * const createCustomer = useCreateCustomer() - * // ... - * - * const handleCreate = ( - * customerData: { - * first_name: string - * last_name: string - * email: string - * password: string - * } - * ) => { - * // ... - * createCustomer.mutate(customerData, { - * onSuccess: ({ customer }) => { - * console.log(customer.id) - * } - * }) - * } - * - * // ... - * } - * - * export default RegisterCustomer - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/customers' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "first_name": "Alec", - * "last_name": "Reynolds", - * "email": "user@example.com", - * "password": "supersecret" - * }' - * tags: - * - Customers - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCustomersRes" - * 422: - * description: A customer with the same email exists - * content: - * application/json: - * schema: - * type: object - * properties: - * code: - * type: string - * description: The error code - * type: - * type: string - * description: The type of error - * message: - * type: string - * description: Human-readable message with details about the error - * example: - * code: "invalid_request_error" - * type: "duplicate_error" - * message: "A customer with the given email already has an account. Log in instead" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(StorePostCustomersReq, req.body) - - const customerService: CustomerService = req.scope.resolve("customerService") - const manager: EntityManager = req.scope.resolve("manager") - let customer: Customer = await manager.transaction( - async (transactionManager) => { - return await customerService - .withTransaction(transactionManager) - .create(validated) - } - ) - - customer = await customerService.retrieve(customer.id, { - relations: defaultStoreCustomersRelations, - select: defaultStoreCustomersFields, - }) - - req.session.customer_id = customer.id - - res.status(200).json({ customer }) -} - -/** - * @schema StorePostCustomersReq - * type: object - * description: "The details of the customer to create." - * required: - * - first_name - * - last_name - * - email - * - password - * properties: - * first_name: - * description: "The customer's first name." - * type: string - * last_name: - * description: "The customer's last name." - * type: string - * email: - * description: "The customer's email." - * type: string - * format: email - * password: - * description: "The customer's password." - * type: string - * format: password - * phone: - * description: "The customer's phone number." - * type: string - */ -export class StorePostCustomersReq { - @IsString() - @IsOptional() - first_name: string - - @IsString() - @IsOptional() - last_name: string - - @IsEmail() - email: string - - @IsString() - password: string - - @IsOptional() - @IsString() - phone?: string -} diff --git a/packages/medusa/src/api/routes/store/customers/delete-address.ts b/packages/medusa/src/api/routes/store/customers/delete-address.ts deleted file mode 100644 index 2cfd4dc8fb..0000000000 --- a/packages/medusa/src/api/routes/store/customers/delete-address.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "." - -import { EntityManager } from "typeorm" -import CustomerService from "../../../../services/customer" - -/** - * @oas [delete] /store/customers/me/addresses/{address_id} - * operationId: DeleteCustomersCustomerAddressesAddress - * summary: Delete an Address - * description: "Delete an Address from the Customer's saved addresses." - * x-authenticated: true - * parameters: - * - (path) address_id=* {string} The id of the Address to remove. - * x-codegen: - * method: deleteAddress - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.addresses.deleteAddress(addressId) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X DELETE '{backend_url}/store/customers/me/addresses/{address_id}' \ - * -H 'Authorization: Bearer {access_token}' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customers - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCustomersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const id = req.user.customer_id - - const { address_id } = req.params - - const customerService: CustomerService = req.scope.resolve("customerService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await customerService - .withTransaction(transactionManager) - .removeAddress(id, address_id) - }) - - const customer = await customerService.retrieve(id, { - relations: defaultStoreCustomersRelations, - select: defaultStoreCustomersFields, - }) - - res.json({ customer }) -} diff --git a/packages/medusa/src/api/routes/store/customers/get-customer.ts b/packages/medusa/src/api/routes/store/customers/get-customer.ts deleted file mode 100644 index eb24b11265..0000000000 --- a/packages/medusa/src/api/routes/store/customers/get-customer.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "." -import CustomerService from "../../../../services/customer" - -/** - * @oas [get] /store/customers/me - * operationId: GetCustomersCustomer - * summary: Get a Customer - * description: "Retrieve the logged-in Customer's details." - * x-authenticated: true - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.retrieve() - * .then(({ customer }) => { - * console.log(customer.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useMeCustomer } from "medusa-react" - * - * const Customer = () => { - * const { customer, isLoading } = useMeCustomer() - * - * return ( - *
- * {isLoading && Loading...} - * {customer && ( - * {customer.first_name} {customer.last_name} - * )} - *
- * ) - * } - * - * export default Customer - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/customers/me' \ - * -H 'Authorization: Bearer {access_token}' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customers - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCustomersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const id = req.user.customer_id - - const customerService: CustomerService = req.scope.resolve("customerService") - - const customer = await customerService.retrieve(id, { - relations: defaultStoreCustomersRelations, - select: defaultStoreCustomersFields, - }) - - res.json({ customer }) -} diff --git a/packages/medusa/src/api/routes/store/customers/get-payment-methods.ts b/packages/medusa/src/api/routes/store/customers/get-payment-methods.ts deleted file mode 100644 index b4c9380f64..0000000000 --- a/packages/medusa/src/api/routes/store/customers/get-payment-methods.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Customer } from "../../../.." -import CustomerService from "../../../../services/customer" -import PaymentProviderService from "../../../../services/payment-provider" -import { PaymentProvider } from "../../../../models" -import { promiseAll } from "@medusajs/utils" - -/** - * @oas [get] /store/customers/me/payment-methods - * operationId: GetCustomersCustomerPaymentMethods - * summary: Get Saved Payment Methods - * description: "Retrieve the logged-in customer's saved payment methods. This API Route only works with payment providers created with the deprecated Payment Service interface. - * The payment methods are saved using the Payment Service's third-party service, and not on the Medusa backend. So, they're retrieved from the third-party service." - * x-authenticated: true - * deprecated: true - * x-codegen: - * method: listPaymentMethods - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.paymentMethods.list() - * .then(({ payment_methods }) => { - * console.log(payment_methods.length); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/customers/me/payment-methods' \ - * -H 'Authorization: Bearer {access_token}' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customers - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCustomersListPaymentMethodsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const id = req.user.customer_id - - const paymentProviderService: PaymentProviderService = req.scope.resolve( - "paymentProviderService" - ) - - const customerService: CustomerService = req.scope.resolve("customerService") - - const customer: Customer = await customerService.retrieve(id) - - const paymentProviders: PaymentProvider[] = - await paymentProviderService.list() - - const methods = await promiseAll( - paymentProviders.map(async (paymentProvider: PaymentProvider) => { - const provider = paymentProviderService.retrieveProvider( - paymentProvider.id - ) - - const pMethods = await provider.retrieveSavedMethods(customer) - return pMethods.map((m) => ({ - provider_id: paymentProvider.id, - data: m, - })) - }) - ) - - res.json({ - payment_methods: methods.flat(), - }) -} diff --git a/packages/medusa/src/api/routes/store/customers/index.ts b/packages/medusa/src/api/routes/store/customers/index.ts deleted file mode 100644 index 7a9459ae60..0000000000 --- a/packages/medusa/src/api/routes/store/customers/index.ts +++ /dev/null @@ -1,295 +0,0 @@ -import { Router } from "express" -import { Customer, Order } from "../../../.." -import { PaginatedResponse } from "../../../../types/common" -import middlewares, { transformStoreQuery } from "../../../middlewares" -import { - defaultStoreOrdersFields, - defaultStoreOrdersRelations, -} from "../orders" -import { StoreGetCustomersCustomerOrdersParams } from "./list-orders" - -const route = Router() - -export default (app, container) => { - const middlewareService = container.resolve("middlewareService") - - app.use("/customers", route) - - // Inject plugin routes - const routers = middlewareService.getRouters("store/customers") - for (const router of routers) { - route.use("/", router) - } - - route.post("/", middlewares.wrap(require("./create-customer").default)) - - route.post( - "/password-reset", - middlewares.wrap(require("./reset-password").default) - ) - - route.post( - "/password-token", - middlewares.wrap(require("./reset-password-token").default) - ) - - // Authenticated endpoints - route.use(middlewares.requireCustomerAuthentication()) - - route.get("/me", middlewares.wrap(require("./get-customer").default)) - route.post("/me", middlewares.wrap(require("./update-customer").default)) - - route.get( - "/me/orders", - transformStoreQuery(StoreGetCustomersCustomerOrdersParams, { - defaultFields: defaultStoreOrdersFields, - defaultRelations: defaultStoreOrdersRelations, - isList: true, - }), - middlewares.wrap(require("./list-orders").default) - ) - - route.post( - "/me/addresses", - middlewares.wrap(require("./create-address").default) - ) - - route.post( - "/me/addresses/:address_id", - middlewares.wrap(require("./update-address").default) - ) - - route.delete( - "/me/addresses/:address_id", - middlewares.wrap(require("./delete-address").default) - ) - - route.get( - "/me/payment-methods", - middlewares.wrap(require("./get-payment-methods").default) - ) - - return app -} - -export const defaultStoreCustomersRelations = [ - "shipping_addresses", - "billing_address", -] - -export const defaultStoreCustomersFields: (keyof Customer)[] = [ - "id", - "email", - "first_name", - "last_name", - "billing_address_id", - "phone", - "has_account", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -export const allowedStoreCustomersRelations = [ - "shipping_addresses", - "billing_address", - "orders", -] - -export const allowedStoreCustomersFields = [ - "id", - "email", - "first_name", - "last_name", - "billing_address_id", - "phone", - "has_account", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -/** - * @schema StoreCustomersRes - * type: object - * description: "The customer's details." - * x-expanded-relations: - * field: customer - * relations: - * - billing_address - * - shipping_addresses - * required: - * - customer - * properties: - * customer: - * description: "Customer details." - * $ref: "#/components/schemas/Customer" - */ -export type StoreCustomersRes = { - customer: Omit -} - -/** - * @schema StoreCustomersResetPasswordRes - * type: object - * required: - * - customer - * properties: - * customer: - * description: "Customer details." - * $ref: "#/components/schemas/Customer" - */ -export type StoreCustomersResetPasswordRes = { - customer: Omit -} - -/** - * @schema StoreCustomersListOrdersRes - * type: object - * description: "The list of the customer's orders with pagination fields." - * x-expanded-relations: - * field: orders - * relations: - * - customer - * - discounts - * - discounts.rule - * - fulfillments - * - fulfillments.tracking_links - * - items - * - items.variant - * - payments - * - region - * - shipping_address - * - shipping_methods - * eager: - * - region.fulfillment_providers - * - region.payment_providers - * - shipping_methods.shipping_option - * implicit: - * - claims - * - claims.additional_items - * - claims.additional_items.adjustments - * - claims.additional_items.refundable - * - claims.additional_items.tax_lines - * - customer - * - discounts - * - discounts.rule - * - gift_card_transactions - * - gift_card_transactions.gift_card - * - gift_cards - * - items - * - items.adjustments - * - items.refundable - * - items.tax_lines - * - items.variant - * - items.variant.product - * - items.variant.product.profiles - * - refunds - * - region - * - shipping_address - * - shipping_methods - * - shipping_methods.tax_lines - * - swaps - * - swaps.additional_items - * - swaps.additional_items.adjustments - * - swaps.additional_items.refundable - * - swaps.additional_items.tax_lines - * totals: - * - discount_total - * - gift_card_tax_total - * - gift_card_total - * - paid_total - * - refundable_amount - * - refunded_total - * - shipping_total - * - subtotal - * - tax_total - * - total - * - claims.additional_items.discount_total - * - claims.additional_items.gift_card_total - * - claims.additional_items.original_tax_total - * - claims.additional_items.original_total - * - claims.additional_items.refundable - * - claims.additional_items.subtotal - * - claims.additional_items.tax_total - * - claims.additional_items.total - * - items.discount_total - * - items.gift_card_total - * - items.original_tax_total - * - items.original_total - * - items.refundable - * - items.subtotal - * - items.tax_total - * - items.total - * - swaps.additional_items.discount_total - * - swaps.additional_items.gift_card_total - * - swaps.additional_items.original_tax_total - * - swaps.additional_items.original_total - * - swaps.additional_items.refundable - * - swaps.additional_items.subtotal - * - swaps.additional_items.tax_total - * - swaps.additional_items.total - * required: - * - orders - * - count - * - offset - * - limit - * properties: - * orders: - * type: array - * description: "An array of orders details." - * items: - * $ref: "#/components/schemas/Order" - * count: - * description: The total number of items available - * type: integer - * offset: - * description: The number of orders skipped when retrieving the orders. - * type: integer - * limit: - * description: The number of items per page - * type: integer - */ -export type StoreCustomersListOrdersRes = PaginatedResponse & { - orders: Order[] -} - -/** - * @schema StoreCustomersListPaymentMethodsRes - * type: object - * description: "The payment method's details." - * required: - * - payment_methods - * properties: - * payment_methods: - * type: array - * description: "The details of the saved payment methods." - * items: - * type: object - * required: - * - provider_id - * - data - * properties: - * provider_id: - * description: The ID of the Payment Provider where the payment method is saved. - * type: string - * data: - * description: The data needed for the Payment Provider to use the saved payment method. - * type: object - */ -export type StoreCustomersListPaymentMethodsRes = { - payment_methods: { - provider_id: string - data: object - }[] -} - -export * from "./create-address" -export * from "./create-customer" -export * from "./list-orders" -export * from "./reset-password" -export * from "./reset-password-token" -export * from "./update-address" -export * from "./update-customer" diff --git a/packages/medusa/src/api/routes/store/customers/list-orders.ts b/packages/medusa/src/api/routes/store/customers/list-orders.ts deleted file mode 100644 index dbb85fcfcf..0000000000 --- a/packages/medusa/src/api/routes/store/customers/list-orders.ts +++ /dev/null @@ -1,375 +0,0 @@ -import { - IsEnum, - IsNumber, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { Request, Response } from "express" -import { - FulfillmentStatus, - OrderStatus, - PaymentStatus, -} from "../../../../models/order" - -import { Type } from "class-transformer" -import OrderService from "../../../../services/order" -import { DateComparisonOperator } from "../../../../types/common" - -/** - * @oas [get] /store/customers/me/orders - * operationId: GetCustomersCustomerOrders - * summary: List Orders - * description: "Retrieve a list of the logged-in Customer's Orders. The orders can be filtered by fields such as `status` or `fulfillment_status`. The orders can also be paginated." - * x-authenticated: true - * parameters: - * - (query) q {string} term to search orders' display ID, email, shipping address's first name, customer's first name, customer's last name, and customer's phone number. - * - (query) id {string} Filter by ID. - * - in: query - * name: status - * style: form - * explode: false - * description: Filter by status. - * schema: - * type: array - * items: - * type: string - * enum: [pending, completed, archived, canceled, requires_action] - * - in: query - * name: fulfillment_status - * style: form - * explode: false - * description: Fulfillment status to search for. - * schema: - * type: array - * items: - * type: string - * enum: [not_fulfilled, partially_fulfilled, fulfilled, partially_shipped, shipped, partially_returned, returned, canceled, requires_action] - * - in: query - * name: payment_status - * style: form - * explode: false - * description: Payment status to search for. - * schema: - * type: array - * items: - * type: string - * enum: [not_paid, awaiting, captured, partially_refunded, refunded, canceled, requires_action] - * - (query) display_id {string} Filter by display ID. - * - (query) cart_id {string} Filter by cart ID. - * - (query) email {string} Filter by email. - * - (query) region_id {string} Filter by region ID. - * - in: query - * name: currency_code - * style: form - * explode: false - * description: Filter by the 3 character ISO currency code of the order. - * schema: - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * - (query) tax_rate {string} Filter by tax rate. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: canceled_at - * description: Filter by a cancelation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - (query) limit=10 {integer} Limit the number of orders returned. - * - (query) offset=0 {integer} The number of orders to skip when retrieving the orders. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned orders. - * - (query) fields {string} Comma-separated fields that should be included in the returned orders. - * x-codegen: - * method: listOrders - * queryParams: StoreGetCustomersCustomerOrdersParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.listOrders() - * .then(({ orders, limit, offset, count }) => { - * console.log(orders); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCustomerOrders } from "medusa-react" - * - * const Orders = () => { - * // refetch a function that can be used to - * // re-retrieve orders after the customer logs in - * const { orders, isLoading } = useCustomerOrders() - * - * return ( - *
- * {isLoading && Loading orders...} - * {orders?.length && ( - *
    - * {orders.map((order) => ( - *
  • {order.display_id}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Orders - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/customers/me/orders' \ - * -H 'Authorization: Bearer {access_token}' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customers - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCustomersListOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const id: string | undefined = req.user?.customer_id - - const orderService: OrderService = req.scope.resolve("orderService") - - req.filterableFields = { - ...req.filterableFields, - customer_id: id, - } - - const [orders, count] = await orderService.listAndCount( - req.filterableFields, - req.listConfig - ) - - const { limit, offset } = req.validatedQuery - - res.json({ orders, count, offset: offset, limit: limit }) -} - -/** - * {@inheritDoc FindPaginationParams} - */ -export class StoreGetCustomersCustomerOrdersPaginationParams { - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 10 - */ - @IsOptional() - @IsNumber() - @Type(() => Number) - limit = 10 - - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsOptional() - @IsNumber() - @Type(() => Number) - offset = 0 - - /** - * {@inheritDoc FindParams.fields} - */ - @IsOptional() - @IsString() - fields?: string - - /** - * {@inheritDoc FindParams.expand} - */ - @IsOptional() - @IsString() - expand?: string -} - -/** - * Parameters used to filter and configure the pagination of the retrieved orders. - */ -// eslint-disable-next-line max-len -export class StoreGetCustomersCustomerOrdersParams extends StoreGetCustomersCustomerOrdersPaginationParams { - /** - * ID to filter orders by. - */ - @IsString() - @IsOptional() - id?: string - - /** - * Search term to search orders' display ID, email, shipping address's first name, customer's first name, customer's last name, and customer's phone number. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Statuses to filter orders by. - */ - @IsOptional() - @IsEnum(OrderStatus, { each: true }) - status?: OrderStatus[] - - /** - * Fulfillment statuses to filter orders by. - */ - @IsOptional() - @IsEnum(FulfillmentStatus, { each: true }) - fulfillment_status?: FulfillmentStatus[] - - /** - * Payment statuses to filter orders by. - */ - @IsOptional() - @IsEnum(PaymentStatus, { each: true }) - payment_status?: PaymentStatus[] - - /** - * Display ID to filter orders by. - */ - @IsString() - @IsOptional() - display_id?: string - - /** - * Cart ID to filter orders by. - */ - @IsString() - @IsOptional() - cart_id?: string - - /** - * Email to filter orders by. - */ - @IsString() - @IsOptional() - email?: string - - /** - * Region ID to filter orders by. - */ - @IsString() - @IsOptional() - region_id?: string - - /** - * Currency code to filter orders by. - */ - @IsString() - @IsOptional() - currency_code?: string - - /** - * Tax rate to filter orders by. - */ - @IsString() - @IsOptional() - tax_rate?: string - - /** - * Date filters to apply on the orders' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the orders' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on the orders' `canceled_at` date. - */ - @ValidateNested() - @IsOptional() - @Type(() => DateComparisonOperator) - canceled_at?: DateComparisonOperator -} diff --git a/packages/medusa/src/api/routes/store/customers/reset-password-token.ts b/packages/medusa/src/api/routes/store/customers/reset-password-token.ts deleted file mode 100644 index ff4ae6d920..0000000000 --- a/packages/medusa/src/api/routes/store/customers/reset-password-token.ts +++ /dev/null @@ -1,104 +0,0 @@ -import CustomerService from "../../../../services/customer" -import { IsEmail } from "class-validator" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" - -/** - * @oas [post] /store/customers/password-token - * operationId: PostCustomersCustomerPasswordToken - * summary: Request Password Reset - * description: "Create a reset password token to be used in a subsequent Reset Password API Route. This emits the event `customer.password_reset`. If a notification provider is - * installed in the Medusa backend and is configured to handle this event, a notification to the customer, such as an email, may be sent with reset instructions." - * externalDocs: - * description: "How to reset password" - * url: "https://docs.medusajs.com/modules/customers/storefront/implement-customer-profiles#reset-password" - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCustomersCustomerPasswordTokenReq" - * x-codegen: - * method: generatePasswordToken - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.customers.generatePasswordToken({ - * email: "user@example.com" - * }) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // failed - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/customers/password-token' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com" - * }' - * tags: - * - Customers - * responses: - * 204: - * description: OK - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = (await validator( - StorePostCustomersCustomerPasswordTokenReq, - req.body - )) as StorePostCustomersCustomerPasswordTokenReq - - const customerService: CustomerService = req.scope.resolve( - "customerService" - ) as CustomerService - - const customer = await customerService - .retrieveRegisteredByEmail(validated.email) - .catch(() => undefined) - - if (customer) { - // Will generate a token and send it to the customer via an email provider - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await customerService - .withTransaction(transactionManager) - .generateResetPasswordToken(customer.id) - }) - } - - res.sendStatus(204) -} - -/** - * @schema StorePostCustomersCustomerPasswordTokenReq - * type: object - * required: - * - email - * properties: - * email: - * description: "The customer's email." - * type: string - * format: email - */ -export class StorePostCustomersCustomerPasswordTokenReq { - @IsEmail() - email: string -} diff --git a/packages/medusa/src/api/routes/store/customers/reset-password.ts b/packages/medusa/src/api/routes/store/customers/reset-password.ts deleted file mode 100644 index abc18b40f9..0000000000 --- a/packages/medusa/src/api/routes/store/customers/reset-password.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { IsEmail, IsString } from "class-validator" -import jwt, { JwtPayload } from "jsonwebtoken" - -import CustomerService from "../../../../services/customer" -import { validator } from "../../../../utils/validator" -import { EntityManager } from "typeorm" -import { MedusaError } from "medusa-core-utils" - -/** - * @oas [post] /store/customers/password-reset - * operationId: PostCustomersResetPassword - * summary: Reset Password - * description: "Reset a Customer's password using a password token created by a previous request to the Request Password Reset API Route. If the password token expired, - * you must create a new one." - * externalDocs: - * description: "How to reset password" - * url: "https://docs.medusajs.com/modules/customers/storefront/implement-customer-profiles#reset-password" - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCustomersResetPasswordReq" - * x-codegen: - * method: resetPassword - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.customers.resetPassword({ - * email: "user@example.com", - * password: "supersecret", - * token: "supersecrettoken" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/customers/password-reset' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "email": "user@example.com", - * "password": "supersecret", - * "token": "supersecrettoken" - * }' - * tags: - * - Customers - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCustomersResetPasswordRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = (await validator( - StorePostCustomersResetPasswordReq, - req.body - )) as StorePostCustomersResetPasswordReq - - const customerService: CustomerService = req.scope.resolve("customerService") - let customer - - customer = await customerService - .retrieveRegisteredByEmail(validated.email, { - select: ["id", "password_hash"], - }) - .catch(() => undefined) - - const decodedToken = customer - ? jwt.verify(validated.token, customer.password_hash) - : undefined - if ( - !decodedToken || - customer.id !== (decodedToken as JwtPayload)?.customer_id - ) { - throw new MedusaError( - MedusaError.Types.UNAUTHORIZED, - "Invalid or expired password reset token" - ) - } - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await customerService - .withTransaction(transactionManager) - .update(customer.id, { - password: validated.password, - }) - }) - - customer = await customerService.retrieve(customer.id) - res.status(200).json({ customer }) -} - -/** - * @schema StorePostCustomersResetPasswordReq - * type: object - * required: - * - email - * - password - * - token - * properties: - * email: - * description: "The customer's email." - * type: string - * format: email - * password: - * description: "The customer's password." - * type: string - * format: password - * token: - * description: "The reset password token" - * type: string - */ -export class StorePostCustomersResetPasswordReq { - @IsEmail() - email: string - - @IsString() - token: string - - @IsString() - password: string -} diff --git a/packages/medusa/src/api/routes/store/customers/update-address.ts b/packages/medusa/src/api/routes/store/customers/update-address.ts deleted file mode 100644 index 5f1e3abb74..0000000000 --- a/packages/medusa/src/api/routes/store/customers/update-address.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "." - -import { EntityManager } from "typeorm" -import CustomerService from "../../../../services/customer" -import { AddressPayload } from "../../../../types/common" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /store/customers/me/addresses/{address_id} - * operationId: PostCustomersCustomerAddressesAddress - * summary: "Update a Shipping Address" - * description: "Update the logged-in customer's saved Shipping Address's details." - * x-authenticated: true - * parameters: - * - (path) address_id=* {String} The ID of the Address. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCustomersCustomerAddressesAddressReq" - * x-codegen: - * method: updateAddress - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.addresses.updateAddress(addressId, { - * first_name: "Gina" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/customers/me/addresses/{address_id}' \ - * -H 'Authorization: Bearer {access_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "first_name": "Gina" - * }' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customers - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCustomersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const id = req.user.customer_id - - const { address_id } = req.params - - const validated = await validator( - StorePostCustomersCustomerAddressesAddressReq, - req.body - ) - - const customerService: CustomerService = req.scope.resolve( - "customerService" - ) as CustomerService - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await customerService - .withTransaction(transactionManager) - .updateAddress(id, address_id, validated) - }) - - const customer = await customerService.retrieve(id, { - relations: defaultStoreCustomersRelations, - select: defaultStoreCustomersFields, - }) - - res.json({ customer }) -} - -/** - * @schema StorePostCustomersCustomerAddressesAddressReq - * anyOf: - * - $ref: "#/components/schemas/AddressPayload" - */ -// eslint-disable-next-line max-len -export class StorePostCustomersCustomerAddressesAddressReq extends AddressPayload {} diff --git a/packages/medusa/src/api/routes/store/customers/update-customer.ts b/packages/medusa/src/api/routes/store/customers/update-customer.ts deleted file mode 100644 index 1754b92400..0000000000 --- a/packages/medusa/src/api/routes/store/customers/update-customer.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { IsEmail, IsObject, IsOptional, IsString } from "class-validator" -import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "." - -import { EntityManager } from "typeorm" -import CustomerService from "../../../../services/customer" -import { AddressPayload } from "../../../../types/common" -import { validator } from "../../../../utils/validator" -import { IsType } from "../../../../utils/validators/is-type" - -/** - * @oas [post] /store/customers/me - * operationId: PostCustomersCustomer - * summary: Update Customer - * description: "Update the logged-in customer's details." - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCustomersCustomerReq" - * x-codegen: - * method: update - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged - * medusa.customers.update({ - * first_name: "Laury" - * }) - * .then(({ customer }) => { - * console.log(customer.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useUpdateMe } from "medusa-react" - * - * type Props = { - * customerId: string - * } - * - * const Customer = ({ customerId }: Props) => { - * const updateCustomer = useUpdateMe() - * // ... - * - * const handleUpdate = ( - * firstName: string - * ) => { - * // ... - * updateCustomer.mutate({ - * id: customerId, - * first_name: firstName, - * }, { - * onSuccess: ({ customer }) => { - * console.log(customer.first_name) - * } - * }) - * } - * - * // ... - * } - * - * export default Customer - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/customers/me' \ - * -H 'Authorization: Bearer {access_token}' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "first_name": "Laury" - * }' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Customers - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCustomersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const id = req.user.customer_id - - const validated = await validator(StorePostCustomersCustomerReq, req.body) - - const customerService: CustomerService = req.scope.resolve("customerService") - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - return await customerService - .withTransaction(transactionManager) - .update(id, validated) - }) - - const customer = await customerService.retrieve(id, { - relations: defaultStoreCustomersRelations, - select: defaultStoreCustomersFields, - }) - - res.status(200).json({ customer }) -} - -/** - * @schema StorePostCustomersCustomerReq - * type: object - * description: "The details to update of the customer." - * properties: - * first_name: - * description: "The customer's first name." - * type: string - * last_name: - * description: "The customer's last name." - * type: string - * billing_address: - * description: "The address to be used for billing purposes." - * anyOf: - * - $ref: "#/components/schemas/AddressPayload" - * description: The full billing address object - * - type: string - * description: The ID of an existing billing address - * password: - * description: "The customer's password." - * type: string - * phone: - * description: "The customer's phone number." - * type: string - * email: - * description: "The customer's email." - * type: string - * metadata: - * description: "Additional custom data about the customer." - * type: object - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ -export class StorePostCustomersCustomerReq { - @IsOptional() - @IsType([AddressPayload, String]) - billing_address?: AddressPayload | string - - @IsOptional() - @IsString() - first_name?: string - - @IsOptional() - @IsString() - last_name?: string - - @IsOptional() - @IsString() - password?: string - - @IsOptional() - @IsString() - phone?: string - - @IsOptional() - @IsEmail() - email?: string - - @IsOptional() - @IsObject() - metadata?: Record -} diff --git a/packages/medusa/src/api/routes/store/gift-cards/get-gift-card.ts b/packages/medusa/src/api/routes/store/gift-cards/get-gift-card.ts deleted file mode 100644 index 70d5aba5ba..0000000000 --- a/packages/medusa/src/api/routes/store/gift-cards/get-gift-card.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { defaultStoreGiftCardFields, defaultStoreGiftCardRelations } from "." - -import GiftCardService from "../../../../services/gift-card" -import { Logger } from "@medusajs/types" - -/** - * @oas [get] /store/gift-cards/{code} - * operationId: "GetGiftCardsCode" - * summary: "Get Gift Card by Code" - * description: "Retrieve a Gift Card's details by its associated unique code." - * parameters: - * - (path) code=* {string} The unique Gift Card code. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.giftCards.retrieve(code) - * .then(({ gift_card }) => { - * console.log(gift_card.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useGiftCard } from "medusa-react" - * - * type Props = { - * giftCardCode: string - * } - * - * const GiftCard = ({ giftCardCode }: Props) => { - * const { gift_card, isLoading, isError } = useGiftCard( - * giftCardCode - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {gift_card && {gift_card.value}} - * {isError && Gift Card does not exist} - *
- * ) - * } - * - * export default GiftCard - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/gift-cards/{code}' - * tags: - * - Gift Cards - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreGiftCardsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { code } = req.params - - try { - const giftCardService: GiftCardService = - req.scope.resolve("giftCardService") - const giftCard = await giftCardService.retrieveByCode(code, { - select: defaultStoreGiftCardFields, - relations: defaultStoreGiftCardRelations, - }) - - res.json({ gift_card: giftCard }) - } catch (error) { - const logger: Logger = req.scope.resolve("logger") - logger.log(error) - throw error - } -} diff --git a/packages/medusa/src/api/routes/store/gift-cards/index.ts b/packages/medusa/src/api/routes/store/gift-cards/index.ts deleted file mode 100644 index b1d06290b9..0000000000 --- a/packages/medusa/src/api/routes/store/gift-cards/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Router } from "express" -import middlewares from "../../../middlewares" -import { GiftCard } from "./../../../../" - -const route = Router() - -export default (app) => { - app.use("/gift-cards", route) - - route.get("/:code", middlewares.wrap(require("./get-gift-card").default)) - - return app -} - -export const defaultStoreGiftCardRelations = ["region"] - -export const defaultStoreGiftCardFields: (keyof GiftCard)[] = [ - "id", - "code", - "value", - "balance", -] - -export const allowedStoreGiftCardRelations = ["region"] - -export const allowedStoreGiftCardFields = ["id", "code", "value", "balance"] - -/** - * @schema StoreGiftCardsRes - * description: "The gift card's details." - * type: object - * required: - * - gift_card - * properties: - * gift_card: - * description: "Gift card details." - * $ref: "#/components/schemas/GiftCard" - */ -export type StoreGiftCardsRes = { - gift_card: GiftCard -} - -export * from "./get-gift-card" diff --git a/packages/medusa/src/api/routes/store/index.js b/packages/medusa/src/api/routes/store/index.js deleted file mode 100644 index c2629d4fee..0000000000 --- a/packages/medusa/src/api/routes/store/index.js +++ /dev/null @@ -1,61 +0,0 @@ -import cors from "cors" -import { Router } from "express" -import { parseCorsOrigins } from "medusa-core-utils" -import middlewares from "../../middlewares" -import productTypesRoutes from "../admin/product-types" -import authRoutes from "./auth" -import cartRoutes from "./carts" -import collectionRoutes from "./collections" -import customerRoutes from "./customers" -import giftCardRoutes from "./gift-cards" -import orderEditRoutes from "./order-edits" -import orderRoutes from "./orders" -import paymentCollectionRoutes from "./payment-collections" -import productCategoryRoutes from "./product-categories" -import productTagsRoutes from "./product-tags" -import productRoutes from "./products" -import regionRoutes from "./regions" -import returnReasonRoutes from "./return-reasons" -import returnRoutes from "./returns" -import shippingOptionRoutes from "./shipping-options" -import swapRoutes from "./swaps" -import variantRoutes from "./variants" - -const route = Router() - -export default (app, container, config) => { - app.use("/store", route) - - const featureFlagRouter = container.resolve("featureFlagRouter") - const storeCors = config.store_cors || "" - - route.use( - cors({ - origin: parseCorsOrigins(storeCors), - credentials: true, - }) - ) - - route.use(middlewares.authenticateCustomer()) - - authRoutes(route) - collectionRoutes(route) - customerRoutes(route, container) - productRoutes(route, featureFlagRouter) - productTagsRoutes(route) - productTypesRoutes(route) - orderRoutes(route) - orderEditRoutes(route) - cartRoutes(route, container) - shippingOptionRoutes(route) - regionRoutes(route, featureFlagRouter) - swapRoutes(route) - variantRoutes(route) - returnRoutes(route) - giftCardRoutes(route) - returnReasonRoutes(route) - paymentCollectionRoutes(route) - productCategoryRoutes(route) - - return app -} diff --git a/packages/medusa/src/api/routes/store/order-edits/__tests__/complete-order-edit.ts b/packages/medusa/src/api/routes/store/order-edits/__tests__/complete-order-edit.ts deleted file mode 100644 index e76ac939d7..0000000000 --- a/packages/medusa/src/api/routes/store/order-edits/__tests__/complete-order-edit.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" - -describe("GET /store/order-edits/:id/complete", () => { - describe("successfully complete an order edit", () => { - const orderEditId = IdMap.getId("testRequestOrder") - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/store/order-edits/${orderEditId}/complete`, - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService confirm", () => { - expect(orderEditServiceMock.confirm).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.confirm).toHaveBeenCalledWith(orderEditId, { - loggedInUserId: undefined, - }) - expect(orderEditServiceMock.decorateTotals).toHaveBeenCalledTimes(1) - }) - - it("returns orderEdit", () => { - expect(subject.body.order_edit.id).toEqual(orderEditId) - }) - }) - - describe("idempotently complete an order edit", () => { - const orderEditId = IdMap.getId("testConfirmOrderEdit") - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/store/order-edits/${orderEditId}/complete`, - { - clientSession: { - jwt: { - user: IdMap.getId("lebron"), - }, - }, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService confirm", () => { - expect(orderEditServiceMock.confirm).toHaveBeenCalledTimes(0) - expect(orderEditServiceMock.decorateTotals).toHaveBeenCalledTimes(1) - }) - - it("returns orderEdit", () => { - expect(subject.body.order_edit.id).toEqual(orderEditId) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/order-edits/__tests__/decline-order-edit.ts b/packages/medusa/src/api/routes/store/order-edits/__tests__/decline-order-edit.ts deleted file mode 100644 index c8cd8af90a..0000000000 --- a/packages/medusa/src/api/routes/store/order-edits/__tests__/decline-order-edit.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" - -describe("GET /store/order-edits/:id/decline", () => { - describe("successfully decline an order edit", () => { - const orderEditId = IdMap.getId("testDeclineOrderEdit") - let subject - - const payload = { - declined_reason: "test", - } - - beforeAll(async () => { - subject = await request( - "POST", - `/store/order-edits/${orderEditId}/decline`, - { - payload, - } - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService decline", () => { - expect(orderEditServiceMock.decline).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.decline).toHaveBeenCalledWith(orderEditId, { - declinedReason: "test", - loggedInUserId: undefined, - }) - expect(orderEditServiceMock.decorateTotals).toHaveBeenCalledTimes(1) - }) - - it("returns orderEdit", () => { - expect(subject.body.order_edit.id).toEqual(orderEditId) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/order-edits/__tests__/get-order.ts b/packages/medusa/src/api/routes/store/order-edits/__tests__/get-order.ts deleted file mode 100644 index 833dabce2b..0000000000 --- a/packages/medusa/src/api/routes/store/order-edits/__tests__/get-order.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { orderEditServiceMock } from "../../../../../services/__mocks__/order-edit" -import { - defaultStoreOrderEditFields, - defaultStoreOrderEditRelations -} from "../../../../../types/order-edit" - -describe("GET /store/order-edits/:id", () => { - describe("successfully gets an order edit", () => { - const orderEditId = IdMap.getId("testCreatedOrder") - let subject - - beforeAll(async () => { - subject = await request("GET", `/store/order-edits/${orderEditId}`) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService retrieve", () => { - expect(orderEditServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(orderEditServiceMock.retrieve).toHaveBeenCalledWith(orderEditId, { - select: defaultStoreOrderEditFields, - relations: defaultStoreOrderEditRelations, - }) - expect(orderEditServiceMock.decorateTotals).toHaveBeenCalledTimes(1) - }) - - it("returns order", () => { - expect(subject.body.order_edit.id).toEqual(orderEditId) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/order-edits/complete-order-edit.ts b/packages/medusa/src/api/routes/store/order-edits/complete-order-edit.ts deleted file mode 100644 index b584524174..0000000000 --- a/packages/medusa/src/api/routes/store/order-edits/complete-order-edit.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { Request, Response } from "express" -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { OrderEditStatus, PaymentCollectionStatus } from "../../../../models" -import { OrderEditService, PaymentProviderService } from "../../../../services" -import { - defaultStoreOrderEditFields, - defaultStoreOrderEditRelations, -} from "../../../../types/order-edit" - -/** - * @oas [post] /store/order-edits/{id}/complete - * operationId: "PostOrderEditsOrderEditComplete" - * summary: "Complete an Order Edit" - * description: "Complete an Order Edit and reflect its changes on the original order. Any additional payment required must be authorized first using the Payment Collection API Routes." - * externalDocs: - * description: "How to handle order edits in a storefront" - * url: "https://docs.medusajs.com/modules/orders/storefront/handle-order-edits" - * parameters: - * - (path) id=* {string} The ID of the Order Edit. - * x-codegen: - * method: complete - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.orderEdits.complete(orderEditId) - * .then(({ order_edit }) => { - * console.log(order_edit.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCompleteOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const completeOrderEdit = useCompleteOrderEdit( - * orderEditId - * ) - * // ... - * - * const handleCompleteOrderEdit = () => { - * completeOrderEdit.mutate(void 0, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.confirmed_at) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/order-edits/{id}/complete' - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreOrderEditsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - - const orderEditService: OrderEditService = - req.scope.resolve("orderEditService") - - const paymentProviderService: PaymentProviderService = req.scope.resolve( - "paymentProviderService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - - const userId = req.user?.customer_id ?? req.user?.id ?? req.user?.userId - - await manager.transaction(async (manager) => { - const orderEditServiceTx = orderEditService.withTransaction(manager) - const paymentProviderServiceTx = - paymentProviderService.withTransaction(manager) - - const orderEdit = await orderEditServiceTx.retrieve(id, { - relations: ["payment_collection", "payment_collection.payments"], - }) - - const allowedStatus = [OrderEditStatus.REQUESTED, OrderEditStatus.CONFIRMED] - if ( - orderEdit.payment_collection && - allowedStatus.includes(orderEdit.status) - ) { - if ( - orderEdit.payment_collection.status !== - PaymentCollectionStatus.AUTHORIZED - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Unable to complete an order edit if the payment is not authorized" - ) - } - - if (orderEdit.payment_collection) { - for (const payment of orderEdit.payment_collection.payments) { - if (payment.order_id !== orderEdit.order_id) { - await paymentProviderServiceTx.updatePayment(payment.id, { - order_id: orderEdit.order_id, - }) - } - } - } - } - - if (orderEdit.status === OrderEditStatus.CONFIRMED) { - return orderEdit - } - - if (orderEdit.status !== OrderEditStatus.REQUESTED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Cannot complete an order edit with status ${orderEdit.status}` - ) - } - - const returned = await orderEditServiceTx.confirm(id, { - confirmedBy: userId, - }) - - return returned - }) - - let orderEdit = await orderEditService.retrieve(id, { - select: defaultStoreOrderEditFields, - relations: defaultStoreOrderEditRelations, - }) - orderEdit = await orderEditService.decorateTotals(orderEdit) - - res.status(200).json({ order_edit: orderEdit }) -} diff --git a/packages/medusa/src/api/routes/store/order-edits/decline-order-edit.ts b/packages/medusa/src/api/routes/store/order-edits/decline-order-edit.ts deleted file mode 100644 index d3b92f6bb9..0000000000 --- a/packages/medusa/src/api/routes/store/order-edits/decline-order-edit.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { IsOptional, IsString } from "class-validator" -import { Request, Response } from "express" -import { EntityManager } from "typeorm" -import { OrderEditService } from "../../../../services" -import { - defaultStoreOrderEditFields, - defaultStoreOrderEditRelations, -} from "../../../../types/order-edit" - -/** - * @oas [post] /store/order-edits/{id}/decline - * operationId: "PostOrderEditsOrderEditDecline" - * summary: "Decline an Order Edit" - * description: "Decline an Order Edit. The changes are not reflected on the original order." - * parameters: - * - (path) id=* {string} The ID of the OrderEdit. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostOrderEditsOrderEditDecline" - * x-codegen: - * method: decline - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.orderEdits.decline(orderEditId) - * .then(({ order_edit }) => { - * console.log(order_edit.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useDeclineOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const declineOrderEdit = useDeclineOrderEdit(orderEditId) - * // ... - * - * const handleDeclineOrderEdit = ( - * declinedReason: string - * ) => { - * declineOrderEdit.mutate({ - * declined_reason: declinedReason, - * }, { - * onSuccess: ({ order_edit }) => { - * console.log(order_edit.declined_at) - * } - * }) - * } - * - * // ... - * } - * - * export default OrderEdit - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/order-edits/{id}/decline' - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreOrderEditsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - const { validatedBody } = req as { - validatedBody: StorePostOrderEditsOrderEditDecline - } - - const orderEditService: OrderEditService = - req.scope.resolve("orderEditService") - - const manager: EntityManager = req.scope.resolve("manager") - - const userId = req.user?.customer_id ?? req.user?.id ?? req.user?.userId - - await manager.transaction(async (manager) => { - await orderEditService.withTransaction(manager).decline(id, { - declinedReason: validatedBody.declined_reason, - declinedBy: userId, - }) - }) - - let orderEdit = await orderEditService.retrieve(id, { - select: defaultStoreOrderEditFields, - relations: defaultStoreOrderEditRelations, - }) - orderEdit = await orderEditService.decorateTotals(orderEdit) - - res.status(200).json({ order_edit: orderEdit }) -} - -/** - * @schema StorePostOrderEditsOrderEditDecline - * type: object - * description: "The details of the order edit's decline." - * properties: - * declined_reason: - * type: string - * description: The reason for declining the Order Edit. - */ -export class StorePostOrderEditsOrderEditDecline { - @IsOptional() - @IsString() - declined_reason?: string -} diff --git a/packages/medusa/src/api/routes/store/order-edits/get-order-edit.ts b/packages/medusa/src/api/routes/store/order-edits/get-order-edit.ts deleted file mode 100644 index 8ed86f0b23..0000000000 --- a/packages/medusa/src/api/routes/store/order-edits/get-order-edit.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Request, Response } from "express" -import { OrderEditService } from "../../../../services" - -/** - * @oas [get] /store/order-edits/{id} - * operationId: "GetOrderEditsOrderEdit" - * summary: "Retrieve an Order Edit" - * description: "Retrieve an Order Edit's details." - * parameters: - * - (path) id=* {string} The ID of the OrderEdit. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.orderEdits.retrieve(orderEditId) - * .then(({ order_edit }) => { - * console.log(order_edit.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useOrderEdit } from "medusa-react" - * - * type Props = { - * orderEditId: string - * } - * - * const OrderEdit = ({ orderEditId }: Props) => { - * const { order_edit, isLoading } = useOrderEdit(orderEditId) - * - * return ( - *
- * {isLoading && Loading...} - * {order_edit && ( - *
    - * {order_edit.changes.map((change) => ( - *
  • {change.type}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default OrderEdit - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/order-edits/{id}' - * tags: - * - Order Edits - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreOrderEditsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const orderEditService: OrderEditService = - req.scope.resolve("orderEditService") - - const { id } = req.params - const retrieveConfig = req.retrieveConfig - - let orderEdit = await orderEditService.retrieve(id, retrieveConfig) - orderEdit = await orderEditService.decorateTotals(orderEdit) - - return res.json({ order_edit: orderEdit }) -} diff --git a/packages/medusa/src/api/routes/store/order-edits/index.ts b/packages/medusa/src/api/routes/store/order-edits/index.ts deleted file mode 100644 index 531aee1125..0000000000 --- a/packages/medusa/src/api/routes/store/order-edits/index.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { Router } from "express" -import { OrderEdit } from "../../../../models" -import { FindParams } from "../../../../types/common" -import { - defaultStoreOrderEditFields, - defaultStoreOrderEditRelations, -} from "../../../../types/order-edit" -import middlewares, { - transformBody, - transformStoreQuery, -} from "../../../middlewares" -import { StorePostOrderEditsOrderEditDecline } from "./decline-order-edit" - -const route = Router() - -export default (app) => { - app.use("/order-edits", route) - - route.get( - "/:id", - transformStoreQuery(FindParams, { - defaultRelations: defaultStoreOrderEditRelations, - defaultFields: defaultStoreOrderEditFields, - allowedFields: defaultStoreOrderEditFields, - isList: false, - }), - middlewares.wrap(require("./get-order-edit").default) - ) - - route.post( - "/:id/decline", - transformBody(StorePostOrderEditsOrderEditDecline), - middlewares.wrap(require("./decline-order-edit").default) - ) - - route.post( - "/:id/complete", - middlewares.wrap(require("./complete-order-edit").default) - ) - - return app -} - -/** - * @schema StoreOrderEditsRes - * type: object - * description: "The order edit's details." - * x-expanded-relations: - * field: order_edit - * relations: - * - changes - * - changes.line_item - * - changes.line_item.variant - * - changes.original_line_item - * - changes.original_line_item.variant - * - items - * - items.adjustments - * - items.tax_lines - * - items.variant - * - payment_collection - * implicit: - * - items - * - items.tax_lines - * - items.adjustments - * - items.variant - * totals: - * - difference_due - * - discount_total - * - gift_card_tax_total - * - gift_card_total - * - shipping_total - * - subtotal - * - tax_total - * - total - * - items.discount_total - * - items.gift_card_total - * - items.original_tax_total - * - items.original_total - * - items.refundable - * - items.subtotal - * - items.tax_total - * - items.total - * required: - * - order_edit - * properties: - * order_edit: - * description: "Order edit details." - * $ref: "#/components/schemas/OrderEdit" - */ -export type StoreOrderEditsRes = { - order_edit: Omit< - OrderEdit, - "internal_note" | "created_by" | "confirmed_by" | "canceled_by" - > -} - -export * from "./decline-order-edit" diff --git a/packages/medusa/src/api/routes/store/orders/__tests__/get-order-by-cart.js b/packages/medusa/src/api/routes/store/orders/__tests__/get-order-by-cart.js deleted file mode 100644 index 37bc33cf59..0000000000 --- a/packages/medusa/src/api/routes/store/orders/__tests__/get-order-by-cart.js +++ /dev/null @@ -1,38 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { defaultStoreOrdersFields, defaultStoreOrdersRelations } from ".." -import { request } from "../../../../../helpers/test-request" -import { OrderServiceMock } from "../../../../../services/__mocks__/order" - -describe("GET /store/orders", () => { - describe("successfully gets an order", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/store/orders/cart/${IdMap.getId("test-cart")}` - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService retrieve", () => { - expect(OrderServiceMock.retrieveByCartIdWithTotals).toHaveBeenCalledTimes( - 1 - ) - expect(OrderServiceMock.retrieveByCartIdWithTotals).toHaveBeenCalledWith( - IdMap.getId("test-cart"), - { - select: defaultStoreOrdersFields, - relations: defaultStoreOrdersRelations, - } - ) - }) - - it("returns order", () => { - expect(subject.body.order.id).toEqual(IdMap.getId("test-order")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/orders/__tests__/get-order.js b/packages/medusa/src/api/routes/store/orders/__tests__/get-order.js deleted file mode 100644 index 0373d3dcb1..0000000000 --- a/packages/medusa/src/api/routes/store/orders/__tests__/get-order.js +++ /dev/null @@ -1,36 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { defaultStoreOrdersFields, defaultStoreOrdersRelations } from ".." -import { request } from "../../../../../helpers/test-request" -import { OrderServiceMock } from "../../../../../services/__mocks__/order" - -describe("GET /store/orders", () => { - describe("successfully gets an order", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/store/orders/${IdMap.getId("test-order")}` - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService retrieve", () => { - expect(OrderServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - expect(OrderServiceMock.retrieveWithTotals).toHaveBeenCalledWith( - IdMap.getId("test-order"), - { - select: defaultStoreOrdersFields, - relations: defaultStoreOrdersRelations, - } - ) - }) - - it("returns order", () => { - expect(subject.body.order.id).toEqual(IdMap.getId("test-order")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/orders/__tests__/lookup-order.js b/packages/medusa/src/api/routes/store/orders/__tests__/lookup-order.js deleted file mode 100644 index 3db679441c..0000000000 --- a/packages/medusa/src/api/routes/store/orders/__tests__/lookup-order.js +++ /dev/null @@ -1,21 +0,0 @@ -import { request } from "../../../../../helpers/test-request" -import { OrderServiceMock } from "../../../../../services/__mocks__/order" - -describe("GET /store/orders", () => { - describe("successfully looksup an order passing param validation", () => { - beforeAll(async () => { - await request( - "GET", - `/store/orders/?display_id=67007&email=tester%40medusa-commerce.com&shipping_address[postal_code]=23232` - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls orderService list", () => { - expect(OrderServiceMock.list).toHaveBeenCalledTimes(1) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/orders/confirm-order-request.ts b/packages/medusa/src/api/routes/store/orders/confirm-order-request.ts deleted file mode 100644 index 68626fa55c..0000000000 --- a/packages/medusa/src/api/routes/store/orders/confirm-order-request.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { IsJWT, IsNotEmpty } from "class-validator" -import { EntityManager } from "typeorm" -import { - CustomerService, - OrderService, - TokenService, -} from "../../../../services" -import { promiseAll } from "@medusajs/utils" - -/** - * @oas [post] /store/orders/customer/confirm - * operationId: "PostOrdersCustomerOrderClaimsCustomerOrderClaimAccept" - * summary: "Verify Order Claim" - * description: "Verify the claim order token provided to the customer when they request ownership of an order." - * externalDocs: - * description: "How to implement claim-order flow in a storefront" - * url: "https://docs.medusajs.com/modules/orders/storefront/implement-claim-order" - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCustomersCustomerAcceptClaimReq" - * x-codegen: - * method: confirmRequest - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.orders.confirmRequest( - * token, - * ) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // an error occurred - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useGrantOrderAccess } from "medusa-react" - * - * const ClaimOrder = () => { - * const confirmOrderRequest = useGrantOrderAccess() - * - * const handleOrderRequestConfirmation = ( - * token: string - * ) => { - * confirmOrderRequest.mutate({ - * token - * }, { - * onSuccess: () => { - * // successful - * }, - * onError: () => { - * // an error occurred. - * } - * }) - * } - * - * // ... - * } - * - * export default ClaimOrder - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/orders/customer/confirm' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "token": "{token}", - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { token } = req.validatedBody - - const orderSerivce: OrderService = req.scope.resolve("orderService") - const customerService: CustomerService = req.scope.resolve("customerService") - const tokenService: TokenService = req.scope.resolve( - TokenService.RESOLUTION_KEY - ) - - const orderService: OrderService = req.scope.resolve("orderService") - - const manager: EntityManager = req.scope.resolve("manager") - await manager.transaction(async (transactionManager) => { - const { claimingCustomerId, orders: orderIds } = tokenService.verifyToken( - token, - { - maxAge: "15m", - } - ) as { - claimingCustomerId: string - orders: string[] - } - - const customer = await customerService - .withTransaction(transactionManager) - .retrieve(claimingCustomerId) - - const orders = await orderService.list({ id: orderIds }) - - await promiseAll( - orders.map(async (order) => { - await orderSerivce - .withTransaction(transactionManager) - .update(order.id, { - customer_id: claimingCustomerId, - email: customer.email, - }) - }) - ) - }) - - res.sendStatus(200) -} - -/** - * @schema StorePostCustomersCustomerAcceptClaimReq - * type: object - * description: "The details necessary to grant order access." - * required: - * - token - * properties: - * token: - * description: "The claim token generated by previous request to the Claim Order API Route." - * type: string - */ -export class StorePostCustomersCustomerAcceptClaimReq { - @IsNotEmpty() - @IsJWT() - token: string -} 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 deleted file mode 100644 index 77e76c09e5..0000000000 --- a/packages/medusa/src/api/routes/store/orders/get-order-by-cart.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { OrderService } from "../../../../services" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [get] /store/orders/cart/{cart_id} - * operationId: GetOrdersOrderCartId - * summary: Get by Cart ID - * description: "Retrieve an Order's details by the ID of the Cart that was used to create the Order." - * parameters: - * - (path) cart_id=* {string} The ID of Cart. - * x-codegen: - * method: retrieveByCartId - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.orders.retrieveByCartId(cartId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCartOrder } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const Order = ({ cartId }: Props) => { - * const { - * order, - * isLoading, - * } = useCartOrder(cartId) - * - * return ( - *
- * {isLoading && Loading...} - * {order && {order.display_id}} - * - *
- * ) - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/orders/cart/{cart_id}' - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { cart_id } = req.params - - const orderService: OrderService = req.scope.resolve("orderService") - - const order = await orderService.retrieveByCartIdWithTotals( - cart_id, - req.retrieveConfig - ) - - res.json({ order: cleanResponseData(order, []) }) -} diff --git a/packages/medusa/src/api/routes/store/orders/get-order.ts b/packages/medusa/src/api/routes/store/orders/get-order.ts deleted file mode 100644 index a62e5cda56..0000000000 --- a/packages/medusa/src/api/routes/store/orders/get-order.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { OrderService } from "../../../../services" -import { FindParams } from "../../../../types/common" -import { cleanResponseData } from "../../../../utils/clean-response-data" - -/** - * @oas [get] /store/orders/{id} - * operationId: GetOrdersOrder - * summary: Get an Order - * description: "Retrieve an Order's details." - * parameters: - * - (path) id=* {string} The ID of the Order. - * - (query) fields {string} Comma-separated fields that should be expanded in the returned order. - * - (query) expand {string} Comma-separated relations that should be included in the returned order. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.orders.retrieve(orderId) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useOrder } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * const Order = ({ orderId }: Props) => { - * const { - * order, - * isLoading, - * } = useOrder(orderId) - * - * return ( - *
- * {isLoading && Loading...} - * {order && {order.display_id}} - * - *
- * ) - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/orders/{id}' - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const orderService: OrderService = req.scope.resolve("orderService") - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig) - - res.json({ - order: cleanResponseData(order, req.allowedProperties || []), - }) -} - -export class StoreGetOrderParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/store/orders/index.ts b/packages/medusa/src/api/routes/store/orders/index.ts deleted file mode 100644 index f2be3de834..0000000000 --- a/packages/medusa/src/api/routes/store/orders/index.ts +++ /dev/null @@ -1,228 +0,0 @@ -import { Router } from "express" -import "reflect-metadata" -import { Order } from "../../../.." -import { FindParams } from "../../../../types/common" -import middlewares, { - transformBody, - transformStoreQuery, -} from "../../../middlewares" -import requireCustomerAuthentication from "../../../middlewares/require-customer-authentication" -import { StorePostCustomersCustomerAcceptClaimReq } from "./confirm-order-request" -import { StoreGetOrderParams } from "./get-order" -import { StoreGetOrdersParams } from "./lookup-order" -import { StorePostCustomersCustomerOrderClaimReq } from "./request-order" - -const route = Router() - -export default (app) => { - app.use("/orders", route) - - /** - * Lookup - */ - route.get( - "/", - transformStoreQuery(StoreGetOrdersParams, { - defaultFields: defaultStoreOrdersFields, - defaultRelations: defaultStoreOrdersRelations, - allowedFields: allowedStoreOrdersFields, - allowedRelations: allowedStoreOrdersRelations, - isList: true, - }), - middlewares.wrap(require("./lookup-order").default) - ) - - /** - * Retrieve Order - */ - route.get( - "/:id", - transformStoreQuery(StoreGetOrderParams, { - defaultFields: defaultStoreOrdersFields, - defaultRelations: defaultStoreOrdersRelations, - allowedFields: allowedStoreOrdersFields, - allowedRelations: allowedStoreOrdersRelations, - }), - middlewares.wrap(require("./get-order").default) - ) - - /** - * Retrieve by Cart Id - */ - route.get( - "/cart/:cart_id", - transformStoreQuery(FindParams, { - defaultFields: defaultStoreOrdersFields, - defaultRelations: defaultStoreOrdersRelations, - allowedFields: allowedStoreOrdersFields, - allowedRelations: allowedStoreOrdersRelations, - }), - middlewares.wrap(require("./get-order-by-cart").default) - ) - - route.post( - "/customer/confirm", - transformBody(StorePostCustomersCustomerAcceptClaimReq), - middlewares.wrap(require("./confirm-order-request").default) - ) - - route.post( - "/batch/customer/token", - requireCustomerAuthentication(), - transformBody(StorePostCustomersCustomerOrderClaimReq), - middlewares.wrap(require("./request-order").default) - ) - - return app -} - -export const defaultStoreOrdersRelations = [ - "shipping_address", - "fulfillments", - "fulfillments.tracking_links", - "items", - "items.variant", - "shipping_methods", - "shipping_methods.shipping_option", - "discounts", - "discounts.rule", - "customer", - "payments", - "region", -] - -export const allowedStoreOrdersRelations = [ - ...defaultStoreOrdersRelations, - "billing_address", -] - -export const defaultStoreOrdersFields = [ - "id", - "status", - "fulfillment_status", - "payment_status", - "display_id", - "cart_id", - "customer_id", - "email", - "region_id", - "currency_code", - "tax_rate", - "created_at", -] as (keyof Order)[] - -export const allowedStoreOrdersFields = [ - ...defaultStoreOrdersFields, - "object", - "shipping_total", - "discount_total", - "tax_total", - "refunded_total", - "total", - "subtotal", - "paid_total", - "refundable_amount", - "gift_card_total", - "gift_card_tax_total", - "items.refundable", -] - -/** - * @schema StoreOrdersRes - * type: object - * description: "The order's details." - * required: - * - order - * x-expanded-relations: - * field: order - * relations: - * - customer - * - discounts - * - discounts.rule - * - fulfillments - * - fulfillments.tracking_links - * - items - * - items.variant - * - payments - * - region - * - shipping_address - * - shipping_methods - * eager: - * - fulfillments.items - * - region.fulfillment_providers - * - region.payment_providers - * - shipping_methods.shipping_option - * implicit: - * - claims - * - claims.additional_items - * - claims.additional_items.adjustments - * - claims.additional_items.refundable - * - claims.additional_items.tax_lines - * - discounts - * - discounts.rule - * - gift_card_transactions - * - gift_card_transactions.gift_card - * - gift_cards - * - items - * - items.adjustments - * - items.refundable - * - items.tax_lines - * - items.variant - * - items.variant.product - * - items.variant.product.profiles - * - refunds - * - region - * - shipping_methods - * - shipping_methods.tax_lines - * - swaps - * - swaps.additional_items - * - swaps.additional_items.adjustments - * - swaps.additional_items.refundable - * - swaps.additional_items.tax_lines - * totals: - * - discount_total - * - gift_card_tax_total - * - gift_card_total - * - paid_total - * - refundable_amount - * - refunded_total - * - shipping_total - * - subtotal - * - tax_total - * - total - * - claims.additional_items.discount_total - * - claims.additional_items.gift_card_total - * - claims.additional_items.original_tax_total - * - claims.additional_items.original_total - * - claims.additional_items.refundable - * - claims.additional_items.subtotal - * - claims.additional_items.tax_total - * - claims.additional_items.total - * - items.discount_total - * - items.gift_card_total - * - items.original_tax_total - * - items.original_total - * - items.refundable - * - items.subtotal - * - items.tax_total - * - items.total - * - swaps.additional_items.discount_total - * - swaps.additional_items.gift_card_total - * - swaps.additional_items.original_tax_total - * - swaps.additional_items.original_total - * - swaps.additional_items.refundable - * - swaps.additional_items.subtotal - * - swaps.additional_items.tax_total - * - swaps.additional_items.total - * properties: - * order: - * description: "Order details." - * $ref: "#/components/schemas/Order" - */ -export type StoreOrdersRes = { - order: Order -} - -export * from "./confirm-order-request" -export * from "./lookup-order" -export * from "./request-order" diff --git a/packages/medusa/src/api/routes/store/orders/lookup-order.ts b/packages/medusa/src/api/routes/store/orders/lookup-order.ts deleted file mode 100644 index 977a7470ec..0000000000 --- a/packages/medusa/src/api/routes/store/orders/lookup-order.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { - IsEmail, - IsNumber, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { Type } from "class-transformer" - -import { OrderService } from "../../../../services" -import { cleanResponseData } from "../../../../utils/clean-response-data" -import { FindParams } from "../../../../types/common" - -/** - * @oas [get] /store/orders - * operationId: "GetOrders" - * summary: "Look Up an Order" - * description: "Look up an order using filters. If the filters don't narrow down the results to a single order, a 404 response is returned with no orders." - * parameters: - * - (query) display_id=* {number} Filter by ID. - * - (query) fields {string} Comma-separated fields that should be expanded in the returned order. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned order. - * - in: query - * name: email - * style: form - * explode: false - * description: Filter by email. - * required: true - * schema: - * type: string - * format: email - * - in: query - * name: shipping_address - * style: form - * explode: false - * description: Filter by the shipping address's postal code. - * schema: - * type: object - * properties: - * postal_code: - * type: string - * description: The postal code of the shipping address - * x-codegen: - * method: lookupOrder - * queryParams: StoreGetOrdersParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.orders.lookupOrder({ - * display_id: 1, - * email: "user@example.com" - * }) - * .then(({ order }) => { - * console.log(order.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useOrders } from "medusa-react" - * - * type Props = { - * displayId: number - * email: string - * } - * - * const Order = ({ - * displayId, - * email - * }: Props) => { - * const { - * order, - * isLoading, - * } = useOrders({ - * display_id: displayId, - * email, - * }) - * - * return ( - *
- * {isLoading && Loading...} - * {order && {order.display_id}} - * - *
- * ) - * } - * - * export default Order - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/orders?display_id=1&email=user@example.com' - * tags: - * - Orders - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreOrdersRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = req.validatedQuery as StoreGetOrdersParams - - const orderService: OrderService = req.scope.resolve("orderService") - - const orders = await orderService.list( - { - display_id: validated.display_id, - email: validated.email, - }, - req.listConfig - ) - - if (orders.length !== 1) { - res.sendStatus(404) - return - } - - const order = orders[0] - - res.json({ - order: cleanResponseData(order, req.allowedProperties || []), - }) -} - -/** - * Filters to apply on the order's shipping address. - */ -export class ShippingAddressPayload { - /** - * Postal code. - */ - @IsOptional() - @IsString() - postal_code?: string -} - -/** - * Filters to narrow down the looked-up order, with configurations applied on the retrieved order. - */ -export class StoreGetOrdersParams extends FindParams { - /** - * Display ID of the order. - */ - @IsNumber() - @Type(() => Number) - display_id: number - - /** - * Email of the order. - */ - @IsEmail() - email: string - - /** - * Filter the retrieved order by its shipping address details. - */ - @IsOptional() - @ValidateNested() - @Type(() => ShippingAddressPayload) - shipping_address?: ShippingAddressPayload -} diff --git a/packages/medusa/src/api/routes/store/orders/request-order.ts b/packages/medusa/src/api/routes/store/orders/request-order.ts deleted file mode 100644 index 0acd2f454f..0000000000 --- a/packages/medusa/src/api/routes/store/orders/request-order.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { promiseAll } from "@medusajs/utils" -import { IsNotEmpty, IsString } from "class-validator" -import { MedusaError } from "medusa-core-utils" -import { CustomerService, OrderService } from "../../../../services" -import EventBusService from "../../../../services/event-bus" -import TokenService from "../../../../services/token" -import { TokenEvents } from "../../../../types/token" - -/** - * @oas [post] /store/orders/batch/customer/token - * operationId: "PostOrdersCustomerOrderClaim" - * summary: "Claim Order" - * description: "Allow the logged-in customer to claim ownership of one or more orders. This generates a token that can be used later on to verify the claim using the Verify Order Claim API Route. - * This also emits the event `order-update-token.created`. So, if you have a notification provider installed that handles this event and sends the customer a notification, such as an email, - * the customer should receive instructions on how to finalize their claim ownership." - * externalDocs: - * description: "How to implement claim-order flow in a storefront" - * url: "https://docs.medusajs.com/modules/orders/storefront/implement-claim-order" - * x-authenticated: true - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostCustomersCustomerOrderClaimReq" - * x-codegen: - * method: requestCustomerOrders - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.orders.requestCustomerOrders({ - * order_ids, - * }) - * .then(() => { - * // successful - * }) - * .catch(() => { - * // an error occurred - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useRequestOrderAccess } from "medusa-react" - * - * const ClaimOrder = () => { - * const claimOrder = useRequestOrderAccess() - * - * const handleClaimOrder = ( - * orderIds: string[] - * ) => { - * claimOrder.mutate({ - * order_ids: orderIds - * }, { - * onSuccess: () => { - * // successful - * }, - * onError: () => { - * // an error occurred. - * } - * }) - * } - * - * // ... - * } - * - * export default ClaimOrder - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/batch/customer/token' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "order_ids": ["id"], - * }' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Orders - * responses: - * 200: - * description: OK - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { order_ids } = req.validatedBody - - const eventBusService: EventBusService = req.scope.resolve("eventBusService") - const orderService: OrderService = req.scope.resolve("orderService") - const customerService: CustomerService = req.scope.resolve("customerService") - const tokenService: TokenService = req.scope.resolve( - TokenService.RESOLUTION_KEY - ) - - const customerId: string = req.user?.customer_id - const customer = await customerService.retrieve(customerId) - - if (!customer.has_account) { - throw new MedusaError( - MedusaError.Types.UNAUTHORIZED, - "Customer does not have an account" - ) - } - - const orders = await orderService.list( - { id: order_ids }, - { select: ["id", "email"] } - ) - - const emailOrderMapping: { [email: string]: string[] } = orders.reduce( - (acc, order) => { - acc[order.email] = [...(acc[order.email] || []), order.id] - return acc - }, - {} - ) - - await promiseAll( - Object.entries(emailOrderMapping).map(async ([email, order_ids]) => { - const token = tokenService.signToken( - { - claimingCustomerId: customerId, - orders: order_ids, - }, - { expiresIn: "15m" } - ) - - await eventBusService.emit(TokenEvents.ORDER_UPDATE_TOKEN_CREATED, { - old_email: email, - new_customer_id: customer.id, - orders: order_ids, - token, - }) - }) - ) - - res.sendStatus(200) -} - -/** - * @schema StorePostCustomersCustomerOrderClaimReq - * type: object - * description: "The details of the orders to claim." - * required: - * - order_ids - * properties: - * order_ids: - * description: "The ID of the orders to claim" - * type: array - * items: - * type: string - */ -export class StorePostCustomersCustomerOrderClaimReq { - @IsNotEmpty({ each: true }) - @IsString({ each: true }) - order_ids: string[] -} diff --git a/packages/medusa/src/api/routes/store/payment-collections/authorize-batch-payment-sessions.ts b/packages/medusa/src/api/routes/store/payment-collections/authorize-batch-payment-sessions.ts deleted file mode 100644 index aabb592f89..0000000000 --- a/packages/medusa/src/api/routes/store/payment-collections/authorize-batch-payment-sessions.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { IsArray, IsString } from "class-validator" -import { PaymentCollectionService } from "../../../../services" - -/** - * @oas [post] /store/payment-collections/{id}/sessions/batch/authorize - * operationId: "PostPaymentCollectionsSessionsBatchAuthorize" - * summary: "Authorize Payment Sessions" - * description: "Authorize the Payment Sessions of a Payment Collection." - * x-authenticated: false - * parameters: - * - (path) id=* {string} The ID of the Payment Collections. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostPaymentCollectionsBatchSessionsAuthorizeReq" - * x-codegen: - * method: authorizePaymentSessionsBatch - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.paymentCollections.authorize(paymentId) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAuthorizePaymentSessionsBatch } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const authorizePaymentSessions = useAuthorizePaymentSessionsBatch( - * paymentCollectionId - * ) - * // ... - * - * const handleAuthorizePayments = (paymentSessionIds: string[]) => { - * authorizePaymentSessions.mutate({ - * session_ids: paymentSessionIds - * }, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/payment-collections/{id}/sessions/batch/authorize' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payment Collections - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePaymentCollectionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const data = - req.validatedBody as StorePostPaymentCollectionsBatchSessionsAuthorizeReq - - const paymentCollectionService: PaymentCollectionService = req.scope.resolve( - "paymentCollectionService" - ) - - const payment_collection = - await paymentCollectionService.authorizePaymentSessions( - id, - data.session_ids, - req.request_context - ) - - res.status(200).json({ payment_collection }) -} - -/** - * @schema StorePostPaymentCollectionsBatchSessionsAuthorizeReq - * type: object - * description: "The details of the payment sessions to authorize." - * required: - * - session_ids - * properties: - * session_ids: - * description: "List of Payment Session IDs to authorize." - * type: array - * items: - * type: string - */ -export class StorePostPaymentCollectionsBatchSessionsAuthorizeReq { - @IsArray() - @IsString({ each: true }) - session_ids: string[] -} diff --git a/packages/medusa/src/api/routes/store/payment-collections/authorize-payment-session.ts b/packages/medusa/src/api/routes/store/payment-collections/authorize-payment-session.ts deleted file mode 100644 index 4d73d51de6..0000000000 --- a/packages/medusa/src/api/routes/store/payment-collections/authorize-payment-session.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { PaymentSessionStatus } from "../../../../models" -import { PaymentCollectionService } from "../../../../services" - -/** - * @oas [post] /store/payment-collections/{id}/sessions/{session_id}/authorize - * operationId: "PostPaymentCollectionsSessionsSessionAuthorize" - * summary: "Authorize Payment Session" - * description: "Authorize a Payment Session of a Payment Collection." - * x-authenticated: false - * parameters: - * - (path) id=* {string} The ID of the Payment Collection. - * - (path) session_id=* {string} The ID of the Payment Session. - * x-codegen: - * method: authorizePaymentSession - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.paymentCollections.authorize(paymentId, sessionId) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useAuthorizePaymentSession } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const authorizePaymentSession = useAuthorizePaymentSession( - * paymentCollectionId - * ) - * // ... - * - * const handleAuthorizePayment = (paymentSessionId: string) => { - * authorizePaymentSession.mutate(paymentSessionId, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/payment-collections/{id}/sessions/{session_id}/authorize' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payment Collections - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePaymentCollectionsSessionRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, session_id } = req.params - - const paymentCollectionService: PaymentCollectionService = req.scope.resolve( - "paymentCollectionService" - ) - - const payment_collection = - await paymentCollectionService.authorizePaymentSessions( - id, - [session_id], - req.request_context - ) - - const session = payment_collection.payment_sessions.find( - ({ id }) => id === session_id - ) - - if (session?.status !== PaymentSessionStatus.AUTHORIZED) { - throw new MedusaError( - MedusaError.Types.PAYMENT_AUTHORIZATION_ERROR, - `Failed to authorize Payment Session id "${id}"` - ) - } - - res.status(200).json({ payment_session: session }) -} diff --git a/packages/medusa/src/api/routes/store/payment-collections/get-payment-collection.ts b/packages/medusa/src/api/routes/store/payment-collections/get-payment-collection.ts deleted file mode 100644 index 0c938b6d3f..0000000000 --- a/packages/medusa/src/api/routes/store/payment-collections/get-payment-collection.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { PaymentCollectionService } from "../../../../services" -import { FindParams } from "../../../../types/common" - -/** - * @oas [get] /store/payment-collections/{id} - * operationId: "GetPaymentCollectionsPaymentCollection" - * summary: "Get a PaymentCollection" - * description: "Retrieve a Payment Collection's details." - * x-authenticated: false - * parameters: - * - (path) id=* {string} The ID of the PaymentCollection. - * - (query) fields {string} Comma-separated fields that should be expanded in the returned payment collection. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned payment collection. - * x-codegen: - * method: retrieve - * queryParams: StoreGetPaymentCollectionsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.paymentCollections.retrieve(paymentCollectionId) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id) - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { usePaymentCollection } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const { - * payment_collection, - * isLoading - * } = usePaymentCollection( - * paymentCollectionId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {payment_collection && ( - * {payment_collection.status} - * )} - *
- * ) - * } - * - * export default PaymentCollection - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/payment-collections/{id}' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payment Collections - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePaymentCollectionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - const retrieveConfig = req.retrieveConfig - - const paymentCollectionService: PaymentCollectionService = req.scope.resolve( - "paymentCollectionService" - ) - - const paymentCollection = await paymentCollectionService.retrieve( - id, - retrieveConfig - ) - - res.status(200).json({ payment_collection: paymentCollection }) -} - -export class StoreGetPaymentCollectionsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/store/payment-collections/index.ts b/packages/medusa/src/api/routes/store/payment-collections/index.ts deleted file mode 100644 index c4f9137158..0000000000 --- a/packages/medusa/src/api/routes/store/payment-collections/index.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { Router } from "express" -import "reflect-metadata" -import middlewares, { - transformBody, - transformStoreQuery, -} from "../../../middlewares" - -import { PaymentCollection, PaymentSession } from "../../../../models" -import { StorePostPaymentCollectionsBatchSessionsAuthorizeReq } from "./authorize-batch-payment-sessions" -import { StoreGetPaymentCollectionsParams } from "./get-payment-collection" -import { StorePostPaymentCollectionsBatchSessionsReq } from "./manage-batch-payment-sessions" -import { StorePaymentCollectionSessionsReq } from "./manage-payment-session" - -const route = Router() - -export default (app, container) => { - app.use("/payment-collections", route) - - route.get( - "/:id", - transformStoreQuery(StoreGetPaymentCollectionsParams, { - defaultFields: defaultPaymentCollectionFields, - defaultRelations: defaultPaymentCollectionRelations, - isList: false, - }), - middlewares.wrap(require("./get-payment-collection").default) - ) - - route.post( - "/:id/sessions/batch", - transformBody(StorePostPaymentCollectionsBatchSessionsReq), - middlewares.wrap(require("./manage-batch-payment-sessions").default) - ) - - route.post( - "/:id/sessions/batch/authorize", - transformBody(StorePostPaymentCollectionsBatchSessionsAuthorizeReq), - middlewares.wrap(require("./authorize-batch-payment-sessions").default) - ) - - route.post( - "/:id/sessions", - transformBody(StorePaymentCollectionSessionsReq), - middlewares.wrap(require("./manage-payment-session").default) - ) - - route.post( - "/:id/sessions/:session_id", - middlewares.wrap(require("./refresh-payment-session").default) - ) - - route.post( - "/:id/sessions/:session_id/authorize", - middlewares.wrap(require("./authorize-payment-session").default) - ) - - return app -} - -export const defaultPaymentCollectionFields = [ - "id", - "type", - "status", - "description", - "amount", - "region", - "currency_code", - "currency", - "metadata", -] - -export const defaultPaymentCollectionRelations = ["region", "payment_sessions"] - -/** - * @schema StorePaymentCollectionsRes - * type: object - * description: "The payment collection's details." - * x-expanded-relations: - * field: payment_collection - * relations: - * - payment_sessions - * - region - * eager: - * - region.fulfillment_providers - * - region.payment_providers - * required: - * - payment_collection - * properties: - * payment_collection: - * description: "Payment collection's details." - * $ref: "#/components/schemas/PaymentCollection" - */ -export type StorePaymentCollectionsRes = { - payment_collection: PaymentCollection -} - -/** - * @schema StorePaymentCollectionsSessionRes - * type: object - * description: "The details of the payment session." - * required: - * - payment_session - * properties: - * payment_session: - * description: "Payment session's details." - * $ref: "#/components/schemas/PaymentSession" - */ -export type StorePaymentCollectionsSessionRes = { - payment_session: PaymentSession -} - -export * from "./authorize-batch-payment-sessions" -export * from "./get-payment-collection" -export * from "./manage-batch-payment-sessions" -export * from "./manage-payment-session" -export * from "./refresh-payment-session" diff --git a/packages/medusa/src/api/routes/store/payment-collections/manage-batch-payment-sessions.ts b/packages/medusa/src/api/routes/store/payment-collections/manage-batch-payment-sessions.ts deleted file mode 100644 index 909e5f0613..0000000000 --- a/packages/medusa/src/api/routes/store/payment-collections/manage-batch-payment-sessions.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { IsInt, IsNotEmpty, IsOptional, IsString } from "class-validator" -import { IsType } from "../../../../utils/validators/is-type" - -import { EntityManager } from "typeorm" -import { PaymentCollectionService } from "../../../../services" - -/** - * @oas [post] /store/payment-collections/{id}/sessions/batch - * operationId: "PostPaymentCollectionsPaymentCollectionSessionsBatch" - * summary: "Manage Payment Sessions" - * description: "Create, update, or delete a list of payment sessions of a Payment Collections. If a payment session is not provided in the `sessions` array, it's deleted." - * x-authenticated: false - * parameters: - * - (path) id=* {string} The ID of the Payment Collection. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostPaymentCollectionsBatchSessionsReq" - * x-codegen: - * method: managePaymentSessionsBatch - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * - * // Total amount = 10000 - * - * // Example 1: Adding two new sessions - * medusa.paymentCollections.managePaymentSessionsBatch(paymentId, { - * sessions: [ - * { - * provider_id: "stripe", - * amount: 5000, - * }, - * { - * provider_id: "manual", - * amount: 5000, - * }, - * ] - * }) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id); - * }) - * - * // Example 2: Updating one session and removing the other - * medusa.paymentCollections.managePaymentSessionsBatch(paymentId, { - * sessions: [ - * { - * provider_id: "stripe", - * amount: 10000, - * session_id: "ps_123456" - * }, - * ] - * }) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useManageMultiplePaymentSessions } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const managePaymentSessions = useManageMultiplePaymentSessions( - * paymentCollectionId - * ) - * - * const handleManagePaymentSessions = () => { - * // Total amount = 10000 - * - * // Example 1: Adding two new sessions - * managePaymentSessions.mutate({ - * sessions: [ - * { - * provider_id: "stripe", - * amount: 5000, - * }, - * { - * provider_id: "manual", - * amount: 5000, - * }, - * ] - * }, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.payment_sessions) - * } - * }) - * - * // Example 2: Updating one session and removing the other - * managePaymentSessions.mutate({ - * sessions: [ - * { - * provider_id: "stripe", - * amount: 10000, - * session_id: "ps_123456" - * }, - * ] - * }, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/payment-collections/{id}/sessions/batch' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "sessions": [ - * { - * "provider_id": "stripe", - * "amount": 5000 - * }, - * { - * "provider_id": "manual", - * "amount": 5000 - * } - * ] - * }' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payment Collections - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePaymentCollectionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const data = req.validatedBody as StorePostPaymentCollectionsBatchSessionsReq - const { id } = req.params - - const customerId = req.user?.customer_id - - const paymentCollectionService: PaymentCollectionService = req.scope.resolve( - "paymentCollectionService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - const paymentCollection = await manager.transaction( - async (transactionManager) => { - return await paymentCollectionService - .withTransaction(transactionManager) - .setPaymentSessionsBatch(id, data.sessions, customerId) - } - ) - - res.status(200).json({ payment_collection: paymentCollection }) -} - -export class StorePostPaymentCollectionsSessionsReq { - @IsString() - provider_id: string - - @IsInt() - @IsNotEmpty() - amount: number - - @IsString() - @IsOptional() - session_id?: string -} - -/** - * @schema StorePostPaymentCollectionsBatchSessionsReq - * type: object - * description: "The details of the payment sessions to manage." - * required: - * - sessions - * properties: - * sessions: - * description: "Payment sessions related to the Payment Collection. Existing sessions that are not added in this array will be deleted." - * type: array - * items: - * type: object - * required: - * - provider_id - * - amount - * properties: - * provider_id: - * type: string - * description: The ID of the Payment Provider. - * amount: - * type: integer - * description: "The payment amount" - * session_id: - * type: string - * description: "The ID of the Payment Session to be updated. If no ID is provided, a new payment session is created." - */ -export class StorePostPaymentCollectionsBatchSessionsReq { - @IsType([[StorePostPaymentCollectionsSessionsReq]]) - sessions: StorePostPaymentCollectionsSessionsReq[] -} diff --git a/packages/medusa/src/api/routes/store/payment-collections/manage-payment-session.ts b/packages/medusa/src/api/routes/store/payment-collections/manage-payment-session.ts deleted file mode 100644 index 4ffa24ebbe..0000000000 --- a/packages/medusa/src/api/routes/store/payment-collections/manage-payment-session.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { IsString } from "class-validator" - -import { EntityManager } from "typeorm" -import { PaymentCollectionService } from "../../../../services" - -/** - * @oas [post] /store/payment-collections/{id}/sessions - * operationId: "PostPaymentCollectionsSessions" - * summary: "Create a Payment Session" - * description: "Create a Payment Session for a payment provider in a Payment Collection." - * x-authenticated: false - * parameters: - * - (path) id=* {string} The ID of the Payment Collection. - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePaymentCollectionSessionsReq" - * x-codegen: - * method: managePaymentSession - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.paymentCollections.managePaymentSession(payment_id, { provider_id: "stripe" }) - * .then(({ payment_collection }) => { - * console.log(payment_collection.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useManagePaymentSession } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const managePaymentSession = useManagePaymentSession( - * paymentCollectionId - * ) - * - * const handleManagePaymentSession = ( - * providerId: string - * ) => { - * managePaymentSession.mutate({ - * provider_id: providerId - * }, { - * onSuccess: ({ payment_collection }) => { - * console.log(payment_collection.payment_sessions) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/payment-collections/{id}/sessions' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "provider_id": "stripe" - * }' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payment Collections - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePaymentCollectionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const data = req.validatedBody as StorePaymentCollectionSessionsReq - const { id } = req.params - - const customerId = req.user?.customer_id - - const paymentCollectionService: PaymentCollectionService = req.scope.resolve( - "paymentCollectionService" - ) - - const manager: EntityManager = req.scope.resolve("manager") - - const paymentCollection = await manager.transaction( - async (transactionManager) => { - return await paymentCollectionService - .withTransaction(transactionManager) - .setPaymentSession(id, data, customerId) - } - ) - - res.status(200).json({ payment_collection: paymentCollection }) -} - -/** - * @schema StorePaymentCollectionSessionsReq - * type: object - * description: "The details of the payment session to manage." - * required: - * - provider_id - * properties: - * provider_id: - * type: string - * description: The ID of the Payment Provider. - */ -export class StorePaymentCollectionSessionsReq { - @IsString() - provider_id: string -} diff --git a/packages/medusa/src/api/routes/store/payment-collections/refresh-payment-session.ts b/packages/medusa/src/api/routes/store/payment-collections/refresh-payment-session.ts deleted file mode 100644 index 0c34dac704..0000000000 --- a/packages/medusa/src/api/routes/store/payment-collections/refresh-payment-session.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { EntityManager } from "typeorm" -import { PaymentCollectionService } from "../../../../services" - -/** - * @oas [post] /store/payment-collections/{id}/sessions/{session_id} - * operationId: PostPaymentCollectionsPaymentCollectionPaymentSessionsSession - * summary: "Refresh a Payment Session" - * description: "Refresh a Payment Session's data to ensure that it is in sync with the Payment Collection." - * x-authenticated: false - * parameters: - * - (path) id=* {string} The id of the PaymentCollection. - * - (path) session_id=* {string} The id of the Payment Session to be refreshed. - * x-codegen: - * method: refreshPaymentSession - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.paymentCollections.refreshPaymentSession(paymentCollectionId, sessionId) - * .then(({ payment_session }) => { - * console.log(payment_session.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { usePaymentCollectionRefreshPaymentSession } from "medusa-react" - * - * type Props = { - * paymentCollectionId: string - * } - * - * const PaymentCollection = ({ - * paymentCollectionId - * }: Props) => { - * const refreshPaymentSession = usePaymentCollectionRefreshPaymentSession( - * paymentCollectionId - * ) - * // ... - * - * const handleRefreshPaymentSession = (paymentSessionId: string) => { - * refreshPaymentSession.mutate(paymentSessionId, { - * onSuccess: ({ payment_session }) => { - * console.log(payment_session.status) - * } - * }) - * } - * - * // ... - * } - * - * export default PaymentCollection - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/payment-collections/{id}/sessions/{session_id}' - * security: - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Payment Collections - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePaymentCollectionsSessionRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id, session_id } = req.params - - const paymentCollectionService: PaymentCollectionService = req.scope.resolve( - "paymentCollectionService" - ) - - const customerId = req.user?.customer_id - - const manager: EntityManager = req.scope.resolve("manager") - const paymentSession = await manager.transaction( - async (transactionManager) => { - return await paymentCollectionService - .withTransaction(transactionManager) - .refreshPaymentSession(id, session_id, customerId) - } - ) - - res.status(200).json({ payment_session: paymentSession }) -} diff --git a/packages/medusa/src/api/routes/store/product-categories/__tests__/get-product-category.ts b/packages/medusa/src/api/routes/store/product-categories/__tests__/get-product-category.ts deleted file mode 100644 index 6994f90d02..0000000000 --- a/packages/medusa/src/api/routes/store/product-categories/__tests__/get-product-category.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { - defaultStoreProductCategoryRelations, - defaultStoreCategoryScope, - defaultStoreProductCategoryFields -} from ".." -import { - ProductCategoryServiceMock, - validProdCategoryId, - invalidProdCategoryId, -} from "../../../../../services/__mocks__/product-category" - -describe("GET /store/product-categories/:id", () => { - describe("get product category by id successfully", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/store/product-categories/${IdMap.getId(validProdCategoryId)}`) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls retrieve from product category service", () => { - expect(ProductCategoryServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(ProductCategoryServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId(validProdCategoryId), - { - relations: defaultStoreProductCategoryRelations, - select: defaultStoreProductCategoryFields, - }, - defaultStoreCategoryScope - ) - }) - - it("returns product category", () => { - expect(subject.body.product_category.id).toEqual(IdMap.getId(validProdCategoryId)) - }) - }) - - describe("returns 404 error when ID is invalid", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/store/product-categories/${IdMap.getId(invalidProdCategoryId)}`) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls retrieve from product category service", () => { - expect(ProductCategoryServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(ProductCategoryServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId(invalidProdCategoryId), - { - relations: defaultStoreProductCategoryRelations, - select: defaultStoreProductCategoryFields, - }, - defaultStoreCategoryScope - ) - }) - - it("throws not found error", () => { - expect(subject.body.type).toEqual("not_found") - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/product-categories/get-product-category.ts b/packages/medusa/src/api/routes/store/product-categories/get-product-category.ts deleted file mode 100644 index f3c6801ee8..0000000000 --- a/packages/medusa/src/api/routes/store/product-categories/get-product-category.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { Request, Response } from "express" - -import ProductCategoryService from "../../../../services/product-category" -import { FindParams } from "../../../../types/common" -import { transformTreeNodesWithConfig } from "../../../../utils/transformers/tree" -import { defaultStoreCategoryScope } from "." - -/** - * @oas [get] /store/product-categories/{id} - * operationId: "GetProductCategoriesCategory" - * summary: "Get a Product Category" - * description: "Retrieve a Product Category's details." - * x-featureFlag: "product_categories" - * parameters: - * - (path) id=* {string} The ID of the Product Category - * - (query) fields {string} Comma-separated fields that should be expanded in the returned product category. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned product category. - * x-codegen: - * method: retrieve - * queryParams: StoreGetProductCategoriesCategoryParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.productCategories.retrieve(productCategoryId) - * .then(({ product_category }) => { - * console.log(product_category.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useProductCategory } from "medusa-react" - * - * type Props = { - * categoryId: string - * } - * - * const Category = ({ categoryId }: Props) => { - * const { product_category, isLoading } = useProductCategory( - * categoryId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {product_category && {product_category.name}} - *
- * ) - * } - * - * export default Category - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/product-categories/{id}' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Categories - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreGetProductCategoriesCategoryRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const { id } = req.params - const { retrieveConfig } = req - - const productCategoryService: ProductCategoryService = req.scope.resolve( - "productCategoryService" - ) - - const productCategory = await productCategoryService.retrieve( - id, - retrieveConfig, - defaultStoreCategoryScope - ) - - res.status(200).json({ - // TODO: When we implement custom queries for tree paths in medusa, remove the transformer - // Adding this here since typeorm tree repo doesn't allow configs to be passed - // onto its children nodes. As an alternative, we are transforming the data post query. - product_category: transformTreeNodesWithConfig( - productCategory, - retrieveConfig, - defaultStoreCategoryScope - ), - }) -} - -export class StoreGetProductCategoriesCategoryParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/store/product-categories/index.ts b/packages/medusa/src/api/routes/store/product-categories/index.ts deleted file mode 100644 index 5ae0920e34..0000000000 --- a/packages/medusa/src/api/routes/store/product-categories/index.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { Router } from "express" -import { ProductCategory } from "../../../../models" -import { PaginatedResponse } from "../../../../types/common" -import middlewares, { transformStoreQuery } from "../../../middlewares" - -import listProductCategories, { - StoreGetProductCategoriesParams, -} from "./list-product-categories" - -import getProductCategory, { - StoreGetProductCategoriesCategoryParams, -} from "./get-product-category" - -const route = Router() - -export default (app) => { - app.use("/product-categories", route) - - route.get( - "/", - transformStoreQuery(StoreGetProductCategoriesParams, { - defaultFields: defaultStoreProductCategoryFields, - allowedFields: allowedStoreProductCategoryFields, - defaultRelations: defaultStoreProductCategoryRelations, - isList: true, - }), - middlewares.wrap(listProductCategories) - ) - - route.get( - "/:id", - transformStoreQuery(StoreGetProductCategoriesCategoryParams, { - defaultFields: defaultStoreProductCategoryFields, - allowedFields: allowedStoreProductCategoryFields, - defaultRelations: defaultStoreProductCategoryRelations, - isList: false, - }), - middlewares.wrap(getProductCategory) - ) - - return app -} - -export const defaultStoreProductCategoryRelations = [ - "parent_category", - "category_children", -] - -export const defaultStoreCategoryScope = { - is_internal: false, - is_active: true, -} - -export const defaultStoreProductCategoryFields = [ - "id", - "name", - "description", - "handle", - "parent_category_id", - "created_at", - "updated_at", - "rank", - "metadata", -] - -export const allowedStoreProductCategoryFields = [ - "id", - "name", - "description", - "handle", - "parent_category_id", - "created_at", - "updated_at", - "rank", - "metadata", -] - -/** - * @schema StoreGetProductCategoriesCategoryRes - * type: object - * description: "The product category's details." - * x-expanded-relations: - * field: product_category - * relations: - * - category_children - * - parent_category - * required: - * - product_category - * properties: - * product_category: - * description: "Product category details." - * $ref: "#/components/schemas/ProductCategory" - */ -export type StoreGetProductCategoriesCategoryRes = { - product_category: ProductCategory -} - -/** - * @schema StoreGetProductCategoriesRes - * type: object - * description: "The list of product categories with pagination fields." - * x-expanded-relations: - * field: product_categories - * relations: - * - category_children - * - parent_category - * required: - * - product_categories - * - count - * - offset - * - limit - * properties: - * product_categories: - * type: array - * description: "An array of product categories details." - * items: - * $ref: "#/components/schemas/ProductCategory" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of product categories skipped when retrieving the product categories. - * limit: - * type: integer - * description: The number of items per page - */ -export type StoreGetProductCategoriesRes = PaginatedResponse & { - product_categories: ProductCategory[] -} - -export * from "./get-product-category" -export * from "./list-product-categories" diff --git a/packages/medusa/src/api/routes/store/product-categories/list-product-categories.ts b/packages/medusa/src/api/routes/store/product-categories/list-product-categories.ts deleted file mode 100644 index fcee7dcdc8..0000000000 --- a/packages/medusa/src/api/routes/store/product-categories/list-product-categories.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { IsOptional, IsString, IsBoolean } from "class-validator" -import { Request, Response } from "express" -import { Transform } from "class-transformer" - -import { ProductCategoryService } from "../../../../services" -import { extendedFindParamsMixin } from "../../../../types/common" -import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean" -import { defaultStoreCategoryScope } from "." - -/** - * @oas [get] /store/product-categories - * operationId: "GetProductCategories" - * summary: "List Product Categories" - * description: "Retrieve a list of product categories. The product categories can be filtered by fields such as `handle` or `q`. The product categories can also be paginated. - * This API Route can also be used to retrieve a product category by its handle." - * x-featureFlag: "product_categories" - * externalDocs: - * description: "How to retrieve a product category by its handle" - * url: "https://docs.medusajs.com/modules/products/storefront/use-categories#get-a-category-by-its-handle" - * parameters: - * - (query) q {string} term used to search product category's names and handles. - * - (query) handle {string} Filter by handle. - * - (query) parent_category_id {string} Filter by the ID of a parent category. Only children of the provided parent category are retrieved. - * - (query) include_descendants_tree {boolean} Whether all nested categories inside a category should be retrieved. - * - (query) offset=0 {integer} The number of product categories to skip when retrieving the product categories. - * - (query) limit=100 {integer} Limit the number of product categories returned. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned product categories. - * - (query) fields {string} Comma-separated fields that should be included in the returned product categories. - * x-codegen: - * method: list - * queryParams: StoreGetProductCategoriesParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.productCategories.list() - * .then(({ product_categories, limit, offset, count }) => { - * console.log(product_categories.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useProductCategories } from "medusa-react" - * - * function Categories() { - * const { - * product_categories, - * isLoading, - * } = useProductCategories() - * - * return ( - *
- * {isLoading && Loading...} - * {product_categories && !product_categories.length && ( - * No Categories - * )} - * {product_categories && product_categories.length > 0 && ( - *
    - * {product_categories.map( - * (category) => ( - *
  • {category.name}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Categories - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/product-categories' \ - * -H 'x-medusa-access-token: {api_token}' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Categories - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreGetProductCategoriesRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const productCategoryService: ProductCategoryService = req.scope.resolve( - "productCategoryService" - ) - - const selectors = Object.assign( - { ...defaultStoreCategoryScope }, - req.filterableFields - ) - - const [data, count] = await productCategoryService.listAndCount( - selectors, - req.listConfig, - defaultStoreCategoryScope - ) - - const { limit, offset } = req.validatedQuery - - res.json({ - count, - offset, - limit, - product_categories: data, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved product categories. - * - * @property {number} limit - Limit the number of product categories returned in the list. Default is `100`. - */ -export class StoreGetProductCategoriesParams extends extendedFindParamsMixin({ - limit: 100, - offset: 0, -}) { - /** - * Search term to search product categories' names and handles. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Handle to filter product categories by. - */ - @IsString() - @IsOptional() - handle?: string - - /** - * Filter product categories by the ID of their associated parent category. - */ - @IsString() - @IsOptional() - @Transform(({ value }) => { - return value === "null" ? null : value - }) - parent_category_id?: string | null - - /** - * Whether to include child categories in the retrieved categories. - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value)) - include_descendants_tree?: boolean -} diff --git a/packages/medusa/src/api/routes/store/product-tags/index.ts b/packages/medusa/src/api/routes/store/product-tags/index.ts deleted file mode 100644 index 384a771293..0000000000 --- a/packages/medusa/src/api/routes/store/product-tags/index.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Router } from "express" -import { ProductTag } from "../../../../models" -import { PaginatedResponse } from "../../../../types/common" -import middlewares, { transformStoreQuery } from "../../../middlewares" -import { StoreGetProductTagsParams } from "./list-product-tags" - -const route = Router() - -export default (app: Router) => { - app.use("/product-tags", route) - - route.get( - "/", - transformStoreQuery(StoreGetProductTagsParams, { - defaultFields: defaultStoreProductTagFields, - defaultRelations: defaultStoreProductTagRelations, - allowedFields: allowedStoreProductTagFields, - isList: true, - }), - middlewares.wrap(require("./list-product-tags").default) - ) - - return app -} - -export const defaultStoreProductTagFields = [ - "id", - "value", - "created_at", - "updated_at", -] - -export const allowedStoreProductTagFields = [...defaultStoreProductTagFields] - -export const defaultStoreProductTagRelations = [] - -/** - * @schema StoreProductTagsListRes - * type: object - * description: "The list of product tags with pagination fields." - * required: - * - product_tags - * - count - * - offset - * - limit - * properties: - * product_tags: - * type: array - * description: "An array of product tags details." - * items: - * $ref: "#/components/schemas/ProductTag" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of product tags skipped when retrieving the product tags. - * limit: - * type: integer - * description: The number of items per page - */ -export type StoreProductTagsListRes = PaginatedResponse & { - product_tags: ProductTag[] -} - -export * from "./list-product-tags" diff --git a/packages/medusa/src/api/routes/store/product-tags/list-product-tags.ts b/packages/medusa/src/api/routes/store/product-tags/list-product-tags.ts deleted file mode 100644 index 243cca5e52..0000000000 --- a/packages/medusa/src/api/routes/store/product-tags/list-product-tags.ts +++ /dev/null @@ -1,228 +0,0 @@ -import { IsOptional, IsString } from "class-validator" -import { - DateComparisonOperator, - FindPaginationParams, - StringComparisonOperator, -} from "../../../../types/common" - -import { Request, Response } from "express" -import ProductTagService from "../../../../services/product-tag" -import { IsType } from "../../../../utils/validators/is-type" - -/** - * @oas [get] /store/product-tags - * operationId: "GetProductTags" - * summary: "List Product Tags" - * description: "Retrieve a list of product tags. The product tags can be filtered by fields such as `id` or `q`. The product tags can also be sorted or paginated." - * x-authenticated: true - * x-codegen: - * method: list - * queryParams: StoreGetProductTagsParams - * parameters: - * - (query) limit=20 {integer} Limit the number of product tags returned. - * - (query) offset=0 {integer} The number of product tags to skip when retrieving the product tags. - * - (query) order {string} A product-tag field to sort-order the retrieved product tags by. - * - (query) discount_condition_id {string} Filter by the ID of a discount condition. When provided, only tags that the discount condition applies for will be retrieved. - * - in: query - * name: value - * style: form - * explode: false - * description: Filter by tag values. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by IDs. - * schema: - * type: array - * items: - * type: string - * - (query) q {string} term to search product tag's value. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.productTags.list() - * .then(({ product_tags }) => { - * console.log(product_tags.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useProductTags } from "medusa-react" - * - * function Tags() { - * const { - * product_tags, - * isLoading, - * } = useProductTags() - * - * return ( - *
- * {isLoading && Loading...} - * {product_tags && !product_tags.length && ( - * No Product Tags - * )} - * {product_tags && product_tags.length > 0 && ( - *
    - * {product_tags.map( - * (tag) => ( - *
  • {tag.value}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Tags - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/product-tags' - * tags: - * - Product Tags - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreProductTagsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req: Request, res: Response) => { - const tagService: ProductTagService = req.scope.resolve("productTagService") - - const { listConfig, filterableFields } = req - const { skip, take } = req.listConfig - - const [tags, count] = await tagService.listAndCount( - filterableFields, - listConfig - ) - - res.status(200).json({ - product_tags: tags, - count, - offset: skip, - limit: take, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved product tags. - */ -export class StoreGetProductTagsParams extends FindPaginationParams { - /** - * IDs to filter product tags by. - */ - @IsType([String, [String], StringComparisonOperator]) - @IsOptional() - id?: string | string[] | StringComparisonOperator - - /** - * Search term to search product tags' values. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Values to filter product tags by. - */ - @IsType([String, [String], StringComparisonOperator]) - @IsOptional() - value?: string | string[] | StringComparisonOperator - - /** - * Date filters to apply to the product tags' `created_at` date. - */ - @IsType([DateComparisonOperator]) - @IsOptional() - created_at?: DateComparisonOperator - - /** - * Date filters to apply to the product tags' `updated_at` date. - */ - @IsType([DateComparisonOperator]) - @IsOptional() - updated_at?: DateComparisonOperator - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string - - /** - * Filter product tags by the ID of their associated discount condition. - */ - @IsString() - @IsOptional() - discount_condition_id?: string -} diff --git a/packages/medusa/src/api/routes/store/product-types/index.ts b/packages/medusa/src/api/routes/store/product-types/index.ts deleted file mode 100644 index 5083283fc8..0000000000 --- a/packages/medusa/src/api/routes/store/product-types/index.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { Router } from "express" -import { ProductType } from "../../../.." -import { PaginatedResponse } from "../../../../types/common" -import middlewares, { transformStoreQuery } from "../../../middlewares" -import "reflect-metadata" -import { StoreGetProductTypesParams } from "./list-product-types" - -const route = Router() - -export default (app) => { - app.use("/product-types", route) - - route.get( - "/", - transformStoreQuery(StoreGetProductTypesParams, { - defaultFields: defaultStoreProductTypeFields, - defaultRelations: defaultStoreProductTypeRelations, - allowedFields: allowedStoreProductTypeFields, - isList: true, - }), - middlewares.wrap(require("./list-product-types").default) - ) - - return app -} - -export const allowedStoreProductTypeFields = [ - "id", - "value", - "created_at", - "updated_at", -] - -export const defaultStoreProductTypeFields = [ - "id", - "value", - "created_at", - "updated_at", -] -export const defaultStoreProductTypeRelations = [] - -/** - * @schema StoreProductTypesListRes - * type: object - * required: - * - product_types - * - count - * - offset - * - limit - * properties: - * product_types: - * type: array - * description: "An array of product types details." - * items: - * $ref: "#/components/schemas/ProductType" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of product types skipped when retrieving the product types. - * limit: - * type: integer - * description: The number of items per page - */ -export type StoreProductTypesListRes = PaginatedResponse & { - product_types: ProductType[] -} - -export * from "./list-product-types" diff --git a/packages/medusa/src/api/routes/store/product-types/list-product-types.ts b/packages/medusa/src/api/routes/store/product-types/list-product-types.ts deleted file mode 100644 index 8b3ae69614..0000000000 --- a/packages/medusa/src/api/routes/store/product-types/list-product-types.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { - DateComparisonOperator, - FindPaginationParams, - StringComparisonOperator, -} from "../../../../types/common" -import { IsOptional, IsString } from "class-validator" - -import { IsType } from "../../../../utils/validators/is-type" -import ProductTypeService from "../../../../services/product-type" - -/** - * @oas [get] /store/product-types - * operationId: "GetProductTypes" - * summary: "List Product Types" - * description: "Retrieve a list of product types. The product types can be filtered by fields such as `value` or `q`. The product types can also be sorted or paginated." - * x-authenticated: true - * parameters: - * - (query) limit=20 {integer} Limit the number of product types returned. - * - (query) offset=0 {integer} The number of product types to skip when retrieving the product types. - * - (query) order {string} A product-type field to sort-order the retrieved product types by. - * - (query) discount_condition_id {string} Filter by the ID of a discount condition. When provided, only types that the discount condition applies for will be retrieved. - * - in: query - * name: value - * style: form - * explode: false - * description: Filter by type values. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by IDs. - * schema: - * type: array - * items: - * type: string - * - (query) q {string} term to search product type's value. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: list - * queryParams: StoreGetProductTypesParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.productTypes.list() - * .then(({ product_types }) => { - * console.log(product_types.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useProductTypes } from "medusa-react" - * - * function Types() { - * const { - * product_types, - * isLoading, - * } = useProductTypes() - * - * return ( - *
- * {isLoading && Loading...} - * {product_types && !product_types.length && ( - * No Product Types - * )} - * {product_types && product_types.length > 0 && ( - *
    - * {product_types.map( - * (type) => ( - *
  • {type.value}
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default Types - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/product-types' - * security: - * - api_token: [] - * - cookie_auth: [] - * - jwt_token: [] - * tags: - * - Product Types - * responses: - * "200": - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreProductTypesListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "401": - * $ref: "#/components/responses/unauthorized" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const typeService: ProductTypeService = - req.scope.resolve("productTypeService") - - const { listConfig, filterableFields } = req - const { skip, take } = req.listConfig - - const [types, count] = await typeService.listAndCount( - filterableFields, - listConfig - ) - - res.status(200).json({ - product_types: types, - count, - offset: skip, - limit: take, - }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved product types. - */ -// eslint-disable-next-line max-len -export class StoreGetProductTypesParams extends FindPaginationParams { - /** - * IDs to filter product types by. - */ - @IsType([String, [String], StringComparisonOperator]) - @IsOptional() - id?: string | string[] | StringComparisonOperator - - /** - * Search term to search product types' values. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Values to filter product types by. - */ - @IsType([String, [String], StringComparisonOperator]) - @IsOptional() - value?: string | string[] | StringComparisonOperator - - /** - * Date filters to apply on the product types' `created_at` date. - */ - @IsType([DateComparisonOperator]) - @IsOptional() - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the product types' `updated_at` date. - */ - @IsType([DateComparisonOperator]) - @IsOptional() - updated_at?: DateComparisonOperator - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string - - /** - * Filter product types by the ID of their associated discount condition. - */ - @IsString() - @IsOptional() - discount_condition_id?: string -} diff --git a/packages/medusa/src/api/routes/store/products/__tests__/get-product.js b/packages/medusa/src/api/routes/store/products/__tests__/get-product.js deleted file mode 100644 index 408a56d5d0..0000000000 --- a/packages/medusa/src/api/routes/store/products/__tests__/get-product.js +++ /dev/null @@ -1,71 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { defaultStoreProductsFields, defaultStoreProductsRelations } from ".." -import { request } from "../../../../../helpers/test-request" -import { ProductServiceMock } from "../../../../../services/__mocks__/product" - -describe("Get product by id", () => { - describe("get product by id successfull", () => { - let subject - beforeAll(async () => { - subject = await request( - "GET", - `/store/products/${IdMap.getId("product1")}` - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls get product from productSerice", () => { - expect(ProductServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(ProductServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("product1"), - { - select: defaultStoreProductsFields, - relations: defaultStoreProductsRelations, - } - ) - }) - - it("returns product decorated", () => { - expect(subject.body.product.id).toEqual(IdMap.getId("product1")) - }) - }) - - describe("Query products with relations", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/store/products/${IdMap.getId("variantsWithPrices")}` - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls retrieve() once", () => { - expect(ProductServiceMock.retrieve).toHaveBeenCalledTimes(1) - }) - - it("endpoint called with defaultRelations", () => { - expect(ProductServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("variantsWithPrices"), - { - select: defaultStoreProductsFields, - relations: defaultStoreProductsRelations, - } - ) - }) - - it("returns product with variant prices", () => { - expect( - subject.body.product.variants.some((variant) => variant.prices) - ).toEqual(true) - expect(subject.body.product.variants[0].prices[0].amount).toEqual(100) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/products/__tests__/list-products.js b/packages/medusa/src/api/routes/store/products/__tests__/list-products.js deleted file mode 100644 index fea1591151..0000000000 --- a/packages/medusa/src/api/routes/store/products/__tests__/list-products.js +++ /dev/null @@ -1,78 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { defaultStoreProductsFields, defaultStoreProductsRelations } from ".." -import { request } from "../../../../../helpers/test-request" -import { ProductServiceMock } from "../../../../../services/__mocks__/product" - -describe("GET /store/products", () => { - describe("list all products", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", "/store/products") - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls get product from productSerice", () => { - expect(ProductServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(ProductServiceMock.listAndCount).toHaveBeenCalledWith( - { - status: ["published"], - categories: { - is_active: true, - is_internal: false, - } - }, - { - relations: defaultStoreProductsRelations, - select: defaultStoreProductsFields, - skip: 0, - take: 100, - order: { - created_at: "DESC", - }, - } - ) - }) - - it("returns products", () => { - expect(subject.body.products[0].id).toEqual(IdMap.getId("product1")) - expect(subject.body.products[1].id).toEqual(IdMap.getId("product2")) - }) - }) - - describe("list all gift cards", () => { - beforeAll(async () => { - await request("GET", "/store/products?is_giftcard=true") - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls list from productSerice", () => { - expect(ProductServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect(ProductServiceMock.listAndCount).toHaveBeenCalledWith( - { - is_giftcard: true, - status: ["published"], - categories: { - is_active: true, - is_internal: false, - } - }, - { - relations: defaultStoreProductsRelations, - select: defaultStoreProductsFields, - skip: 0, - take: 100, - order: { - created_at: "DESC", - }, - } - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/products/__tests__/search.js b/packages/medusa/src/api/routes/store/products/__tests__/search.js deleted file mode 100644 index ff6dc18ed3..0000000000 --- a/packages/medusa/src/api/routes/store/products/__tests__/search.js +++ /dev/null @@ -1,42 +0,0 @@ -import { request } from "../../../../../helpers/test-request" -import { SearchServiceMock } from "../../../../../services/__mocks__/search" - -describe("GET /store/products/search", () => { - describe("searches for products", () => { - afterAll(() => { - jest.clearAllMocks() - }) - - it("validates the request", async () => { - const response = await request("POST", "/store/products/search", { - payload: { - q: "test", - limit: 10, - offset: 0, - filter: { type: "shirts" }, - wildcard: "whuhuu", - }, - }) - expect(SearchServiceMock.search).toHaveBeenCalledTimes(1) - expect(response.status).toEqual(200) - }) - - it("fails to validates the request", async () => { - const response = await request("POST", "/store/products/search", { - payload: { - q: 423, - limit: "10 pieces", - offset: "from the start", - filter: { type: "shirts" }, - wildcard: "whuhuu", - }, - }) - - expect(response.body.type).toEqual("invalid_data") - expect(response.body.message).toEqual( - "q must be a string, offset must be a number conforming to the specified constraints, limit must be a number conforming to the specified constraints" - ) - expect(response.status).toEqual(400) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/products/get-product.ts b/packages/medusa/src/api/routes/store/products/get-product.ts deleted file mode 100644 index 3f384352dd..0000000000 --- a/packages/medusa/src/api/routes/store/products/get-product.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { IsOptional, IsString } from "class-validator" -import { - CartService, - PricingService, - ProductService, - ProductVariantInventoryService, - RegionService, -} from "../../../../services" - -import { MedusaError, MedusaV2Flag, promiseAll } from "@medusajs/utils" -import { PriceSelectionParams } from "../../../../types/price-selection" -import { cleanResponseData } from "../../../../utils" -import { defaultStoreProductRemoteQueryObject } from "./index" - -/** - * @oas [get] /store/products/{id} - * operationId: GetProductsProduct - * summary: Get a Product - * description: | - * Retrieve a Product's details. For accurate and correct pricing of the product based on the customer's context, it's highly recommended to pass fields such as - * `region_id`, `currency_code`, and `cart_id` when available. - * - * Passing `sales_channel_id` ensures retrieving only products available in the current sales channel. - * You can alternatively use a publishable API key in the request header instead of passing a `sales_channel_id`. - * externalDocs: - * description: "How to pass product pricing parameters" - * url: "https://docs.medusajs.com/modules/products/storefront/show-products#product-pricing-parameters" - * parameters: - * - (path) id=* {string} The ID of the Product. - * - (query) sales_channel_id {string} The ID of the sales channel the customer is viewing the product from. - * - (query) cart_id {string} The ID of the cart. This is useful for accurate pricing based on the cart's context. - * - (query) region_id {string} The ID of the region. This is useful for accurate pricing based on the selected region. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned product. - * - (query) fields {string} Comma-separated fields that should be included in the returned product. - * - in: query - * name: currency_code - * style: form - * explode: false - * description: A 3 character ISO currency code. This is useful for accurate pricing based on the selected currency. - * schema: - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * x-codegen: - * method: retrieve - * queryParams: StoreGetProductsProductParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.products.retrieve(productId) - * .then(({ product }) => { - * console.log(product.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useProduct } from "medusa-react" - * - * type Props = { - * productId: string - * } - * - * const Product = ({ productId }: Props) => { - * const { product, isLoading } = useProduct(productId) - * - * return ( - *
- * {isLoading && Loading...} - * {product && {product.title}} - *
- * ) - * } - * - * export default Product - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/products/{id}' - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreProductsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = req.validatedQuery as StoreGetProductsProductParams - - const customer_id = req.user?.customer_id - - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - const productService: ProductService = req.scope.resolve("productService") - const pricingService: PricingService = req.scope.resolve("pricingService") - const cartService: CartService = req.scope.resolve("cartService") - const regionService: RegionService = req.scope.resolve("regionService") - const featureFlagRouter = req.scope.resolve("featureFlagRouter") - - let rawProduct - if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) { - rawProduct = await getProductWithIsolatedProductModule(req, id) - } else { - rawProduct = await productService.retrieve(id, req.retrieveConfig) - } - - let sales_channel_id = validated.sales_channel_id - if (req.publishableApiKeyScopes?.sales_channel_ids.length === 1) { - sales_channel_id = req.publishableApiKeyScopes.sales_channel_ids[0] - } - - let regionId = validated.region_id - let currencyCode = validated.currency_code - if (validated.cart_id) { - const cart = await cartService.retrieve(validated.cart_id, { - select: ["id", "region_id"], - }) - const region = await regionService.retrieve(cart.region_id, { - select: ["id", "currency_code"], - }) - regionId = region.id - currencyCode = region.currency_code - } - - const decoratedProduct = rawProduct - - // We only set prices if variants.prices are requested - const shouldSetPricing = ["variants", "variants.prices"].every((relation) => - req.retrieveConfig.relations?.includes(relation) - ) - - // We only set availability if variants are requested - const shouldSetAvailability = - req.retrieveConfig.relations?.includes("variants") - - const decoratePromises: Promise[] = [] - - if (shouldSetPricing) { - decoratePromises.push( - pricingService.setProductPrices([decoratedProduct], { - cart_id: validated.cart_id, - customer_id: customer_id, - region_id: regionId, - currency_code: currencyCode, - include_discount_prices: true, - }) - ) - } - - if (shouldSetAvailability) { - decoratePromises.push( - productVariantInventoryService.setProductAvailability( - [decoratedProduct], - sales_channel_id - ) - ) - } - - // We can run them concurrently as the new properties are assigned to the references - // of the appropriate entity - await promiseAll(decoratePromises) - - res.json({ - product: cleanResponseData(decoratedProduct, req.allowedProperties || []), - }) -} - -async function getProductWithIsolatedProductModule(req, id: string) { - const remoteQuery = req.scope.resolve("remoteQuery") - - const variables = { id } - - const query = { - product: { - __args: variables, - ...defaultStoreProductRemoteQueryObject, - }, - } - - const [product] = await remoteQuery(query) - - if (!product) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Product with id: ${id} not found` - ) - } - - product.profile_id = product.profile?.id - - return product -} - -export class StoreGetProductsProductParams extends PriceSelectionParams { - @IsString() - @IsOptional() - sales_channel_id?: string -} diff --git a/packages/medusa/src/api/routes/store/products/index.ts b/packages/medusa/src/api/routes/store/products/index.ts deleted file mode 100644 index eded227c34..0000000000 --- a/packages/medusa/src/api/routes/store/products/index.ts +++ /dev/null @@ -1,304 +0,0 @@ -import "reflect-metadata" - -import middlewares, { transformStoreQuery } from "../../../middlewares" - -import { FlagRouter } from "@medusajs/utils" -import { Router } from "express" -import { Product } from "../../../.." -import { PaginatedResponse } from "../../../../types/common" -import { PricedProduct } from "../../../../types/pricing" -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 { withDefaultSalesChannel } from "../../../middlewares/with-default-sales-channel" -import { StoreGetProductsProductParams } from "./get-product" -import { StoreGetProductsParams } from "./list-products" - -const route = Router() - -export default (app, featureFlagRouter: FlagRouter) => { - if (featureFlagRouter.isFeatureEnabled("product_categories")) { - allowedStoreProductsRelations.push("categories") - } - - app.use("/products", extendRequestParams, validateSalesChannelParam, route) - - route.use("/:id", validateProductSalesChannelAssociation) - - route.get( - "/", - withDefaultSalesChannel({ attachChannelAsArray: true }), - transformStoreQuery(StoreGetProductsParams, { - defaultRelations: defaultStoreProductsRelations, - defaultFields: defaultStoreProductsFields, - allowedFields: allowedStoreProductsFields, - allowedRelations: allowedStoreProductsRelations, - isList: true, - }), - middlewares.wrap(require("./list-products").default) - ) - - route.get( - "/:id", - withDefaultSalesChannel(), - transformStoreQuery(StoreGetProductsProductParams, { - defaultRelations: defaultStoreProductsRelations, - defaultFields: defaultStoreProductsFields, - allowedFields: allowedStoreProductsFields, - allowedRelations: allowedStoreProductsRelations, - }), - middlewares.wrap(require("./get-product").default) - ) - - route.post("/search", middlewares.wrap(require("./search").default)) - - return app -} - -export const defaultStoreProductsRelations = [ - "variants", - "variants.prices", - "variants.options", - "options", - "options.values", - "images", - "tags", - "collection", - "type", - "profiles", -] - -export const defaultStoreProductsFields: (keyof Product)[] = [ - "id", - "title", - "subtitle", - "status", - "external_id", - "description", - "handle", - "is_giftcard", - "discountable", - "thumbnail", - "collection_id", - "type_id", - "weight", - "length", - "height", - "width", - "hs_code", - "origin_country", - "mid_code", - "material", - "created_at", - "updated_at", - "deleted_at", - "metadata", -] - -export const allowedStoreProductsFields = [ - ...defaultStoreProductsFields, - // profile_id is not a column in the products table, so it should be ignored as it - // will be rejected by typeorm as invalid, though, it is an entity property - // that we want to return, so it part of the allowedStoreProductsFields - "profile_id", - "variants.title", - "variants.prices.amount", -] - -export const allowedStoreProductsRelations = [ - ...defaultStoreProductsRelations, - "variants.inventory_items", - "sales_channels", -] - -/** - * This is temporary. - */ -export const defaultStoreProductRemoteQueryObject = { - fields: defaultStoreProductsFields, - images: { - fields: ["id", "created_at", "updated_at", "deleted_at", "url", "metadata"], - }, - tags: { - fields: ["id", "created_at", "updated_at", "deleted_at", "value"], - }, - - type: { - fields: ["id", "created_at", "updated_at", "deleted_at", "value"], - }, - - collection: { - fields: ["title", "handle", "id", "created_at", "updated_at", "deleted_at"], - }, - - options: { - fields: [ - "id", - "created_at", - "updated_at", - "deleted_at", - "title", - "product_id", - "metadata", - ], - values: { - fields: [ - "id", - "created_at", - "updated_at", - "deleted_at", - "value", - "option_id", - "variant_id", - "metadata", - ], - }, - }, - - variants: { - fields: [ - "id", - "created_at", - "updated_at", - "deleted_at", - "title", - "product_id", - "sku", - "barcode", - "ean", - "upc", - "variant_rank", - "inventory_quantity", - "allow_backorder", - "manage_inventory", - "hs_code", - "origin_country", - "mid_code", - "material", - "weight", - "length", - "height", - "width", - "metadata", - ], - - options: { - fields: [ - "id", - "created_at", - "updated_at", - "deleted_at", - "value", - "option_id", - "variant_id", - "metadata", - ], - }, - }, - profile: { - fields: ["id", "created_at", "updated_at", "deleted_at", "name", "type"], - }, - sales_channels: { - fields: [ - "id", - "name", - "description", - "is_disabled", - "created_at", - "updated_at", - "deleted_at", - "metadata", - ], - }, -} - -export * from "./list-products" -export * from "./search" - -/** - * @schema StoreProductsRes - * type: object - * x-expanded-relations: - * field: product - * relations: - * - collection - * - images - * - options - * - options.values - * - tags - * - type - * - variants - * - variants.options - * - variants.prices - * totals: - * - variants.purchasable - * required: - * - product - * properties: - * product: - * description: "Product details." - * $ref: "#/components/schemas/PricedProduct" - */ -export type StoreProductsRes = { - product: PricedProduct -} - -/** - * @schema StorePostSearchRes - * description: "The list of search results." - * allOf: - * - type: object - * required: - * - hits - * properties: - * hits: - * description: "Array of search results. The format of the items depends on the search engine installed on the Medusa backend." - * type: array - * - type: object - */ -export type StorePostSearchRes = { - hits: unknown[] -} & Record - -/** - * @schema StoreProductsListRes - * type: object - * description: "The list of products with pagination fields." - * x-expanded-relations: - * field: products - * relations: - * - collection - * - images - * - options - * - options.values - * - tags - * - type - * - variants - * - variants.options - * - variants.prices - * totals: - * - variants.purchasable - * required: - * - products - * - count - * - offset - * - limit - * properties: - * products: - * type: array - * description: "An array of products details." - * items: - * $ref: "#/components/schemas/PricedProduct" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of products skipped when retrieving the products. - * limit: - * type: integer - * description: The number of items per page - */ -export type StoreProductsListRes = PaginatedResponse & { - products: PricedProduct[] -} diff --git a/packages/medusa/src/api/routes/store/products/list-products.ts b/packages/medusa/src/api/routes/store/products/list-products.ts deleted file mode 100644 index bcbfcc81d9..0000000000 --- a/packages/medusa/src/api/routes/store/products/list-products.ts +++ /dev/null @@ -1,579 +0,0 @@ -import { Transform, Type } from "class-transformer" -import { - IsArray, - IsBoolean, - IsNumber, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { - CartService, - ProductService, - ProductVariantInventoryService, - SalesChannelService, -} from "../../../../services" - -import { MedusaV2Flag, promiseAll } from "@medusajs/utils" -import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" -import PricingService from "../../../../services/pricing" -import { DateComparisonOperator } from "../../../../types/common" -import { PriceSelectionParams } from "../../../../types/price-selection" -import { cleanResponseData } from "../../../../utils/clean-response-data" -import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" -import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean" -import { IsType } from "../../../../utils/validators/is-type" -import { defaultStoreCategoryScope } from "../product-categories" -import { defaultStoreProductRemoteQueryObject } from "./index" - -/** - * @oas [get] /store/products - * operationId: GetProducts - * summary: List Products - * description: | - * Retrieves a list of products. The products can be filtered by fields such as `id` or `q`. The products can also be sorted or paginated. - * This API Route can also be used to retrieve a product by its handle. - * - * For accurate and correct pricing of the products based on the customer's context, it's highly recommended to pass fields such as - * `region_id`, `currency_code`, and `cart_id` when available. - * - * Passing `sales_channel_id` ensures retrieving only products available in the specified sales channel. - * You can alternatively use a publishable API key in the request header instead of passing a `sales_channel_id`. - * externalDocs: - * description: "How to retrieve a product by its handle" - * url: "https://docs.medusajs.com/modules/products/storefront/show-products#retrieve-product-by-handle" - * parameters: - * - (query) q {string} term used to search products' title, description, variant's title, variant's sku, and collection's title. - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by IDs. - * schema: - * oneOf: - * - type: string - * - type: array - * items: - * type: string - * - in: query - * name: sales_channel_id - * style: form - * explode: false - * description: "Filter by sales channel IDs. When provided, only products available in the selected sales channels are retrieved. Alternatively, you can pass a - * publishable API key in the request header and this will have the same effect." - * schema: - * type: array - * items: - * type: string - * - in: query - * name: collection_id - * style: form - * explode: false - * description: Filter by product collection IDs. When provided, only products that belong to the specified product collections are retrieved. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: type_id - * style: form - * explode: false - * description: Filter by product type IDs. When provided, only products that belong to the specified product types are retrieved. - * schema: - * type: array - * items: - * type: string - * - in: query - * name: tags - * style: form - * explode: false - * description: Filter by product tag IDs. When provided, only products that belong to the specified product tags are retrieved. - * schema: - * type: array - * items: - * type: string - * - (query) title {string} Filter by title. - * - (query) description {string} Filter by description - * - (query) handle {string} Filter by handle. - * - (query) is_giftcard {boolean} Whether to retrieve regular products or gift-card products. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: category_id - * style: form - * explode: false - * description: Filter by product category IDs. When provided, only products that belong to the specified product categories are retrieved. - * schema: - * type: array - * x-featureFlag: "product_categories" - * items: - * type: string - * - in: query - * name: include_category_children - * style: form - * explode: false - * description: Whether to include child product categories when filtering using the `category_id` field. - * schema: - * type: boolean - * x-featureFlag: "product_categories" - * - (query) offset=0 {integer} The number of products to skip when retrieving the products. - * - (query) limit=100 {integer} Limit the number of products returned. - * - (query) expand {string} Comma-separated relations that should be expanded in the returned products. - * - (query) fields {string} Comma-separated fields that should be included in the returned products. - * - (query) order {string} A product field to sort-order the retrieved products by. - * - (query) cart_id {string} The ID of the cart. This is useful for accurate pricing based on the cart's context. - * - (query) region_id {string} The ID of the region. This is useful for accurate pricing based on the selected region. - * - in: query - * name: currency_code - * style: form - * explode: false - * description: A 3 character ISO currency code. This is useful for accurate pricing based on the selected currency. - * schema: - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * x-codegen: - * method: list - * queryParams: StoreGetProductsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.products.list() - * .then(({ products, limit, offset, count }) => { - * console.log(products.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useProducts } from "medusa-react" - * - * const Products = () => { - * const { products, isLoading } = useProducts() - * - * return ( - *
- * {isLoading && Loading...} - * {products && !products.length && No Products} - * {products && products.length > 0 && ( - *
    - * {products.map((product) => ( - *
  • {product.title}
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Products - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/products' - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreProductsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const productService: ProductService = req.scope.resolve("productService") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - const pricingService: PricingService = req.scope.resolve("pricingService") - const cartService: CartService = req.scope.resolve("cartService") - - const featureFlagRouter = req.scope.resolve("featureFlagRouter") - - const validated = req.validatedQuery as StoreGetProductsParams - - let { - cart_id, - region_id: regionId, - currency_code: currencyCode, - ...filterableFields - } = req.filterableFields - const listConfig = req.listConfig - - // get only published products for store endpoint - filterableFields["status"] = ["published"] - // store APIs only receive active and public categories to query from - filterableFields["categories"] = { - ...(filterableFields.categories || {}), - // Store APIs are only allowed to query active and public categories - ...defaultStoreCategoryScope, - } - - if (req.publishableApiKeyScopes?.sales_channel_ids.length) { - filterableFields.sales_channel_id = - filterableFields.sales_channel_id || - req.publishableApiKeyScopes.sales_channel_ids - - if (!listConfig.relations.includes("listConfig.relations")) { - listConfig.relations.push("sales_channels") - } - } - - const isMedusaV2Enabled = featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key) - - const promises: Promise[] = [] - - if (isMedusaV2Enabled) { - promises.push( - listAndCountProductWithIsolatedProductModule( - req, - filterableFields, - listConfig - ) - ) - } else { - promises.push(productService.listAndCount(filterableFields, listConfig)) - } - - if (validated.cart_id) { - promises.push( - cartService.retrieve(validated.cart_id, { - select: ["id", "region_id"] as any, - relations: ["region"], - }) - ) - } - - const [[rawProducts, count], cart] = await promiseAll(promises) - - if (validated.cart_id) { - regionId = cart.region_id - currencyCode = cart.region.currency_code - } - - // Create a new reference just for naming purpose - const computedProducts = rawProducts - - // We only set prices if variants.prices are requested - const shouldSetPricing = ["variants", "variants.prices"].every((relation) => - listConfig.relations?.includes(relation) - ) - - // We only set availability if variants are requested - const shouldSetAvailability = listConfig.relations?.includes("variants") - - const decoratePromises: Promise[] = [] - - if (shouldSetPricing) { - decoratePromises.push( - pricingService.setProductPrices(computedProducts, { - cart_id: cart_id, - region_id: regionId, - currency_code: currencyCode, - customer_id: req.user?.customer_id, - include_discount_prices: true, - }) - ) - } - - if (shouldSetAvailability) { - decoratePromises.push( - productVariantInventoryService.setProductAvailability( - computedProducts, - filterableFields.sales_channel_id - ) - ) - } - - // We can run them concurrently as the new properties are assigned to the references - // of the appropriate entity - await promiseAll(decoratePromises) - - res.json({ - products: cleanResponseData(computedProducts, req.allowedProperties || []), - count, - offset: validated.offset, - limit: validated.limit, - }) -} - -async function listAndCountProductWithIsolatedProductModule( - req, - filterableFields, - listConfig -) { - // TODO: Add support for fields/expands - - const remoteQuery = req.scope.resolve("remoteQuery") - - let salesChannelIdFilter = filterableFields.sales_channel_id - if (req.publishableApiKeyScopes?.sales_channel_ids.length) { - salesChannelIdFilter ??= req.publishableApiKeyScopes.sales_channel_ids - } - - delete filterableFields.sales_channel_id - - filterableFields["categories"] = { - $or: [ - { - id: null, - }, - { - ...(filterableFields.categories || {}), - // Store APIs are only allowed to query active and public categories - ...defaultStoreCategoryScope, - }, - ], - } - - // This is not the best way of handling cross filtering but for now I would say it is fine - if (salesChannelIdFilter) { - const salesChannelService = req.scope.resolve( - "salesChannelService" - ) as SalesChannelService - - const productIdsInSalesChannel = - await salesChannelService.listProductIdsBySalesChannelIds( - salesChannelIdFilter - ) - - let filteredProductIds = productIdsInSalesChannel[salesChannelIdFilter] - - if (filterableFields.id) { - filterableFields.id = Array.isArray(filterableFields.id) - ? filterableFields.id - : [filterableFields.id] - - const salesChannelProductIdsSet = new Set(filteredProductIds) - - filteredProductIds = filterableFields.id.filter((productId) => - salesChannelProductIdsSet.has(productId) - ) - } - - filterableFields.id = filteredProductIds - } - - const variables = { - filters: filterableFields, - order: listConfig.order, - skip: listConfig.skip, - take: listConfig.take, - } - - const query = { - product: { - __args: variables, - ...defaultStoreProductRemoteQueryObject, - }, - } - - if (salesChannelIdFilter) { - query.product["sales_channels"]["__args"] = { id: salesChannelIdFilter } - } - - const { - rows: products, - metadata: { count }, - } = await remoteQuery(query) - - products.forEach((product) => { - product.profile_id = product.profile?.id - }) - - return [products, count] -} - -/** - * {@inheritDoc FindPaginationParams} - */ -export class StoreGetProductsPaginationParams extends PriceSelectionParams { - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - offset?: number = 0 - - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 100 - */ - @IsNumber() - @IsOptional() - @Type(() => Number) - limit?: number = 100 - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsString() - @IsOptional() - order?: string -} - -/** - * Parameters used to filter and configure the pagination of the retrieved products. - */ -export class StoreGetProductsParams extends StoreGetProductsPaginationParams { - /** - * {@inheritDoc FilterableProductProps.id} - */ - @IsOptional() - @IsType([String, [String]]) - id?: string | string[] - - /** - * {@inheritDoc FilterableProductProps.q} - */ - @IsString() - @IsOptional() - q?: string - - /** - * {@inheritDoc FilterableProductProps.collection_id} - */ - @IsArray() - @IsOptional() - collection_id?: string[] - - /** - * {@inheritDoc FilterableProductProps.tags} - */ - @IsArray() - @IsOptional() - tags?: string[] - - /** - * {@inheritDoc FilterableProductProps.title} - */ - @IsString() - @IsOptional() - title?: string - - /** - * {@inheritDoc FilterableProductProps.description} - */ - @IsString() - @IsOptional() - description?: string - - /** - * {@inheritDoc FilterableProductProps.handle} - */ - @IsString() - @IsOptional() - handle?: string - - /** - * {@inheritDoc FilterableProductProps.is_giftcard} - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value.toLowerCase())) - is_giftcard?: boolean - - /** - * {@inheritDoc FilterableProductProps.type_id} - */ - @IsArray() - @IsOptional() - type_id?: string[] - - /** - * {@inheritDoc FilterableProductProps.sales_channel_id} - */ - @FeatureFlagDecorators(SalesChannelFeatureFlag.key, [IsOptional(), IsArray()]) - sales_channel_id?: string[] - - /** - * {@inheritDoc FilterableProductProps.category_id} - */ - @IsArray() - @IsOptional() - category_id?: string[] - - /** - * {@inheritDoc FilterableProductProps.include_category_children} - * - * @featureFlag product_categories - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value.toLowerCase())) - include_category_children?: boolean - - /** - * {@inheritDoc FilterableProductProps.created_at} - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * {@inheritDoc FilterableProductProps.created_at} - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator -} diff --git a/packages/medusa/src/api/routes/store/products/search.ts b/packages/medusa/src/api/routes/store/products/search.ts deleted file mode 100644 index 213a1ccb6d..0000000000 --- a/packages/medusa/src/api/routes/store/products/search.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { IsNumber, IsOptional, IsString } from "class-validator" - -import ProductService from "../../../../services/product" -import { SearchService } from "../../../../services" -import { Type } from "class-transformer" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /store/products/search - * operationId: PostProductsSearch - * summary: Search Products - * description: "Run a search query on products using the search service installed on the Medusa backend. The searching is handled through the search service, so the returned data's - * format depends on the search service you're using." - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostSearchReq" - * x-codegen: - * method: search - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.products.search({ - * q: "Shirt" - * }) - * .then(({ hits }) => { - * console.log(hits.length); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/products/search' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "q": "Shirt" - * }' - * tags: - * - Products - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostSearchRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - // As we want to allow wildcards, we pass a config allowing this - const validated = await validator(StorePostSearchReq, req.body, { - whitelist: false, - forbidNonWhitelisted: false, - }) - - const { q, offset, limit, filter, ...options } = validated - - const paginationOptions = { offset, limit } - - const searchService: SearchService = req.scope.resolve("searchService") - - const results = await searchService.search(ProductService.IndexName, q, { - paginationOptions, - filter, - additionalOptions: options, - }) - - res.status(200).send(results) -} - -/** - * @schema StorePostSearchReq - * type: object - * properties: - * q: - * type: string - * description: The search query. - * offset: - * type: number - * description: The number of products to skip when retrieving the products. - * limit: - * type: number - * description: Limit the number of products returned. - * filter: - * description: Pass filters based on the search service. - */ -export class StorePostSearchReq { - @IsOptional() - @IsString() - q?: string - - @IsOptional() - @IsNumber() - @Type(() => Number) - offset?: number - - @IsOptional() - @IsNumber() - @Type(() => Number) - limit?: number - - @IsOptional() - filter?: unknown -} diff --git a/packages/medusa/src/api/routes/store/regions/__tests__/get-region.js b/packages/medusa/src/api/routes/store/regions/__tests__/get-region.js deleted file mode 100644 index f314d0a10c..0000000000 --- a/packages/medusa/src/api/routes/store/regions/__tests__/get-region.js +++ /dev/null @@ -1,52 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -describe("Get region by id", () => { - describe("get region by id successfull", () => { - let subject - beforeAll(async () => { - subject = await request( - "GET", - `/store/regions/${IdMap.getId("testRegion")}` - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls retrieve from region service", () => { - expect(RegionServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(RegionServiceMock.retrieve).toHaveBeenCalledWith( - IdMap.getId("testRegion"), - { - relations: [ - "countries", - "payment_providers", - "fulfillment_providers", - "currency", - ], - select: [ - "id", - "name", - "currency_code", - "tax_rate", - "tax_code", - "gift_cards_taxable", - "automatic_taxes", - "tax_provider_id", - "metadata", - "created_at", - "updated_at", - "deleted_at", - ], - } - ) - }) - - it("returns region", () => { - expect(subject.body.region.id).toEqual(IdMap.getId("testRegion")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/regions/__tests__/list-regions.js b/packages/medusa/src/api/routes/store/regions/__tests__/list-regions.js deleted file mode 100644 index e0217eabbc..0000000000 --- a/packages/medusa/src/api/routes/store/regions/__tests__/list-regions.js +++ /dev/null @@ -1,55 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { RegionServiceMock } from "../../../../../services/__mocks__/region" - -describe("List regions", () => { - describe("list regions", () => { - let subject - beforeAll(async () => { - subject = await request("GET", `/store/regions`) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls list from region service", () => { - expect(RegionServiceMock.listAndCount).toHaveBeenCalledTimes(1) - expect( - RegionServiceMock.listAndCount.mock.calls[0][1].relations - ).toHaveLength(4) - expect(RegionServiceMock.listAndCount).toHaveBeenCalledWith( - {}, - { - relations: expect.arrayContaining([ - "countries", - "currency", - "fulfillment_providers", - "payment_providers", - ]), - select: [ - "id", - "name", - "currency_code", - "tax_rate", - "tax_code", - "gift_cards_taxable", - "automatic_taxes", - "tax_provider_id", - "metadata", - "created_at", - "updated_at", - "deleted_at", - ], - skip: 0, - take: 100, - order: { created_at: "DESC" }, - } - ) - }) - - it("returns regions", () => { - expect(subject.body.regions[0].id).toEqual(IdMap.getId("testRegion")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/regions/get-region.ts b/packages/medusa/src/api/routes/store/regions/get-region.ts deleted file mode 100644 index fd32d2cd9b..0000000000 --- a/packages/medusa/src/api/routes/store/regions/get-region.ts +++ /dev/null @@ -1,80 +0,0 @@ -import RegionService from "../../../../services/region" -import { FindParams } from "../../../../types/common" - -/** - * @oas [get] /store/regions/{id} - * operationId: GetRegionsRegion - * summary: Get a Region - * description: "Retrieve a Region's details." - * parameters: - * - (path) id=* {string} The ID of the Region. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.regions.retrieve(regionId) - * .then(({ region }) => { - * console.log(region.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useRegion } from "medusa-react" - * - * type Props = { - * regionId: string - * } - * - * const Region = ({ regionId }: Props) => { - * const { region, isLoading } = useRegion( - * regionId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {region && {region.name}} - *
- * ) - * } - * - * export default Region - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/regions/{id}' - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreRegionsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { region_id } = req.params - const regionService: RegionService = req.scope.resolve("regionService") - - const region = await regionService.retrieve(region_id, req.retrieveConfig) - - res.json({ region }) -} - -export class StoreGetRegionsRegionParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/store/regions/index.ts b/packages/medusa/src/api/routes/store/regions/index.ts deleted file mode 100644 index 8c2efcb9e2..0000000000 --- a/packages/medusa/src/api/routes/store/regions/index.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { PaginatedResponse } from "@medusajs/types" -import { TaxInclusivePricingFeatureFlag, wrapHandler } from "@medusajs/utils" -import { Router } from "express" -import { transformQuery } from "../../../middlewares" -import { Region } from "./../../../../" -import getRegion from "./get-region" -import listRegions, { StoreGetRegionsParams } from "./list-regions" - -const route = Router() - -export default (app, featureFlagRouter) => { - if (featureFlagRouter.isFeatureEnabled(TaxInclusivePricingFeatureFlag.key)) { - defaultStoreRegionFields.push("includes_tax") - } - - const retrieveTransformQueryConfig = { - defaultFields: defaultStoreRegionFields, - defaultRelations: defaultStoreRegionRelations, - allowedRelations: defaultStoreRegionRelations, - isList: false, - } - - const listTransformQueryConfig = { - ...retrieveTransformQueryConfig, - isList: true, - } - - app.use("/regions", route) - - route.get( - "/", - transformQuery(StoreGetRegionsParams, listTransformQueryConfig), - wrapHandler(listRegions) - ) - - route.get( - "/:region_id", - transformQuery(StoreGetRegionsParams, retrieveTransformQueryConfig), - wrapHandler(getRegion) - ) - - return app -} - -export const defaultStoreRegionRelations = [ - "countries", - "payment_providers", - "fulfillment_providers", - "currency", -] - -export const defaultStoreRegionFields = [ - "id", - "name", - "currency_code", - "tax_rate", - "tax_code", - "gift_cards_taxable", - "automatic_taxes", - "tax_provider_id", - "metadata", - "created_at", - "updated_at", - "deleted_at", -] - -/** - * @schema StoreRegionsListRes - * type: object - * description: "The list of regions with pagination fields." - * x-expanded-relations: - * field: regions - * relations: - * - countries - * - payment_providers - * - fulfillment_providers - * eager: - * - payment_providers - * - fulfillment_providers - * required: - * - regions - * properties: - * regions: - * type: array - * description: "An array of regions details." - * items: - * $ref: "#/components/schemas/Region" - * count: - * type: integer - * description: The total number of items available - * offset: - * type: integer - * description: The number of regions skipped when retrieving the regions. - * limit: - * type: integer - * description: The number of items per page - */ -export type StoreRegionsListRes = PaginatedResponse & { - regions: Region[] -} - -/** - * @schema StoreRegionsRes - * type: object - * description: "The region's details." - * x-expanded-relations: - * field: region - * relations: - * - countries - * - payment_providers - * - fulfillment_providers - * eager: - * - payment_providers - * - fulfillment_providers - * required: - * - region - * properties: - * region: - * description: "Region details." - * $ref: "#/components/schemas/Region" - */ -export type StoreRegionsRes = { - region: Region -} - -export * from "./get-region" -export * from "./list-regions" diff --git a/packages/medusa/src/api/routes/store/regions/list-regions.ts b/packages/medusa/src/api/routes/store/regions/list-regions.ts deleted file mode 100644 index 6c3303fded..0000000000 --- a/packages/medusa/src/api/routes/store/regions/list-regions.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { IsOptional, ValidateNested } from "class-validator" - -import { Type } from "class-transformer" -import RegionService from "../../../../services/region" -import { - DateComparisonOperator, - extendedFindParamsMixin, -} from "../../../../types/common" - -/** - * @oas [get] /store/regions - * operationId: GetRegions - * summary: List Regions - * description: "Retrieve a list of regions. The regions can be filtered by fields such as `created_at`. The regions can also be paginated. This API Route is useful to - * show the customer all available regions to choose from." - * externalDocs: - * description: "How to use regions in a storefront" - * url: "https://docs.medusajs.com/modules/regions-and-currencies/storefront/use-regions" - * parameters: - * - (query) offset=0 {integer} The number of regions to skip when retrieving the regions. - * - (query) limit=100 {integer} Limit the number of regions returned. - * - in: query - * name: created_at - * description: Filter by a creation date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * - in: query - * name: updated_at - * description: Filter by an update date range. - * schema: - * type: object - * properties: - * lt: - * type: string - * description: filter by dates less than this date - * format: date - * gt: - * type: string - * description: filter by dates greater than this date - * format: date - * lte: - * type: string - * description: filter by dates less than or equal to this date - * format: date - * gte: - * type: string - * description: filter by dates greater than or equal to this date - * format: date - * x-codegen: - * method: list - * queryParams: StoreGetRegionsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.regions.list() - * .then(({ regions, count, limit, offset }) => { - * console.log(regions.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useRegions } from "medusa-react" - * - * const Regions = () => { - * const { regions, isLoading } = useRegions() - * - * return ( - *
- * {isLoading && Loading...} - * {regions?.length && ( - *
    - * {regions.map((region) => ( - *
  • - * {region.name} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default Regions - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/regions' - * tags: - * - Regions - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreRegionsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const regionService: RegionService = req.scope.resolve("regionService") - const { limit, offset } = req.validatedQuery - - const [regions, count] = await regionService.listAndCount( - req.filterableFields, - req.listConfig - ) - - res.json({ regions, count, limit, offset }) -} - -export class StoreGetRegionsParams extends extendedFindParamsMixin({ - limit: 100, - offset: 0, -}) { - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator -} diff --git a/packages/medusa/src/api/routes/store/return-reasons/get-reason.ts b/packages/medusa/src/api/routes/store/return-reasons/get-reason.ts deleted file mode 100644 index 57c99de3ce..0000000000 --- a/packages/medusa/src/api/routes/store/return-reasons/get-reason.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { - defaultStoreReturnReasonFields, - defaultStoreReturnReasonRelations, -} from "." -import ReturnReasonService from "../../../../services/return-reason" - -/** - * @oas [get] /store/return-reasons/{id} - * operationId: "GetReturnReasonsReason" - * summary: "Get a Return Reason" - * description: "Retrieve a Return Reason's details." - * parameters: - * - (path) id=* {string} The id of the Return Reason. - * x-codegen: - * method: retrieve - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.returnReasons.retrieve(reasonId) - * .then(({ return_reason }) => { - * console.log(return_reason.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useReturnReason } from "medusa-react" - * - * type Props = { - * returnReasonId: string - * } - * - * const ReturnReason = ({ returnReasonId }: Props) => { - * const { - * return_reason, - * isLoading - * } = useReturnReason( - * returnReasonId - * ) - * - * return ( - *
- * {isLoading && Loading...} - * {return_reason && {return_reason.label}} - *
- * ) - * } - * - * export default ReturnReason - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/return-reasons/{id}' - * tags: - * - Return Reasons - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreReturnReasonsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const returnReasonService: ReturnReasonService = req.scope.resolve( - "returnReasonService" - ) - - const return_reason = await returnReasonService.retrieve(id, { - select: defaultStoreReturnReasonFields, - relations: defaultStoreReturnReasonRelations, - }) - - res.status(200).json({ return_reason }) -} diff --git a/packages/medusa/src/api/routes/store/return-reasons/index.ts b/packages/medusa/src/api/routes/store/return-reasons/index.ts deleted file mode 100644 index 28a8cd3769..0000000000 --- a/packages/medusa/src/api/routes/store/return-reasons/index.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { ReturnReason } from "./../../../../" -import { Router } from "express" -import middlewares from "../../../middlewares" - -const route = Router() - -export default (app) => { - app.use("/return-reasons", route) - - /** - * List reasons - */ - route.get("/", middlewares.wrap(require("./list-reasons").default)) - - /** - * Retrieve reason - */ - route.get("/:id", middlewares.wrap(require("./get-reason").default)) - - return app -} - -export const defaultStoreReturnReasonFields: (keyof ReturnReason)[] = [ - "id", - "value", - "label", - "parent_return_reason_id", - "description", - "created_at", - "updated_at", - "deleted_at", -] - -export const defaultStoreReturnReasonRelations: (keyof ReturnReason)[] = [ - "parent_return_reason", - "return_reason_children", -] - -/** - * @schema StoreReturnReasonsListRes - * type: object - * description: "The list of return reasons." - * x-expanded-relations: - * field: return_reasons - * relations: - * - parent_return_reason - * - return_reason_children - * required: - * - return_reasons - * properties: - * return_reasons: - * type: array - * description: "An array of return reasons details." - * items: - * $ref: "#/components/schemas/ReturnReason" - */ -export type StoreReturnReasonsListRes = { - return_reasons: ReturnReason[] -} - -/** - * @schema StoreReturnReasonsRes - * type: object - * description: "The return reason's details." - * x-expanded-relations: - * field: return_reason - * relations: - * - parent_return_reason - * - return_reason_children - * required: - * - return_reason - * properties: - * return_reason: - * description: "Return reason details." - * $ref: "#/components/schemas/ReturnReason" - */ -export type StoreReturnReasonsRes = { - return_reason: ReturnReason -} - -export * from "./get-reason" diff --git a/packages/medusa/src/api/routes/store/return-reasons/list-reasons.ts b/packages/medusa/src/api/routes/store/return-reasons/list-reasons.ts deleted file mode 100644 index 0f2a12bf82..0000000000 --- a/packages/medusa/src/api/routes/store/return-reasons/list-reasons.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { - defaultStoreReturnReasonFields, - defaultStoreReturnReasonRelations, -} from "." -import ReturnReasonService from "../../../../services/return-reason" - -/** - * @oas [get] /store/return-reasons - * operationId: "GetReturnReasons" - * summary: "List Return Reasons" - * description: "Retrieve a list of Return Reasons. This is useful when implementing a Create Return flow in the storefront." - * x-codegen: - * method: list - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.returnReasons.list() - * .then(({ return_reasons }) => { - * console.log(return_reasons.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useReturnReasons } from "medusa-react" - * - * const ReturnReasons = () => { - * const { - * return_reasons, - * isLoading - * } = useReturnReasons() - * - * return ( - *
- * {isLoading && Loading...} - * {return_reasons?.length && ( - *
    - * {return_reasons.map((returnReason) => ( - *
  • - * {returnReason.label} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ReturnReasons - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/return-reasons' - * tags: - * - Return Reasons - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreReturnReasonsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const returnReasonService: ReturnReasonService = req.scope.resolve( - "returnReasonService" - ) - - const query = { parent_return_reason_id: null } - - const return_reasons = await returnReasonService.list(query, { - select: defaultStoreReturnReasonFields, - relations: defaultStoreReturnReasonRelations, - }) - - res.status(200).json({ return_reasons }) -} diff --git a/packages/medusa/src/api/routes/store/returns/create-return.ts b/packages/medusa/src/api/routes/store/returns/create-return.ts deleted file mode 100644 index 1e59b76870..0000000000 --- a/packages/medusa/src/api/routes/store/returns/create-return.ts +++ /dev/null @@ -1,354 +0,0 @@ -import { - IsArray, - IsNotEmpty, - IsNumber, - IsOptional, - IsString, - Min, - ValidateNested, -} from "class-validator" - -import { Type } from "class-transformer" -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import EventBusService from "../../../../services/event-bus" -import IdempotencyKeyService from "../../../../services/idempotency-key" -import ReturnService from "../../../../services/return" -import { validator } from "../../../../utils/validator" -import { defaultRelations } from "." -import { Logger } from "@medusajs/types" - -/** - * @oas [post] /store/returns - * operationId: "PostReturns" - * summary: "Create Return" - * description: "Create a Return for an Order. If a return shipping method is specified, the return is automatically fulfilled." - * externalDocs: - * description: "How to create a return in a storefront" - * url: "https://docs.medusajs.com/modules/orders/storefront/create-return" - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostReturnsReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.returns.create({ - * order_id, - * items: [ - * { - * item_id, - * quantity: 1 - * } - * ] - * }) - * .then((data) => { - * console.log(data.return.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCreateReturn } from "medusa-react" - * - * type CreateReturnData = { - * items: { - * item_id: string, - * quantity: number - * }[] - * return_shipping: { - * option_id: string - * } - * } - * - * type Props = { - * orderId: string - * } - * - * const CreateReturn = ({ orderId }: Props) => { - * const createReturn = useCreateReturn() - * // ... - * - * const handleCreate = (data: CreateReturnData) => { - * createReturn.mutate({ - * ...data, - * order_id: orderId - * }, { - * onSuccess: ({ return: returnData }) => { - * console.log(returnData.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateReturn - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/returns' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "order_id": "asfasf", - * "items": [ - * { - * "item_id": "assfasf", - * "quantity": 1 - * } - * ] - * }' - * tags: - * - Returns - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreReturnsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const returnDto = await validator(StorePostReturnsReq, req.body) - - const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve( - "idempotencyKeyService" - ) - const manager: EntityManager = req.scope.resolve("manager") - - const headerKey = req.get("Idempotency-Key") || "" - - let idempotencyKey - try { - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .initializeRequest(headerKey, req.method, req.params, req.path) - }) - } catch (error) { - res.status(409).send("Failed to create idempotency key") - return - } - - res.setHeader("Access-Control-Expose-Headers", "Idempotency-Key") - res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key) - - try { - const returnService: ReturnService = req.scope.resolve("returnService") - const eventBus: EventBusService = req.scope.resolve("eventBusService") - - let inProgress = true - let err: unknown = false - - while (inProgress) { - switch (idempotencyKey.recovery_point) { - case "started": { - await manager - .transaction("SERIALIZABLE", async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .workStage(idempotencyKey.idempotency_key, async (manager) => { - const returnObj: any = { - order_id: returnDto.order_id, - idempotency_key: idempotencyKey.idempotency_key, - items: returnDto.items, - } - - if (returnDto.return_shipping) { - returnObj.shipping_method = returnDto.return_shipping - } - - const createdReturn = await returnService - .withTransaction(manager) - .create(returnObj) - - if (returnDto.return_shipping) { - await returnService - .withTransaction(manager) - .fulfill(createdReturn.id) - } - - await eventBus - .withTransaction(manager) - .emit("order.return_requested", { - id: returnDto.order_id, - return_id: createdReturn.id, - }) - - return { - recovery_point: "return_requested", - } - }) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "return_requested": { - await manager - .transaction("SERIALIZABLE", async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .workStage(idempotencyKey.idempotency_key, async (manager) => { - const returnOrders = await returnService - .withTransaction(manager) - .list( - { - idempotency_key: idempotencyKey.idempotency_key, - }, - { - relations: defaultRelations, - } - ) - if (!returnOrders.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Return not found` - ) - } - const returnOrder = returnOrders[0] - - return { - response_code: 200, - response_body: { return: returnOrder }, - } - }) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "finished": { - inProgress = false - break - } - - default: - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .update(idempotencyKey.idempotency_key, { - recovery_point: "finished", - response_code: 500, - response_body: { message: "Unknown recovery point" }, - }) - }) - break - } - } - - if (err) { - throw err - } - - res.status(idempotencyKey.response_code).json(idempotencyKey.response_body) - } catch (err) { - const logger: Logger = req.scope.resolve("logger") - logger.log(err) - throw err - } -} - -class ReturnShipping { - @IsString() - @IsNotEmpty() - option_id: string -} - -class Item { - @IsString() - @IsNotEmpty() - item_id: string - - @IsNumber() - @Min(1) - quantity: number - - @IsOptional() - @IsString() - reason_id?: string - - @IsOptional() - @IsString() - note?: string -} - -/** - * @schema StorePostReturnsReq - * type: object - * description: "The details of the return to create." - * required: - * - order_id - * - items - * properties: - * order_id: - * type: string - * description: The ID of the Order to create the return for. - * items: - * description: "The items to include in the return." - * type: array - * items: - * type: object - * required: - * - item_id - * - quantity - * properties: - * item_id: - * description: The ID of the line item to return. - * type: string - * quantity: - * description: The quantity to return. - * type: integer - * reason_id: - * description: The ID of the return reason. Return reasons can be retrieved from the List Return Reasons API Route. - * type: string - * note: - * description: A note to add to the item returned. - * type: string - * return_shipping: - * description: The return shipping method used to return the items. If provided, a fulfillment is automatically created for the return. - * type: object - * required: - * - option_id - * properties: - * option_id: - * type: string - * description: The ID of the Shipping Option to create the Shipping Method from. - */ -export class StorePostReturnsReq { - @IsString() - @IsNotEmpty() - order_id: string - - @IsArray() - @ValidateNested({ each: true }) - @Type(() => Item) - items: Item[] - - @IsOptional() - @ValidateNested() - @Type(() => ReturnShipping) - return_shipping?: ReturnShipping -} diff --git a/packages/medusa/src/api/routes/store/returns/index.ts b/packages/medusa/src/api/routes/store/returns/index.ts deleted file mode 100644 index 3a7c84d684..0000000000 --- a/packages/medusa/src/api/routes/store/returns/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Return } from "./../../../../models/return" -import { Router } from "express" -import middlewares from "../../../middlewares" - -const route = Router() - -export default (app) => { - app.use("/returns", route) - - route.post("/", middlewares.wrap(require("./create-return").default)) - - return app -} - -export const defaultRelations = ["items", "items.reason"] - -/** - * @schema StoreReturnsRes - * type: object - * description: "The return's details." - * x-expanded-relations: - * field: return - * relations: - * - items - * - items.reason - * eager: - * - items - * required: - * - return - * properties: - * return: - * description: "Return details." - * $ref: "#/components/schemas/Return" - */ -export type StoreReturnsRes = { - return: Return -} - -export * from "./create-return" diff --git a/packages/medusa/src/api/routes/store/shipping-options/__tests__/list-options.js b/packages/medusa/src/api/routes/store/shipping-options/__tests__/list-options.js deleted file mode 100644 index e3e0b7e3bc..0000000000 --- a/packages/medusa/src/api/routes/store/shipping-options/__tests__/list-options.js +++ /dev/null @@ -1,41 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { ShippingOptionServiceMock } from "../../../../../services/__mocks__/shipping-option" -import { ProductServiceMock } from "../../../../../services/__mocks__/product" - -describe("GET /store/shipping-options", () => { - describe("retrieves shipping options by product ids", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/store/shipping-options?product_ids=1,2,3®ion_id=test-region` - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls ShippingProfileService fetchOptionsByProductIds", () => { - expect(ProductServiceMock.list).toHaveBeenCalledTimes(1) - expect(ProductServiceMock.list).toHaveBeenCalledWith({ - id: ["1", "2", "3"], - }) - expect(ShippingOptionServiceMock.list).toHaveBeenCalledTimes(1) - expect(ShippingOptionServiceMock.list).toHaveBeenCalledWith( - { - admin_only: false, - profile_id: [undefined, undefined], - region_id: "test-region", - }, - { relations: ["requirements"] } - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/shipping-options/__tests__/list-shipping-options.js b/packages/medusa/src/api/routes/store/shipping-options/__tests__/list-shipping-options.js deleted file mode 100644 index 1b77104b06..0000000000 --- a/packages/medusa/src/api/routes/store/shipping-options/__tests__/list-shipping-options.js +++ /dev/null @@ -1,47 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" -import { carts, CartServiceMock } from "../../../../../services/__mocks__/cart" -import { ShippingProfileServiceMock } from "../../../../../services/__mocks__/shipping-profile" - -describe("GET /store/shipping-options", () => { - describe("retrieves shipping options", () => { - let subject - - beforeAll(async () => { - subject = await request( - "GET", - `/store/shipping-options/${IdMap.getId("emptyCart")}` - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls CartService retrieve", () => { - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - expect(CartServiceMock.retrieveWithTotals).toHaveBeenCalledWith( - IdMap.getId("emptyCart") - ) - }) - - it("calls ShippingProfileService fetchCartOptions", () => { - expect(ShippingProfileServiceMock.fetchCartOptions).toHaveBeenCalledTimes( - 1 - ) - expect(ShippingProfileServiceMock.fetchCartOptions).toHaveBeenCalledWith( - carts.emptyCart - ) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the shippingOptions", () => { - expect(subject.body.shipping_options[0].id).toEqual( - IdMap.getId("cartShippingOption") - ) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/shipping-options/index.ts b/packages/medusa/src/api/routes/store/shipping-options/index.ts deleted file mode 100644 index ff813bd7a2..0000000000 --- a/packages/medusa/src/api/routes/store/shipping-options/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Router } from "express" -import middlewares from "../../../middlewares" -import { PricedShippingOption } from "../../../../types/pricing" - -const route = Router() - -export default (app) => { - app.use("/shipping-options", route) - - route.get("/", middlewares.wrap(require("./list-options").default)) - route.get( - "/:cart_id", - middlewares.wrap(require("./list-shipping-options").default) - ) - - return app -} - -export const defaultRelations = ["requirements"] - -/** - * @schema StoreShippingOptionsListRes - * type: object - * description: "The list of shipping options." - * x-expanded-relations: - * field: shipping_options - * relations: - * - requirements - * required: - * - shipping_options - * properties: - * shipping_options: - * type: array - * description: "An array of shipping options details." - * items: - * $ref: "#/components/schemas/PricedShippingOption" - */ -export type StoreShippingOptionsListRes = { - shipping_options: PricedShippingOption[] -} - -/** - * @schema StoreCartShippingOptionsListRes - * type: object - * x-expanded-relations: - * field: shipping_options - * implicit: - * - profile - * - requirements - * required: - * - shipping_options - * properties: - * shipping_options: - * type: array - * description: "An array of shipping options details." - * items: - * $ref: "#/components/schemas/PricedShippingOption" - */ -export type StoreCartShippingOptionsListRes = { - shipping_options: PricedShippingOption[] -} - -export * from "./list-options" -export * from "./list-shipping-options" diff --git a/packages/medusa/src/api/routes/store/shipping-options/list-options.ts b/packages/medusa/src/api/routes/store/shipping-options/list-options.ts deleted file mode 100644 index bbb2655f00..0000000000 --- a/packages/medusa/src/api/routes/store/shipping-options/list-options.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { FlagRouter, MedusaV2Flag } from "@medusajs/utils" -import { IsBooleanString, IsOptional, IsString } from "class-validator" -import { defaultRelations } from "." -import { - PricingService, - ProductService, - ShippingProfileService, -} from "../../../../services" -import ShippingOptionService from "../../../../services/shipping-option" -import { validator } from "../../../../utils/validator" - -/** - * @oas [get] /store/shipping-options - * operationId: GetShippingOptions - * summary: Get Shipping Options - * description: "Retrieve a list of Shipping Options." - * parameters: - * - (query) is_return {boolean} Whether return shipping options should be included. By default, all shipping options are returned. - * - (query) product_ids {string} "Comma-separated list of Product IDs to filter Shipping Options by. If provided, only shipping options that can be used with the provided products are retrieved." - * - (query) region_id {string} "The ID of the region that the shipping options belong to. If not provided, all shipping options are retrieved." - * x-codegen: - * method: list - * queryParams: StoreGetShippingOptionsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.shippingOptions.list() - * .then(({ shipping_options }) => { - * console.log(shipping_options.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useShippingOptions } from "medusa-react" - * - * const ShippingOptions = () => { - * const { - * shipping_options, - * isLoading, - * } = useShippingOptions() - * - * return ( - *
- * {isLoading && Loading...} - * {shipping_options?.length && - * shipping_options?.length > 0 && ( - *
    - * {shipping_options?.map((shipping_option) => ( - *
  • - * {shipping_option.id} - *
  • - * ))} - *
- * )} - *
- * ) - * } - * - * export default ShippingOptions - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/shipping-options' - * tags: - * - Shipping Options - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreShippingOptionsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(StoreGetShippingOptionsParams, req.query) - - const productIds = - (validated.product_ids && validated.product_ids.split(",")) || [] - const regionId = validated.region_id - const productService: ProductService = req.scope.resolve("productService") - const pricingService: PricingService = req.scope.resolve("pricingService") - const shippingOptionService: ShippingOptionService = req.scope.resolve( - "shippingOptionService" - ) - const shippingProfileService: ShippingProfileService = req.scope.resolve( - "shippingProfileService" - ) - const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter") - - // should be selector - const query: Record = {} - - if ("is_return" in req.query) { - query.is_return = validated.is_return === "true" - } - - if (regionId) { - query.region_id = regionId - } - - query.admin_only = false - - if (productIds.length) { - if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) { - const productShippinProfileMap = - await shippingProfileService.getMapProfileIdsByProductIds(productIds) - - query.profile_id = [...productShippinProfileMap.values()] - } else { - const prods = await productService.list({ id: productIds }) - query.profile_id = prods.map((p) => p.profile_id) - } - } - - const options = await shippingOptionService.list(query, { - relations: defaultRelations, - }) - - const data = await pricingService.setShippingOptionPrices(options) - - res.status(200).json({ shipping_options: data }) -} - -/** - * Filters to apply on the retrieved shipping options. - */ -export class StoreGetShippingOptionsParams { - /** - * Product ID that is used to filter shipping options by whether they can be used to ship that product. - */ - @IsOptional() - @IsString() - product_ids?: string - - /** - * Filter the shipping options by the ID of their associated region. - */ - @IsOptional() - @IsString() - region_id?: string - - /** - * Filter the shipping options by whether they're return shipping options. - */ - @IsOptional() - @IsBooleanString() - is_return?: string -} diff --git a/packages/medusa/src/api/routes/store/shipping-options/list-shipping-options.ts b/packages/medusa/src/api/routes/store/shipping-options/list-shipping-options.ts deleted file mode 100644 index 62b6167ae9..0000000000 --- a/packages/medusa/src/api/routes/store/shipping-options/list-shipping-options.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { CartService, PricingService } from "../../../../services" -import ShippingProfileService from "../../../../services/shipping-profile" - -/** - * @oas [get] /store/shipping-options/{cart_id} - * operationId: GetShippingOptionsCartId - * summary: List for Cart - * description: "Retrieve a list of Shipping Options available for a cart." - * externalDocs: - * description: "How to implement shipping step in checkout" - * url: "https://docs.medusajs.com/modules/carts-and-checkout/storefront/implement-checkout-flow#shipping-step" - * parameters: - * - (path) cart_id {string} The ID of the Cart. - * x-codegen: - * method: listCartOptions - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.shippingOptions.listCartOptions(cartId) - * .then(({ shipping_options }) => { - * console.log(shipping_options.length); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCartShippingOptions } from "medusa-react" - * - * type Props = { - * cartId: string - * } - * - * const ShippingOptions = ({ cartId }: Props) => { - * const { shipping_options, isLoading } = - * useCartShippingOptions(cartId) - * - * return ( - *
- * {isLoading && Loading...} - * {shipping_options && !shipping_options.length && ( - * No shipping options - * )} - * {shipping_options && ( - *
    - * {shipping_options.map( - * (shipping_option) => ( - *
  • - * {shipping_option.name} - *
  • - * ) - * )} - *
- * )} - *
- * ) - * } - * - * export default ShippingOptions - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/shipping-options/{cart_id}' - * tags: - * - Shipping Options - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreCartShippingOptionsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { cart_id } = req.params - - const cartService: CartService = req.scope.resolve("cartService") - const pricingService: PricingService = req.scope.resolve("pricingService") - const shippingProfileService: ShippingProfileService = req.scope.resolve( - "shippingProfileService" - ) - - const cart = await cartService.retrieveWithTotals(cart_id) - const options = await shippingProfileService.fetchCartOptions(cart) - const data = await pricingService.setShippingOptionPrices(options, { - cart_id, - }) - - res.status(200).json({ shipping_options: data }) -} diff --git a/packages/medusa/src/api/routes/store/swaps/create-swap.ts b/packages/medusa/src/api/routes/store/swaps/create-swap.ts deleted file mode 100644 index f71c0e40f9..0000000000 --- a/packages/medusa/src/api/routes/store/swaps/create-swap.ts +++ /dev/null @@ -1,407 +0,0 @@ -import { - IsArray, - IsNotEmpty, - IsNumber, - IsOptional, - IsString, - Min, - ValidateNested, -} from "class-validator" -import { defaultStoreSwapFields, defaultStoreSwapRelations } from "." - -import { EntityManager } from "typeorm" -import IdempotencyKeyService from "../../../../services/idempotency-key" -import { MedusaError } from "medusa-core-utils" -import OrderService from "../../../../services/order" -import ReturnService from "../../../../services/return" -import SwapService from "../../../../services/swap" -import { Type } from "class-transformer" -import { validator } from "../../../../utils/validator" - -/** - * @oas [post] /store/swaps - * operationId: PostSwaps - * summary: Create a Swap - * description: | - * Create a Swap for an Order. This will also create a return and associate it with the swap. If a return shipping option is specified, the return will automatically be fulfilled. - * To complete the swap, you must use the Complete Cart API Route passing it the ID of the swap's cart. - * - * An idempotency key will be generated if none is provided in the header `Idempotency-Key` and added to - * the response. If an error occurs during swap creation or the request is interrupted for any reason, the swap creation can be retried by passing the idempotency - * key in the `Idempotency-Key` header. - * externalDocs: - * description: "How to create a swap" - * url: "https://docs.medusajs.com/modules/orders/storefront/create-swap" - * requestBody: - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StorePostSwapsReq" - * x-codegen: - * method: create - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.swaps.create({ - * order_id, - * return_items: [ - * { - * item_id, - * quantity: 1 - * } - * ], - * additional_items: [ - * { - * variant_id, - * quantity: 1 - * } - * ] - * }) - * .then(({ swap }) => { - * console.log(swap.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCreateSwap } from "medusa-react" - * - * type Props = { - * orderId: string - * } - * - * type CreateData = { - * return_items: { - * item_id: string - * quantity: number - * }[] - * additional_items: { - * variant_id: string - * quantity: number - * }[] - * return_shipping_option: string - * } - * - * const CreateSwap = ({ - * orderId - * }: Props) => { - * const createSwap = useCreateSwap() - * // ... - * - * const handleCreate = ( - * data: CreateData - * ) => { - * createSwap.mutate({ - * ...data, - * order_id: orderId - * }, { - * onSuccess: ({ swap }) => { - * console.log(swap.id) - * } - * }) - * } - * - * // ... - * } - * - * export default CreateSwap - * - lang: Shell - * label: cURL - * source: | - * curl -X POST '{backend_url}/store/swaps' \ - * -H 'Content-Type: application/json' \ - * --data-raw '{ - * "order_id": "{order_id}", - * "return_items": [ - * { - * "item_id": "{item_id}", - * "quantity": 1 - * } - * ], - * "additional_items": [ - * { - * "variant_id": "{variant_id}", - * "quantity": 1 - * } - * ] - * }' - * tags: - * - Swaps - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreSwapsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const swapDto = await validator(StorePostSwapsReq, req.body) - - const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve( - "idempotencyKeyService" - ) - const manager: EntityManager = req.scope.resolve("manager") - - const headerKey = req.get("Idempotency-Key") || "" - - let idempotencyKey - try { - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .initializeRequest(headerKey, req.method, req.params, req.path) - }) - } catch (error) { - res.status(409).send("Failed to create idempotency key") - return - } - - res.setHeader("Access-Control-Expose-Headers", "Idempotency-Key") - res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key) - - const orderService: OrderService = req.scope.resolve("orderService") - const swapService: SwapService = req.scope.resolve("swapService") - const returnService: ReturnService = req.scope.resolve("returnService") - - let inProgress = true - let err: unknown = false - - while (inProgress) { - switch (idempotencyKey.recovery_point) { - case "started": { - await manager - .transaction("SERIALIZABLE", async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .workStage(idempotencyKey.idempotency_key, async (manager) => { - const order = await orderService - .withTransaction(manager) - .retrieve(swapDto.order_id, { - select: ["refunded_total", "total"], - relations: [ - "items.variant", - "items.tax_lines", - "swaps.additional_items.variant.product.profiles", - "swaps.additional_items.tax_lines", - ], - }) - - let returnShipping - if (swapDto.return_shipping_option) { - returnShipping = { - option_id: swapDto.return_shipping_option, - } - } - - const swap = await swapService - .withTransaction(manager) - .create( - order, - swapDto.return_items, - swapDto.additional_items, - returnShipping, - { - idempotency_key: idempotencyKey.idempotency_key, - no_notification: true, - } - ) - - await swapService.withTransaction(manager).createCart(swap.id) - const returnOrder = await returnService - .withTransaction(manager) - .retrieveBySwap(swap.id) - - await returnService - .withTransaction(manager) - .fulfill(returnOrder.id) - - return { - recovery_point: "swap_created", - } - }) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "swap_created": { - await manager - .transaction("SERIALIZABLE", async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .workStage(idempotencyKey.idempotency_key, async (manager) => { - const swaps = await swapService - .withTransaction(transactionManager) - .list({ - idempotency_key: idempotencyKey.idempotency_key, - }) - - if (!swaps.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Swap not found" - ) - } - - const swap = await swapService - .withTransaction(transactionManager) - .retrieve(swaps[0].id, { - select: defaultStoreSwapFields, - relations: defaultStoreSwapRelations, - }) - - return { - response_code: 200, - response_body: { swap }, - } - }) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "finished": { - inProgress = false - break - } - - default: - await manager.transaction(async (transactionManager) => { - idempotencyKey = await idempotencyKeyService - .withTransaction(transactionManager) - .update(idempotencyKey.idempotency_key, { - recovery_point: "finished", - response_code: 500, - response_body: { message: "Unknown recovery point" }, - }) - }) - break - } - } - - if (err) { - throw err - } - - res.status(idempotencyKey.response_code).json(idempotencyKey.response_body) -} - -class Item { - @IsString() - @IsNotEmpty() - item_id: string - - @IsNumber() - @Min(1) - quantity: number - - @IsOptional() - @IsString() - reason_id?: string - - @IsOptional() - @IsString() - note?: string -} - -class AdditionalItem { - @IsString() - @IsNotEmpty() - variant_id: string - - @IsNumber() - @Min(1) - quantity: number -} - -/** - * @schema StorePostSwapsReq - * type: object - * description: "The details of the swap to create." - * required: - * - order_id - * - return_items - * - additional_items - * properties: - * order_id: - * type: string - * description: The ID of the Order to create the Swap for. - * return_items: - * description: "The items to include in the Return." - * type: array - * items: - * type: object - * required: - * - item_id - * - quantity - * properties: - * item_id: - * description: The ID of the order's line item to return. - * type: string - * quantity: - * description: The quantity to return. - * type: integer - * reason_id: - * description: The ID of the reason of this return. Return reasons can be retrieved from the List Return Reasons API Route. - * type: string - * note: - * description: The note to add to the item being swapped. - * type: string - * return_shipping_option: - * type: string - * description: The ID of the Shipping Option to create the Shipping Method from. - * additional_items: - * description: "The items to exchange the returned items with." - * type: array - * items: - * type: object - * required: - * - variant_id - * - quantity - * properties: - * variant_id: - * description: The ID of the Product Variant. - * type: string - * quantity: - * description: The quantity of the variant. - * type: integer - */ -export class StorePostSwapsReq { - @IsString() - @IsNotEmpty() - order_id: string - - @IsArray() - @ValidateNested({ each: true }) - @Type(() => Item) - return_items: Item[] - - @IsArray() - @ValidateNested({ each: true }) - @Type(() => AdditionalItem) - additional_items: AdditionalItem[] - - @IsOptional() - @IsString() - return_shipping_option?: string -} diff --git a/packages/medusa/src/api/routes/store/swaps/get-swap-by-cart.ts b/packages/medusa/src/api/routes/store/swaps/get-swap-by-cart.ts deleted file mode 100644 index 5e1e321e64..0000000000 --- a/packages/medusa/src/api/routes/store/swaps/get-swap-by-cart.ts +++ /dev/null @@ -1,83 +0,0 @@ -import SwapService from "../../../../services/swap" -import { defaultStoreSwapRelations } from "." - -/** - * @oas [get] /store/swaps/{cart_id} - * operationId: GetSwapsSwapCartId - * summary: Get by Cart ID - * description: "Retrieve a Swap's details by the ID of its cart." - * parameters: - * - (path) cart_id {string} The id of the Cart - * x-codegen: - * method: retrieveByCartId - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * medusa.swaps.retrieveByCartId(cartId) - * .then(({ swap }) => { - * console.log(swap.id); - * }) - * - lang: tsx - * label: Medusa React - * source: | - * import React from "react" - * import { useCartSwap } from "medusa-react" - * type Props = { - * cartId: string - * } - * - * const Swap = ({ cartId }: Props) => { - * const { - * swap, - * isLoading, - * } = useCartSwap(cartId) - * - * return ( - *
- * {isLoading && Loading...} - * {swap && {swap.id}} - * - *
- * ) - * } - * - * export default Swap - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/swaps/{cart_id}' - * tags: - * - Swaps - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreSwapsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { cart_id } = req.params - - const swapService: SwapService = req.scope.resolve("swapService") - - const swap = await swapService.retrieveByCartId( - cart_id, - defaultStoreSwapRelations - ) - - res.json({ swap }) -} diff --git a/packages/medusa/src/api/routes/store/swaps/index.ts b/packages/medusa/src/api/routes/store/swaps/index.ts deleted file mode 100644 index 0ede0c94fb..0000000000 --- a/packages/medusa/src/api/routes/store/swaps/index.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Router } from "express" - -import { Swap } from "./../../../../" -import middlewares from "../../../middlewares" -import { FindConfig } from "../../../../types/common" - -const route = Router() - -export default (app) => { - app.use("/swaps", route) - - route.get( - "/:cart_id", - middlewares.wrap(require("./get-swap-by-cart").default) - ) - route.post("/", middlewares.wrap(require("./create-swap").default)) - - return app -} - -export const defaultStoreSwapRelations = [ - "order", - "additional_items", - "additional_items.variant", - "return_order", - "return_order.shipping_method", - "return_order.shipping_method.shipping_option", - "fulfillments", - "payment", - "shipping_address", - "shipping_methods", - "shipping_methods.shipping_option", - "cart", -] -export const defaultStoreSwapFields: FindConfig["select"] = [ - "id", - "fulfillment_status", - "payment_status", - "order_id", - "difference_due", - "shipping_address_id", - "cart_id", - "confirmed_at", - "created_at", - "updated_at", - "deleted_at", - "metadata", - "idempotency_key", -] - -/** - * @schema StoreSwapsRes - * type: object - * description: "The swap's details." - * x-expanded-relations: - * field: swap - * relations: - * - additional_items - * - additional_items.variant - * - cart - * - fulfillments - * - order - * - payment - * - return_order - * - return_order.shipping_method - * - shipping_address - * - shipping_methods - * eager: - * - fulfillments.items - * required: - * - swap - * properties: - * swap: - * description: "Swap details." - * $ref: "#/components/schemas/Swap" - */ -export type StoreSwapsRes = { - swap: Swap -} - -export * from "./create-swap" -export * from "./get-swap-by-cart" diff --git a/packages/medusa/src/api/routes/store/variants/__tests__/get-variant.js b/packages/medusa/src/api/routes/store/variants/__tests__/get-variant.js deleted file mode 100644 index 79dfb059e1..0000000000 --- a/packages/medusa/src/api/routes/store/variants/__tests__/get-variant.js +++ /dev/null @@ -1,37 +0,0 @@ -import { request } from "../../../../../helpers/test-request" -import { ProductVariantServiceMock } from "../../../../../services/__mocks__/product-variant" - -describe("Get variant by id", () => { - describe("get variant by id successfull", () => { - let subject - beforeAll(async () => { - subject = await request("GET", `/store/variants/1`) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls get variant from variantSerice", () => { - expect(ProductVariantServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(ProductVariantServiceMock.retrieve).toHaveBeenCalledWith("1", { - relations: ["prices", "options", "product"], - }) - }) - - it("returns variant decorated", () => { - expect(subject.body.variant.id).toEqual("1") - }) - }) - - describe("get variant with prices", () => { - let subject - beforeAll(async () => { - subject = await request("GET", `/store/variants/variant_with_prices`) - }) - it("successfully retrieves variants with prices", async () => { - expect(subject.status).toEqual(200) - expect(subject.body.variant.prices[0].amount).toEqual(100) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/variants/__tests__/list-variants.js b/packages/medusa/src/api/routes/store/variants/__tests__/list-variants.js deleted file mode 100644 index c1c163764e..0000000000 --- a/packages/medusa/src/api/routes/store/variants/__tests__/list-variants.js +++ /dev/null @@ -1,20 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { request } from "../../../../../helpers/test-request" - -describe("List variants", () => { - describe("list variants successfull", () => { - let subject - - beforeAll(async () => { - subject = await request("GET", `/store/variants`) - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("returns variants", () => { - expect(subject.body.variants[0].id).toEqual(IdMap.getId("testVariant")) - }) - }) -}) diff --git a/packages/medusa/src/api/routes/store/variants/get-variant.ts b/packages/medusa/src/api/routes/store/variants/get-variant.ts deleted file mode 100644 index bdaa57ba78..0000000000 --- a/packages/medusa/src/api/routes/store/variants/get-variant.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { - CartService, - PricingService, - ProductVariantInventoryService, - ProductVariantService, - RegionService, -} from "../../../../services" -import { IsOptional, IsString } from "class-validator" - -import { PriceSelectionParams } from "../../../../types/price-selection" -import { validator } from "../../../../utils/validator" -import { promiseAll } from "@medusajs/utils" - -/** - * @oas [get] /store/variants/{id} - * operationId: GetVariantsVariant - * summary: Get a Product Variant - * description: | - * Retrieve a Product Variant's details. For accurate and correct pricing of the product variant based on the customer's context, it's highly recommended to pass fields such as - * `region_id`, `currency_code`, and `cart_id` when available. - * - * Passing `sales_channel_id` ensures retrieving only variants of products available in the current sales channel. - * You can alternatively use a publishable API key in the request header instead of passing a `sales_channel_id`. - * externalDocs: - * description: "How to pass product pricing parameters" - * url: "https://docs.medusajs.com/modules/products/storefront/show-products#product-pricing-parameters" - * parameters: - * - (path) id=* {string} The ID of the Product Variant. - * - (query) sales_channel_id {string} The ID of the sales channel the customer is viewing the product variant from. - * - (query) cart_id {string} The ID of the cart. This is useful for accurate pricing based on the cart's context. - * - (query) region_id {string} The ID of the region. This is useful for accurate pricing based on the selected region. - * - in: query - * name: currency_code - * style: form - * explode: false - * description: A 3 character ISO currency code. This is useful for accurate pricing based on the selected currency. - * schema: - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * x-codegen: - * method: retrieve - * queryParams: StoreGetVariantsVariantParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.product.variants.retrieve(productVariantId) - * .then(({ variant }) => { - * console.log(variant.id); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/variants/{id}' - * tags: - * - Product Variants - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreVariantsRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const { id } = req.params - - const validated = await validator(StoreGetVariantsVariantParams, req.query) - - const variantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - const pricingService: PricingService = req.scope.resolve("pricingService") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - const cartService: CartService = req.scope.resolve("cartService") - const regionService: RegionService = req.scope.resolve("regionService") - const featureFlagRouter = req.scope.resolve("featureFlagRouter") - - const customer_id = req.user?.customer_id - - const variant = await variantService.retrieve(id, req.retrieveConfig) - - let sales_channel_id = validated.sales_channel_id - if (req.publishableApiKeyScopes?.sales_channel_ids.length === 1) { - sales_channel_id = req.publishableApiKeyScopes.sales_channel_ids[0] - } - - let regionId = validated.region_id - let currencyCode = validated.currency_code - if (validated.cart_id) { - const cart = await cartService.retrieve(validated.cart_id, { - select: ["id", "region_id"], - }) - const region = await regionService.retrieve(cart.region_id, { - select: ["id", "currency_code"], - }) - regionId = region.id - currencyCode = region.currency_code - } - - const decoratePromises: Promise[] = [] - - decoratePromises.push( - (await pricingService.setVariantPrices([variant], { - cart_id: validated.cart_id, - customer_id: customer_id, - region_id: regionId, - currency_code: currencyCode, - include_discount_prices: true, - })) as any - ) - - decoratePromises.push( - (await productVariantInventoryService.setVariantAvailability( - [variant], - sales_channel_id - )) as any - ) - - await promiseAll(decoratePromises) - - res.json({ variant }) -} - -export class StoreGetVariantsVariantParams extends PriceSelectionParams { - @IsString() - @IsOptional() - sales_channel_id?: string -} diff --git a/packages/medusa/src/api/routes/store/variants/index.ts b/packages/medusa/src/api/routes/store/variants/index.ts deleted file mode 100644 index 21dbfeaf11..0000000000 --- a/packages/medusa/src/api/routes/store/variants/index.ts +++ /dev/null @@ -1,97 +0,0 @@ -import middlewares, { transformStoreQuery } from "../../../middlewares" - -import { Router } from "express" -import { PricedVariant } from "../../../../types/pricing" -import { extendRequestParams } from "../../../middlewares/publishable-api-key/extend-request-params" -import { validateSalesChannelParam } from "../../../middlewares/publishable-api-key/validate-sales-channel-param" -import { validateProductVariantSalesChannelAssociation } from "../../../middlewares/publishable-api-key/validate-variant-sales-channel-association" -import { withDefaultSalesChannel } from "../../../middlewares/with-default-sales-channel" -import { StoreGetVariantsVariantParams } from "./get-variant" -import { StoreGetVariantsParams } from "./list-variants" - -const route = Router() - -export default (app) => { - app.use("/variants", extendRequestParams, validateSalesChannelParam, route) - - route.use("/:id", validateProductVariantSalesChannelAssociation) - - route.get( - "/", - withDefaultSalesChannel(), - transformStoreQuery(StoreGetVariantsParams, { - defaultRelations: defaultStoreVariantRelations, - allowedRelations: allowedStoreVariantRelations, - isList: true, - }), - middlewares.wrap(require("./list-variants").default) - ) - route.get( - "/:id", - withDefaultSalesChannel(), - transformStoreQuery(StoreGetVariantsVariantParams, { - defaultRelations: defaultStoreVariantRelations, - allowedRelations: allowedStoreVariantRelations, - }), - middlewares.wrap(require("./get-variant").default) - ) - - return app -} - -export const defaultStoreVariantRelations = ["prices", "options", "product"] - -export const allowedStoreVariantRelations = [ - ...defaultStoreVariantRelations, - "inventory_items", -] -/** - * @schema StoreVariantsRes - * type: object - * description: "The product variant's details." - * x-expanded-relations: - * field: variant - * relations: - * - prices - * - options - * - product - * totals: - * - purchasable - * required: - * - variant - * properties: - * variant: - * description: "Product variant description." - * $ref: "#/components/schemas/PricedVariant" - */ -export type StoreVariantsRes = { - variant: PricedVariant -} - -/** - * @schema StoreVariantsListRes - * type: object - * description: "The list of product variants." - * x-expanded-relations: - * field: variants - * relations: - * - prices - * - options - * - product - * totals: - * - purchasable - * required: - * - variants - * properties: - * variants: - * type: array - * description: "An array of product variant descriptions." - * items: - * $ref: "#/components/schemas/PricedVariant" - */ -export type StoreVariantsListRes = { - variants: PricedVariant[] -} - -export * from "./get-variant" -export * from "./list-variants" diff --git a/packages/medusa/src/api/routes/store/variants/list-variants.ts b/packages/medusa/src/api/routes/store/variants/list-variants.ts deleted file mode 100644 index ce867f96af..0000000000 --- a/packages/medusa/src/api/routes/store/variants/list-variants.ts +++ /dev/null @@ -1,264 +0,0 @@ -import { - CartService, - PricingService, - ProductVariantInventoryService, - ProductVariantService, - RegionService, -} from "../../../../services" -import { IsInt, IsOptional, IsString } from "class-validator" - -import { IsType } from "../../../../utils/validators/is-type" -import { NumericalComparisonOperator } from "../../../../types/common" -import { PriceSelectionParams } from "../../../../types/price-selection" -import { Type } from "class-transformer" -import { validator } from "../../../../utils/validator" -import { promiseAll } from "@medusajs/utils" - -/** - * @oas [get] /store/variants - * operationId: GetVariants - * summary: Get Product Variants - * description: | - * Retrieves a list of product variants. The product variants can be filtered by fields such as `id` or `title`. The product variants can also be paginated. - * - * For accurate and correct pricing of the product variants based on the customer's context, it's highly recommended to pass fields such as - * `region_id`, `currency_code`, and `cart_id` when available. - * - * Passing `sales_channel_id` ensures retrieving only variants of products available in the specified sales channel. - * You can alternatively use a publishable API key in the request header instead of passing a `sales_channel_id`. - * externalDocs: - * description: "How to pass product pricing parameters" - * url: "https://docs.medusajs.com/modules/products/storefront/show-products#product-pricing-parameters" - * parameters: - * - (query) ids {string} Filter by a comma-separated list of IDs. If supplied, it overrides the `id` parameter. - * - in: query - * name: id - * style: form - * explode: false - * description: Filter by one or more IDs. If `ids` is supplied, it's overrides the value of this parameter. - * schema: - * oneOf: - * - type: string - * description: Filter by an ID. - * - type: array - * description: Filter by IDs. - * items: - * type: string - * - (query) sales_channel_id {string} "Filter by sales channel IDs. When provided, only products available in the selected sales channels are retrieved. Alternatively, you can pass a - * publishable API key in the request header and this will have the same effect." - * - (query) expand {string} Comma-separated relations that should be expanded in the returned product variants. - * - (query) fields {string} Comma-separated fields that should be included in the returned product variants. - * - (query) offset=0 {number} The number of products to skip when retrieving the product variants. - * - (query) limit=100 {number} Limit the number of product variants returned. - * - (query) cart_id {string} The ID of the cart. This is useful for accurate pricing based on the cart's context. - * - (query) region_id {string} The ID of the region. This is useful for accurate pricing based on the selected region. - * - in: query - * name: currency_code - * style: form - * explode: false - * description: A 3 character ISO currency code. This is useful for accurate pricing based on the selected currency. - * schema: - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * - in: query - * name: title - * style: form - * explode: false - * description: Filter by title - * schema: - * oneOf: - * - type: string - * description: a single title to filter by - * - type: array - * description: multiple titles to filter by - * items: - * type: string - * - in: query - * name: inventory_quantity - * description: Filter by available inventory quantity - * schema: - * oneOf: - * - type: number - * description: A specific number to filter by. - * - type: object - * description: Filter using less and greater than comparisons. - * properties: - * lt: - * type: number - * description: Filter by inventory quantity less than this number - * gt: - * type: number - * description: Filter by inventory quantity greater than this number - * lte: - * type: number - * description: Filter by inventory quantity less than or equal to this number - * gte: - * type: number - * description: Filter by inventory quantity greater than or equal to this number - * x-codegen: - * method: list - * queryParams: StoreGetVariantsParams - * x-codeSamples: - * - lang: JavaScript - * label: JS Client - * source: | - * import Medusa from "@medusajs/medusa-js" - * const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 }) - * // must be previously logged in or use api token - * medusa.product.variants.list() - * .then(({ variants }) => { - * console.log(variants.length); - * }) - * - lang: Shell - * label: cURL - * source: | - * curl '{backend_url}/store/variants' - * tags: - * - Product Variants - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * $ref: "#/components/schemas/StoreVariantsListRes" - * "400": - * $ref: "#/components/responses/400_error" - * "404": - * $ref: "#/components/responses/not_found_error" - * "409": - * $ref: "#/components/responses/invalid_state_error" - * "422": - * $ref: "#/components/responses/invalid_request_error" - * "500": - * $ref: "#/components/responses/500_error" - */ -export default async (req, res) => { - const validated = await validator(StoreGetVariantsParams, req.query) - - const customer_id = req.user?.customer_id - - let { - cart_id, - region_id, - currency_code, - sales_channel_id, - ids, - ...filterableFields - } = req.filterableFields - - if (validated.ids) { - filterableFields["id"] = validated.ids.split(",") - } - - if (req.publishableApiKeyScopes?.sales_channel_ids.length === 1) { - sales_channel_id = req.publishableApiKeyScopes.sales_channel_ids[0] - } - - const pricingService: PricingService = req.scope.resolve("pricingService") - const variantService: ProductVariantService = req.scope.resolve( - "productVariantService" - ) - const cartService: CartService = req.scope.resolve("cartService") - const productVariantInventoryService: ProductVariantInventoryService = - req.scope.resolve("productVariantInventoryService") - const regionService: RegionService = req.scope.resolve("regionService") - const featureFlagRouter = req.scope.resolve("featureFlagRouter") - - const variants = await variantService.list(filterableFields, req.listConfig) - - let regionId = validated.region_id - let currencyCode = validated.currency_code - if (validated.cart_id) { - const cart = await cartService.retrieve(validated.cart_id, { - select: ["id", "region_id"], - }) - const region = await regionService.retrieve(cart.region_id, { - select: ["id", "currency_code"], - }) - regionId = region.id - currencyCode = region.currency_code - } - - const decoratePromises: Promise[] = [] - - decoratePromises.push( - (await pricingService.setVariantPrices(variants, { - cart_id: validated.cart_id, - region_id: regionId, - currency_code: currencyCode, - customer_id: customer_id, - include_discount_prices: true, - })) as any - ) - - decoratePromises.push( - (await productVariantInventoryService.setVariantAvailability( - variants, - sales_channel_id - )) as any - ) - await promiseAll(decoratePromises) - - res.json({ variants }) -} - -/** - * Parameters used to filter and configure the pagination of the retrieved product variants. - */ -export class StoreGetVariantsParams extends PriceSelectionParams { - /** - * {@inheritDoc FindPaginationParams.limit} - * @defaultValue 100 - */ - @IsOptional() - @IsInt() - @Type(() => Number) - limit?: number = 100 - - /** - * {@inheritDoc FindPaginationParams.offset} - * @defaultValue 0 - */ - @IsOptional() - @IsInt() - @Type(() => Number) - offset?: number = 0 - - /** - * ID to filter the product variants by. - */ - @IsOptional() - @IsString() - ids?: string - - /** - * Filter product variants by the ID of their associated sales channel. - */ - @IsOptional() - @IsString() - sales_channel_id?: string - - /** - * IDs to filter product variants by. - */ - @IsOptional() - @IsType([String, [String]]) - id?: string | string[] - - /** - * Titles to filter product variants by. - */ - @IsOptional() - @IsType([String, [String]]) - title?: string | string[] - - /** - * Number filters to apply on the product variants' `inventory_quantity` field. - */ - @IsOptional() - @IsType([Number, NumericalComparisonOperator]) - inventory_quantity?: number | NumericalComparisonOperator -} diff --git a/packages/medusa/src/commands/seed.ts b/packages/medusa/src/commands/seed.ts deleted file mode 100644 index 08dccf6dea..0000000000 --- a/packages/medusa/src/commands/seed.ts +++ /dev/null @@ -1,297 +0,0 @@ -import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { IPricingModuleService } from "@medusajs/types" -import { MedusaV2Flag } from "@medusajs/utils" -import express from "express" -import fs from "fs" -import { sync as existsSync } from "fs-exists-cached" -import { getConfigFile } from "medusa-core-utils" -import { track } from "medusa-telemetry" -import path from "path" -import { DataSource, DataSourceOptions } from "typeorm" -import loaders from "../loaders" -import { handleConfigError } from "../loaders/config" -import featureFlagLoader from "../loaders/feature-flags" -import Logger from "../loaders/logger" -import { SalesChannel } from "../models" -import { - ProductCategoryService, - ProductCollectionService, - ProductService, - ProductVariantService, - RegionService, - SalesChannelService, - ShippingOptionService, - ShippingProfileService, - StoreService, - UserService, -} from "../services" -import PublishableApiKeyService from "../services/publishable-api-key" -import { ConfigModule } from "../types/global" -import { CreateProductInput } from "../types/product" -import { CreateProductCategoryInput } from "../types/product-category" -import getMigrations, { getModuleSharedResources } from "./utils/get-migrations" - -type SeedOptions = { - directory: string - migrate: boolean - seedFile: string -} - -const seed = async function ({ directory, migrate, seedFile }: SeedOptions) { - track("CLI_SEED") - let resolvedPath = seedFile - - // If we are already given an absolute path we can skip resolution step - if (!existsSync(resolvedPath)) { - resolvedPath = path.resolve(path.join(directory, seedFile)) - - if (!existsSync(resolvedPath)) { - console.error(`Could not find a seed file at: ${seedFile}`) - console.error(`Resolved path: ${resolvedPath}`) - - process.exit(1) - } - } - - const { configModule, error }: { configModule: ConfigModule; error?: any } = - getConfigFile(directory, `medusa-config`) - - if (error) { - handleConfigError(error) - } - - const featureFlagRouter = featureFlagLoader(configModule) - - if (migrate) { - const { coreMigrations } = getMigrations(directory, featureFlagRouter) - - const { migrations: moduleMigrations } = getModuleSharedResources( - configModule, - featureFlagRouter - ) - - const connectionOptions = { - type: "postgres", - database: configModule.projectConfig.database_database, - schema: configModule.projectConfig.database_schema, - url: configModule.projectConfig.database_url, - extra: configModule.projectConfig.database_extra || {}, - migrations: coreMigrations.concat(moduleMigrations), - logging: true, - } as DataSourceOptions - - const connection = new DataSource(connectionOptions) - - await connection.initialize() - await connection.runMigrations() - await connection.destroy() - - Logger.info("Migrations completed.") - } - - const app = express() - const { container } = await loaders({ - directory, - expressApp: app, - isTest: false, - }) - - const manager = container.resolve("manager") - - const storeService: StoreService = container.resolve("storeService") - const userService: UserService = container.resolve("userService") - const regionService: RegionService = container.resolve("regionService") - const productCollectionService: ProductCollectionService = container.resolve( - "productCollectionService" - ) - const productService: ProductService = container.resolve("productService") - const productCategoryService: ProductCategoryService = container.resolve( - "productCategoryService" - ) - const publishableApiKeyService: PublishableApiKeyService = container.resolve( - "publishableApiKeyService" - ) - const salesChannelService: SalesChannelService = container.resolve( - "salesChannelService" - ) - - /* eslint-disable */ - const productVariantService: ProductVariantService = container.resolve( - "productVariantService" - ) - const shippingOptionService: ShippingOptionService = container.resolve( - "shippingOptionService" - ) - const shippingProfileService: ShippingProfileService = container.resolve( - "shippingProfileService" - ) - const pricingModuleService: IPricingModuleService = container.resolve( - ModuleRegistrationName.PRICING - ) - /* eslint-enable */ - - await manager.transaction(async (tx) => { - const { - store: seededStore, - regions, - product_collections = [], - products, - categories = [], - shipping_options, - users, - rule_types = [], - publishable_api_keys = [], - } = JSON.parse(fs.readFileSync(resolvedPath, `utf-8`)) - - const gcProfile = await shippingProfileService.retrieveGiftCardDefault() - const defaultProfile = await shippingProfileService.retrieveDefault() - - if (seededStore) { - await storeService.withTransaction(tx).update(seededStore) - } - - const store = await storeService.retrieve() - - for (const u of users) { - const pass = u.password - if (pass) { - delete u.password - } - await userService.withTransaction(tx).create(u, pass) - } - - const regionIds = {} - for (const r of regions) { - let dummyId - if (!r.id || !r.id.startsWith("reg_")) { - dummyId = r.id - delete r.id - } - - const reg = await regionService.withTransaction(tx).create(r) - - if (dummyId) { - regionIds[dummyId] = reg.id - } - } - - for (const so of shipping_options) { - if (regionIds[so.region_id]) { - so.region_id = regionIds[so.region_id] - } - - so.profile_id = defaultProfile!.id - if (so.is_giftcard) { - so.profile_id = gcProfile!.id - delete so.is_giftcard - } - - await shippingOptionService.withTransaction(tx).create(so) - } - - const createProductCategory = async ( - parameters, - parentCategoryId: string | null = null - ) => { - // default to the categories being visible and public - parameters.is_active = parameters.is_active || true - parameters.is_internal = parameters.is_internal || false - parameters.parent_category_id = parentCategoryId - - const categoryChildren = parameters.category_children || [] - delete parameters.category_children - - const category = await productCategoryService - .withTransaction(tx) - .create(parameters as CreateProductCategoryInput) - - if (categoryChildren.length) { - for (const categoryChild of categoryChildren) { - await createProductCategory(categoryChild, category.id) - } - } - } - - for (const c of categories) { - await createProductCategory(c) - } - - for (const pc of product_collections) { - await productCollectionService.withTransaction(tx).create(pc) - } - - for (const p of products) { - const variants = p.variants - delete p.variants - - // default to the products being visible - p.status = p.status || "published" - - p.sales_channels = [{ id: store.default_sales_channel_id }] - - p.profile_id = defaultProfile!.id - if (p.is_giftcard) { - p.profile_id = gcProfile!.id - } - - const newProd = await productService - .withTransaction(tx) - .create(p as CreateProductInput) - - if (variants && variants.length) { - const optionIds = p.options.map( - (o) => newProd.options.find((newO) => newO.title === o.title)?.id - ) - - for (const v of variants) { - const variant = { - ...v, - options: v.options.map((o, index) => ({ - ...o, - option_id: optionIds[index], - })), - } - - await productVariantService - .withTransaction(tx) - .create(newProd.id, variant) - } - } - } - - let defaultSalesChannel: SalesChannel | null = null - - try { - defaultSalesChannel = await salesChannelService - .withTransaction(tx) - .retrieveDefault() - } catch (e) { - defaultSalesChannel = null - } - - for (const pak of publishable_api_keys) { - const publishableApiKey = await publishableApiKeyService - .withTransaction(tx) - .create(pak, { - loggedInUserId: "", - }) - - // attach to default sales channel if exists - if (defaultSalesChannel) { - await publishableApiKeyService.addSalesChannels(publishableApiKey.id, [ - defaultSalesChannel.id, - ]) - } - } - - if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) { - for (const ruleType of rule_types) { - await pricingModuleService.createRuleTypes(ruleType) - } - } - }) - - track("CLI_SEED_COMPLETED") -} - -export default seed diff --git a/packages/medusa/src/controllers/customers/index.ts b/packages/medusa/src/controllers/customers/index.ts deleted file mode 100644 index 7b4ac3e2ce..0000000000 --- a/packages/medusa/src/controllers/customers/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import listAndCount from "./list-customers" -export default { listAndCount } diff --git a/packages/medusa/src/controllers/customers/list-customers.ts b/packages/medusa/src/controllers/customers/list-customers.ts deleted file mode 100644 index 2a68d2e245..0000000000 --- a/packages/medusa/src/controllers/customers/list-customers.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { omit, pickBy } from "lodash" -import { isDefined } from "medusa-core-utils" -import { AdminCustomersListRes } from "../../api" -import { AdminGetCustomersParams } from "../../api/routes/admin/customers" -import { Customer } from "../../models/customer" -import { CustomerService } from "../../services" -import { FindConfig } from "../../types/common" -import { validator } from "../../utils/validator" - -const listAndCount = async ( - scope, - query, - body -): Promise => { - const validatedQueryParams = await validator(AdminGetCustomersParams, query) - - const customerService: CustomerService = scope.resolve("customerService") - - let expandFields: string[] = [] - if (validatedQueryParams.expand) { - expandFields = validatedQueryParams.expand.split(",") - } - - let orderBy: { [key: string]: "ASC" | "DESC" } | undefined = undefined - if (validatedQueryParams.order) { - const order = validatedQueryParams.order - const direction = order.startsWith("-") ? "DESC" : "ASC" - const field = order.replace(/^-/, "") - orderBy = { - [field]: direction, - } - } - - const listConfig: FindConfig = { - relations: expandFields, - skip: validatedQueryParams.offset, - take: validatedQueryParams.limit, - order: orderBy, - } - - const filterableFields = omit(validatedQueryParams, [ - "limit", - "offset", - "expand", - "fields", - "order", - ]) - - const [customers, count] = await customerService.listAndCount( - pickBy(filterableFields, (val) => isDefined(val)), - listConfig - ) - - return { - customers, - count, - offset: validatedQueryParams.offset, - limit: validatedQueryParams.limit, - } -} - -export default listAndCount diff --git a/packages/medusa/src/index.js b/packages/medusa/src/index.js index e582f69c7f..1b3ccf1eed 100644 --- a/packages/medusa/src/index.js +++ b/packages/medusa/src/index.js @@ -1,5 +1,3 @@ -export * from "./api" -export * from "./api/middlewares" export * from "./interfaces" export * from "./models" export * from "./modules-config" @@ -8,7 +6,6 @@ export * from "./types/batch-job" export * from "./types/common" export * from "./types/global" export * from "./types/middlewares" -export * from "./types/price-list" export * from "./types/routing" export * from "./types/scheduled-jobs" export * from "./types/subscribers" diff --git a/packages/medusa/src/interfaces/__tests__/event-bus-service.spec.ts b/packages/medusa/src/interfaces/__tests__/event-bus-service.spec.ts deleted file mode 100644 index cf4383ca12..0000000000 --- a/packages/medusa/src/interfaces/__tests__/event-bus-service.spec.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { EventBusTypes } from "@medusajs/types" -import { EventBusUtils } from "@medusajs/utils" -import { EntityManager } from "typeorm" - -class EventBus extends EventBusUtils.AbstractEventBusModuleService { - protected manager_!: EntityManager - - constructor(protected readonly container) { - super() - this.container = container - } - - async emit( - eventName: string, - data: T, - options: Record - ): Promise - async emit(data: EventBusTypes.EmitData[]): Promise - async emit(data: EventBusTypes.Message[]): Promise - - async emit< - T, - TInput extends - | string - | EventBusTypes.EmitData[] - | EventBusTypes.Message[] = string - >( - eventOrData: TInput, - data?: T, - options: Record = {} - ): Promise { - const isBulkEmit = Array.isArray(eventOrData) - const event = isBulkEmit ? eventOrData[0].eventName : eventOrData - - console.log( - `[${event}] Local Event Bus installed. Emitting events has no effect.` - ) - } -} - -describe("AbstractEventBusService", () => { - let eventBus - - describe("subscribe", () => { - beforeAll(() => { - jest.clearAllMocks() - }) - - beforeEach(() => { - eventBus = new EventBus({}) - }) - - it("successfully adds subscriber", () => { - eventBus.subscribe("eventName", () => "test", { - subscriberId: "my-subscriber", - }) - - expect(eventBus.eventToSubscribersMap_.get("eventName").length).toEqual(1) - }) - - it("successfully adds multiple subscribers with explicit ids", () => { - eventBus.subscribe("eventName", () => "test", { - subscriberId: "my-subscriber-1", - }) - - eventBus.subscribe("eventName", () => "test", { - subscriberId: "my-subscriber-2", - }) - - expect(eventBus.eventToSubscribersMap_.get("eventName").length).toEqual(2) - }) - - it("successfully adds multiple subscribers with generates ids", () => { - eventBus.subscribe("eventName", () => "test") - - eventBus.subscribe("eventName", () => "test") - - expect(eventBus.eventToSubscribersMap_.get("eventName").length).toEqual(2) - }) - - it("throws when subscriber already exists", async () => { - expect.assertions(1) - - eventBus.subscribe("eventName", () => "test", { - subscriberId: "my-subscriber", - }) - - try { - eventBus.subscribe("eventName", () => "new", { - subscriberId: "my-subscriber", - }) - } catch (error) { - expect(error.message).toBe( - "Subscriber with id my-subscriber already exists" - ) - } - }) - - it("throws when subscriber is not a function", async () => { - expect.assertions(1) - - try { - eventBus.subscribe("eventName", "definitely-not-a-function") - } catch (error) { - expect(error.message).toBe("Subscriber must be a function") - } - }) - }) - - describe("unsubscribe", () => { - beforeAll(() => { - jest.clearAllMocks() - }) - - beforeEach(() => { - eventBus = new EventBus({}) - - eventBus.subscribe("eventName", () => "test", { subscriberId: "test" }) - }) - - it("successfully removes subscriber", () => { - eventBus.unsubscribe("eventName", () => "test", { subscriberId: "test" }) - - expect(eventBus.eventToSubscribersMap_.get("eventName").length).toEqual(0) - }) - - it("does nothing if subscriber does not exist", () => { - eventBus.unsubscribe("eventName", () => "non-existing") - - expect(eventBus.eventToSubscribersMap_.get("eventName").length).toEqual(1) - }) - - it("does nothing if event has no subcribers", () => { - eventBus.unsubscribe("non-existing", () => "test") - - expect(eventBus.eventToSubscribersMap_.get("eventName").length).toEqual(1) - }) - }) -}) diff --git a/packages/medusa/src/interfaces/abstract-parser.ts b/packages/medusa/src/interfaces/abstract-parser.ts deleted file mode 100644 index 6368c29195..0000000000 --- a/packages/medusa/src/interfaces/abstract-parser.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Generic parsing interface. All different parsing implementations (csv, json, etc.) should implement this interface - */ -export interface IParser { - /** - * - * @param readableStream readable stream to parse - * @param options options used for parsing by underlying parser implementation - */ - parse( - readableStream: NodeJS.ReadableStream, - options?: TParseOptions - ): Promise -} - -/** - * Abstract class implementation of the IParser interface. All different parsing implementations should extend this class - */ -export abstract class AbstractParser< - TSchema, - TParserResult, - TParseOptions, - TOutputResult -> implements IParser -{ - protected readonly $$schema: TSchema - - protected constructor(schema: TSchema) { - this.$$schema = schema - } - - public abstract parse( - readableStream: NodeJS.ReadableStream, - options?: TParseOptions - ): Promise - - /** - * - * @param data data to be built after parsing. Includes validation according to schema, transformation of values, etc. - */ - public abstract buildData(data: TParserResult[]): Promise -} diff --git a/packages/medusa/src/interfaces/batch-job-strategy.ts b/packages/medusa/src/interfaces/batch-job-strategy.ts deleted file mode 100644 index 6767268edd..0000000000 --- a/packages/medusa/src/interfaces/batch-job-strategy.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { BatchJob } from "../models" -import { BatchJobService } from "../services" -import { ProductExportBatchJob } from "../strategies/batch-jobs/product/types" -import { BatchJobResultError, CreateBatchJobInput } from "../types/batch-job" -import { TransactionBaseService } from "./transaction-base-service" - -export interface IBatchJobStrategy extends TransactionBaseService { - /** - * Method for preparing a batch job for processing - */ - prepareBatchJobForProcessing( - batchJobEntity: CreateBatchJobInput, - req: Express.Request - ): Promise - - /** - * Method for pre-processing a batch job - */ - preProcessBatchJob(batchJobId: string): Promise - - /** - * Method does the actual processing of the job. Should report back on the progress of the operation. - */ - processJob(batchJobId: string): Promise - - /** - * Builds and returns a template file that can be downloaded and filled in - */ - buildTemplate(): Promise -} - -export abstract class AbstractBatchJobStrategy - extends TransactionBaseService - implements IBatchJobStrategy -{ - static _isBatchJobStrategy = true - static identifier: string - static batchType: string - - protected abstract batchJobService_: BatchJobService - - static isBatchJobStrategy(object): object is IBatchJobStrategy { - return object?.constructor?._isBatchJobStrategy - } - - async prepareBatchJobForProcessing( - batchJob: CreateBatchJobInput, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - req: Express.Request - ): Promise { - return batchJob - } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - public async preProcessBatchJob(batchJobId: string): Promise { - return - } - - public abstract processJob(batchJobId: string): Promise - - public abstract buildTemplate(): Promise - - protected async shouldRetryOnProcessingError( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - batchJob: BatchJob, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - err: unknown - ): Promise { - return false - } - - protected async handleProcessingError( - batchJobId: string, - err: unknown, - result: T - ): Promise { - // TODO just throw to be handled by the subscriber - return await this.atomicPhase_(async (transactionManager) => { - const batchJob = (await this.batchJobService_ - .withTransaction(transactionManager) - .retrieve(batchJobId)) as ProductExportBatchJob - - const shouldRetry = await this.shouldRetryOnProcessingError(batchJob, err) - - const errMessage = - (err as { message: string }).message ?? - `Something went wrong with the batchJob ${batchJob.id}` - const errCode = (err as { code: string | number }).code ?? "unknown" - const resultError = { message: errMessage, code: errCode, err } - - if (shouldRetry) { - const existingErrors = - batchJob?.result?.errors ?? ([] as BatchJobResultError[]) - const retryCount = batchJob.context.retry_count ?? 0 - - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJobId, { - context: { - retry_count: retryCount + 1, - }, - result: { - ...result, - errors: [...existingErrors, resultError.message], - }, - }) - } else { - await this.batchJobService_ - .withTransaction(transactionManager) - .setFailed(batchJob, resultError) - } - }) - } -} diff --git a/packages/medusa/src/interfaces/cart-completion-strategy.ts b/packages/medusa/src/interfaces/cart-completion-strategy.ts deleted file mode 100644 index 5381414d81..0000000000 --- a/packages/medusa/src/interfaces/cart-completion-strategy.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { TransactionBaseService } from "./transaction-base-service" -import { IdempotencyKey } from "../models" -import { RequestContext } from "../types/request" - -export type CartCompletionResponse = { - /** The response code for the completion request */ - response_code: number - - /** The response body for the completion request */ - response_body: Record -} - -export interface ICartCompletionStrategy { - /** - * Takes a cart id and completes the cart. This for example takes place when - * creating an order or confirming a swap. - * @param cartId - the id of the Cart to complete. - * @param idempotencyKey - the idempotency key for the request - * @param context - the request context for the completion request - * @return the response for the completion request - */ - complete( - cartId: string, - idempotencyKey: IdempotencyKey, - context: RequestContext - ): Promise -} - -export abstract class AbstractCartCompletionStrategy - extends TransactionBaseService - implements ICartCompletionStrategy -{ - static _isCartCompletionStrategy = true - - static isCartCompletionStrategy(object): object is ICartCompletionStrategy { - return object?.constructor?._isCartCompletionStrategy - } - - abstract complete( - cartId: string, - idempotencyKey: IdempotencyKey, - context: RequestContext - ): Promise -} diff --git a/packages/medusa/src/interfaces/csv-parser.ts b/packages/medusa/src/interfaces/csv-parser.ts deleted file mode 100644 index 1bc1864fb6..0000000000 --- a/packages/medusa/src/interfaces/csv-parser.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { AwilixContainer } from "awilix" - -/** - * Generic validation interface used to run validation logic on every line or record. - * All different validation objects should implement this interface - */ -export interface ICsvValidator { - /** - * - * @param value value of column or property - * @param context includes contextual information such as line number, line, etc. - */ - validate: ( - value: TBuiltLine, - context: CsvParserContext - ) => Promise -} - -export type CsvParserContext = LineContext & { - column: string -} - -export type LineContext = { - lineNumber: number - line: TLine -} - -/** - * Abstract class implementation of the IValidator interface. - * All validation objects part of the schema should extend this class. - */ -export abstract class AbstractCsvValidator - implements ICsvValidator -{ - constructor(protected readonly container: AwilixContainer) {} - - abstract validate( - builtLine: TBuiltLine, - context: CsvParserContext - ): Promise -} - -export type CsvSchemaColumn< - TCsvLine, - TBuiltLine, - NameAsOptional = false -> = (NameAsOptional extends false - ? { - name: string - } - : { - name?: string - }) & { - required?: boolean - validator?: AbstractCsvValidator -} & ( - | { - mapTo?: string - transform?: ColumnTransformer - } - | { - match?: RegExp - reducer?: ColumnReducer - transform?: ColumnTransformer - } - ) - -export type ColumnTransformer = ( - value: string, - context: CsvParserContext -) => unknown - -export type ColumnReducer = ( - builtLine: TBuiltLine, - key: string, - value: string, - context: CsvParserContext -) => TBuiltLine - -export type CsvSchema = { - columns: CsvSchemaColumn[] -} diff --git a/packages/medusa/src/interfaces/file-service.ts b/packages/medusa/src/interfaces/file-service.ts deleted file mode 100644 index fa4543a7c5..0000000000 --- a/packages/medusa/src/interfaces/file-service.ts +++ /dev/null @@ -1,364 +0,0 @@ -import { TransactionBaseService } from "./transaction-base-service" -import { - DeleteFileType, - FileServiceGetUploadStreamResult, - FileServiceUploadResult, - GetUploadedFileType, - MedusaContainer, - UploadStreamDescriptorType, -} from "@medusajs/types" - -/** - * ## Overview - * - * A file service class is defined in a TypeScript or JavaScript file that’s created in the `src/services` directory. - * The class must extend the `AbstractFileService` class imported from the `@medusajs/medusa` package. - * - * Based on services’ naming conventions, the file’s name should be the slug version of the file service’s name - * without `service`, and the class’s name should be the pascal case of the file service’s name following by `Service`. - * - * For example, create the file `src/services/local-file.ts` with the following content: - * - * ```ts title="src/services/local-file.ts" - * import { AbstractFileService } from "@medusajs/medusa" - * import { - * DeleteFileType, - * FileServiceGetUploadStreamResult, - * FileServiceUploadResult, - * GetUploadedFileType, - * UploadStreamDescriptorType, - * } from "@medusajs/types" - * - * class LocalFileService extends AbstractFileService { - * async upload( - * fileData: Express.Multer.File - * ): Promise { - * throw new Error("Method not implemented.") - * } - * async uploadProtected( - * fileData: Express.Multer.File - * ): Promise { - * throw new Error("Method not implemented.") - * } - * async delete(fileData: DeleteFileType): Promise { - * throw new Error("Method not implemented.") - * } - * async getUploadStreamDescriptor( - * fileData: UploadStreamDescriptorType - * ): Promise { - * throw new Error("Method not implemented.") - * } - * async getDownloadStream( - * fileData: GetUploadedFileType - * ): Promise { - * throw new Error("Method not implemented.") - * } - * async getPresignedDownloadUrl( - * fileData: GetUploadedFileType - * ): Promise { - * throw new Error("Method not implemented.") - * } - * } - * - * export default LocalFileService - * ``` - * - * :::note[Multer Typing] - * - * The examples implement a file service supporting local uploads. - * - * If you’re using TypeScript and you're following along with the implementation, - * you should install the Multer types package in the root of your Medusa backend to resolve errors within your file service types: - * - * ```bash npm2yarn - * npm install @types/multer - * ``` - * - * ::: - * - * --- - */ -export interface IFileService extends TransactionBaseService { - /** - * This method is used to upload a file to the Medusa backend. - * - * @param {Express.Multer.File} file - A [multer file object](http://expressjs.com/en/resources/middleware/multer.html#file-information). - * The file is uploaded to a temporary directory by default. Among the file’s details, you can access the file’s path in the `path` property of the file object. - * @returns {Promise} The details of the upload's result. - * - * @example - * ```ts - * class LocalFileService extends AbstractFileService { - * // ... - * async upload( - * fileData: Express.Multer.File - * ): Promise { - * const filePath = - * `${this.publicPath}/${fileData.originalname}` - * fs.copyFileSync(fileData.path, filePath) - * return { - * url: `${this.serverUrl}/${filePath}`, - * key: filePath, - * } - * } - * // ... - * } - * ``` - * - * :::tip - * - * This example does not account for duplicate names to maintain simplicity in this guide. So, an uploaded file can replace another existing file that has the same name. - * - * ::: - */ - upload(file: Express.Multer.File): Promise - - /** - * This method is used to upload a file to the Medusa backend, but to a protected storage. Typically, this would be used to store files that - * shouldn’t be accessible by using the file’s URL or should only be accessible by authenticated users. For example, exported or imported - * CSV files. - * - * @param {Express.Multer.File} file - A [multer file object](http://expressjs.com/en/resources/middleware/multer.html#file-information). - * The file is uploaded to a temporary directory by default. Among the file’s details, you can access the file’s path in the `path` property of the file object. - * @returns {Promise} The details of the upload's result. - * - * @example - * ```ts - * class LocalFileService extends AbstractFileService { - * // ... - * async uploadProtected( - * fileData: Express.Multer.File - * ): Promise { - * const filePath = - * `${this.protectedPath}/${fileData.originalname}` - * fs.copyFileSync(fileData.path, filePath) - * return { - * url: `${this.serverUrl}/${filePath}`, - * key: filePath - * } - * } - * // ... - * } - * ``` - * - * :::tip - * - * This example does not account for duplicate names to maintain simplicity in this guide. So, an uploaded file can replace another existing file that has the same name. - * - * ::: - */ - uploadProtected(file: Express.Multer.File): Promise - - /** - * This method is used to delete a file from storage. - * - * @param {DeleteFileType} fileData - The details of the file to remove. - * @returns {Promise} Resolves when the file is deleted successfully. - * - * @example - * class LocalFileService extends AbstractFileService { - * - * async delete( - * fileData: DeleteFileType - * ): Promise { - * fs.rmSync(fileData.fileKey) - * } - * - * // ... - * } - */ - delete(fileData: DeleteFileType): Promise - - /** - * This method is used to retrieve a write stream to be used to upload a file. - * - * @param {UploadStreamDescriptorType} fileData - The details of the file being uploaded. - * @returns {Promise} The result of the file-stream upload. - * - * @example - * // ... - * import { Stream } from "stream" - * - * class LocalFileService extends AbstractFileService { - * // ... - * async getUploadStreamDescriptor({ - * name, - * ext, - * isPrivate = true, - * }: UploadStreamDescriptorType - * ): Promise { - * const filePath = `${isPrivate ? - * this.publicPath : this.protectedPath - * }/${name}.${ext}` - * - * const pass = new Stream.PassThrough() - * const writeStream = fs.createWriteStream(filePath) - * - * pass.pipe(writeStream) - * - * return { - * writeStream: pass, - * promise: Promise.resolve(), - * url: `${this.serverUrl}/${filePath}`, - * fileKey: filePath, - * } - * } - * // ... - * } - */ - getUploadStreamDescriptor( - fileData: UploadStreamDescriptorType - ): Promise - - /** - * This method is used to retrieve a read stream for a file, which can then be used to download the file. - * - * @param {GetUploadedFileType} fileData - The details of the file. - * @returns {Promise} The [read stream](https://nodejs.org/api/webstreams.html#class-readablestream) to read and download the file. - * - * @example - * class LocalFileService extends AbstractFileService { - * - * async getDownloadStream({ - * fileKey, - * isPrivate = true, - * }: GetUploadedFileType - * ): Promise { - * const filePath = `${isPrivate ? - * this.publicPath : this.protectedPath - * }/${fileKey}` - * const readStream = fs.createReadStream(filePath) - * - * return readStream - * } - * - * // ... - * } - */ - getDownloadStream( - fileData: GetUploadedFileType - ): Promise - - /** - * This method is used to retrieve a download URL of the file. For some file services, such as S3, a presigned URL indicates a temporary URL to get access to a file. - * - * If your file service doesn’t perform or offer a similar functionality, you can just return the URL to download the file. - * - * @param {GetUploadedFileType} fileData - The details of the file. - * @returns {Promise} The presigned URL to download the file - * - * @example - * class LocalFileService extends AbstractFileService { - * - * async getPresignedDownloadUrl({ - * fileKey, - * isPrivate = true, - * }: GetUploadedFileType - * ): Promise { - * // Local upload doesn't provide - * // support for presigned URLs, - * // so just return the file's URL. - * - * const filePath = `${isPrivate ? - * this.publicPath : this.protectedPath - * }/${fileKey}` - * return `${this.serverUrl}/${filePath}` - * } - * - * // ... - * } - */ - getPresignedDownloadUrl(fileData: GetUploadedFileType): Promise -} - -/** - * @parentIgnore activeManager_,atomicPhase_,shouldRetryTransaction_,withTransaction - */ -export abstract class AbstractFileService - extends TransactionBaseService - implements IFileService -{ - /** - * @ignore - */ - static _isFileService = true - - /** - * @ignore - */ - static isFileService(object): object is AbstractFileService { - return object?.constructor?._isFileService - } - - /** - * You can use the `constructor` of your file service to access the different services in Medusa through dependency injection. - * - * You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs, - * you can initialize it in the constructor and use it in other methods in the service. - * - * Additionally, if you’re creating your file service as an external plugin to be installed on any Medusa backend and you want to access the options added for the plugin, - * you can access them in the constructor. - * - * @param {Record} container - An instance of `MedusaContainer` that allows you to access other resources, such as services, in your Medusa backend. - * @param {Record} config - If this file service is created in a plugin, the plugin's options are passed in this parameter. - * - * @example - * // ... - * import { Logger } from "@medusajs/medusa" - * import * as fs from "fs" - * - * class LocalFileService extends AbstractFileService { - * // can also be replaced by an environment variable - * // or a plugin option - * protected serverUrl = "http://localhost:9000" - * protected publicPath = "uploads" - * protected protectedPath = "protected-uploads" - * protected logger_: Logger - * - * constructor({ logger }: InjectedDependencies) { - * // @ts-ignore - * super(...arguments) - * this.logger_ = logger - * - * // for public uploads - * if (!fs.existsSync(this.publicPath)) { - * fs.mkdirSync(this.publicPath) - * } - * - * // for protected uploads - * if (!fs.existsSync(this.protectedPath)) { - * fs.mkdirSync(this.protectedPath) - * } - * } - * // ... - * } - */ - protected constructor( - protected readonly container: Record, - protected readonly config?: Record // eslint-disable-next-line @typescript-eslint/no-empty-function - ) { - super(container, config) - } - - abstract upload( - fileData: Express.Multer.File - ): Promise - - abstract uploadProtected( - fileData: Express.Multer.File - ): Promise - - abstract delete(fileData: DeleteFileType): Promise - - abstract getUploadStreamDescriptor( - fileData: UploadStreamDescriptorType - ): Promise - - abstract getDownloadStream( - fileData: GetUploadedFileType - ): Promise - - abstract getPresignedDownloadUrl( - fileData: GetUploadedFileType - ): Promise -} diff --git a/packages/medusa/src/interfaces/fulfillment-service.ts b/packages/medusa/src/interfaces/fulfillment-service.ts deleted file mode 100644 index d0ac6adee7..0000000000 --- a/packages/medusa/src/interfaces/fulfillment-service.ts +++ /dev/null @@ -1,511 +0,0 @@ -import { MedusaContainer } from "@medusajs/types" -import { Cart, Fulfillment, LineItem, Order } from "../models" -import { CreateReturnType } from "../types/fulfillment-provider" -import { TransactionBaseService } from "./transaction-base-service" - -type FulfillmentProviderData = Record -type ShippingOptionData = Record -type ShippingMethodData = Record - -/** - * ## Overview - * - * A fulfillment provider is the shipping provider used to fulfill orders and deliver them to customers. An example of a fulfillment provider is FedEx. - * - * By default, a Medusa Backend has a `manual` fulfillment provider which has minimal implementation. It allows you to accept orders and fulfill them manually. However, you can integrate any fulfillment provider into Medusa, and your fulfillment provider can interact with third-party shipping providers. - * - * A fulfillment provider is a service that extends the `AbstractFulfillmentService` and implements its methods. So, adding a fulfillment provider is as simple as creating a service file in `src/services`. - * The file's name is the fulfillment provider's class name as a slug and without the word `Service`. For example, if you're creating a `MyFulfillmentService` class, the file name is `src/services/my-fulfillment.ts`. - * - * ```ts title="src/services/my-fulfillment.ts" - * import { AbstractFulfillmentService } from "@medusajs/medusa" - * - * class MyFulfillmentService extends AbstractFulfillmentService { - * // methods here... - * } - * - * export default MyFulfillmentService - * ``` - * - * --- - * - * ## Identifier Property - * - * The `FulfillmentProvider` entity has 2 properties: `identifier` and `is_installed`. The `identifier` property in the fulfillment provider service is used when the fulfillment provider is added to the database. - * - * The value of this property is also used to reference the fulfillment provider throughout Medusa. For example, it is used to [add a fulfillment provider](https://docs.medusajs.com/api/admin#regions_postregionsregionfulfillmentproviders) to a region. - * - * ```ts - * class MyFulfillmentService extends AbstractFulfillmentService { - * static identifier = "my-fulfillment" - * - * // ... - * } - * ``` - * - * --- - */ -export interface FulfillmentService extends TransactionBaseService { - /** - * @ignore - * - * Return a unique identifier to retrieve the fulfillment plugin provider - */ - getIdentifier(): string - - /** - * This method is used when retrieving the list of fulfillment options available in a region, particularly by the [List Fulfillment Options API Route](https://docs.medusajs.com/api/admin#regions_getregionsregionfulfillmentoptions). - * For example, if you’re integrating UPS as a fulfillment provider, you might support two fulfillment options: UPS Express Shipping and UPS Access Point. Each of these options can have different data associated with them. - * - * @returns {Promise} The list of fulfillment options. These options don't have any required format. Later on, these options can be used when creating a shipping option, - * such as when using the [Create Shipping Option API Route](https://docs.medusajs.com/api/admin#shipping-options_postshippingoptions). The chosen fulfillment option, which is one of the - * items in the array returned by this method, will be set in the `data` object of the shipping option. - * - * @example - * class MyFulfillmentService extends AbstractFulfillmentService { - * // ... - * async getFulfillmentOptions(): Promise { - * return [ - * { - * id: "my-fulfillment", - * }, - * { - * id: "my-fulfillment-dynamic", - * }, - * ] - * } - * } - */ - getFulfillmentOptions(): Promise - - /** - * This method is called when a shipping method is created. This typically happens when the customer chooses a shipping option during checkout, when a shipping method is created - * for an order return, or in other similar cases. The shipping option and its data are validated before the shipping method is created. - * - * You can use the provided parameters to validate the chosen shipping option. For example, you can check if the `data` object passed as a second parameter includes all data needed to - * fulfill the shipment later on. - * - * If any of the data is invalid, you can throw an error. This error will stop Medusa from creating a shipping method and the error message will be returned as a result of the API Route. - * - * @param {ShippingOptionData} optionData - The data object of the shipping option selected when creating the shipping method. - * @param {FulfillmentProviderData} data - The `data` object passed in the body of the request. - * @param {Cart} cart - The customer's cart details. It may be empty if the shipping method isn't associated with a cart, such as when it's associated with a claim. - * @returns {Promise>} The data that will be stored in the `data` property of the shipping method to be created. - * Make sure the value you return contains everything you need to fulfill the shipment later on. The returned value may also be used to calculate the price of the shipping method - * if it doesn't have a set price. It will be passed along to the {@link calculatePrice} method. - * - * @example - * class MyFulfillmentService extends AbstractFulfillmentService { - * // ... - * async validateFulfillmentData( - * optionData: Record, - * data: Record, - * cart: Cart - * ): Promise> { - * if (data.id !== "my-fulfillment") { - * throw new Error("invalid data") - * } - * - * return { - * ...data, - * } - * } - * } - */ - validateFulfillmentData( - optionData: ShippingOptionData, - data: FulfillmentProviderData, - cart: Cart - ): Promise> - - /** - * Once the admin creates the shipping option, the data of the shipping option will be validated first using this method. This method is called when the [Create Shipping Option API Route](https://docs.medusajs.com/api/admin#shipping-options_postshippingoptions) is used. - * - * @param {ShippingOptionData} data - the data object that is sent in the body of the request, basically, the data object of the shipping option. You can use this data to validate the shipping option before it is saved. - * @returns {Promise} Whether the fulfillment option is valid. If the returned value is false, an error is thrown and the shipping option will not be saved. - * - * @example - * For example, you can use this method to ensure that the `id` in the `data` object is correct: - * - * ```ts - * class MyFulfillmentService extends AbstractFulfillmentService { - * // ... - * async validateOption( - * data: Record - * ): Promise { - * return data.id == "my-fulfillment" - * } - * } - * ``` - */ - validateOption(data: ShippingOptionData): Promise - - /** - * This method is used to determine whether a shipping option is calculated dynamically or flat rate. It is called if the `price_type` of the shipping option being created is set to calculated. - * - * @param {ShippingOptionData} data - The `data` object of the shipping option being created. You can use this data to determine whether the shipping option should be calculated or not. - * This is useful if the fulfillment provider you are integrating has both flat rate and dynamically priced fulfillment options. - * @returns {Promise} If this method returns `true`, that means that the price can be calculated dynamically and the shipping option can have the `price_type` set to calculated. - * The amount property of the shipping option will then be set to null. The amount will be created later when the shipping method is created on checkout using the {@link calculatePrice} method. - * If the method returns `false`, an error is thrown as it means the selected shipping option is invalid and it can only have the `flat_rate` price type. - * - * @example - * class MyFulfillmentService extends AbstractFulfillmentService { - * // ... - * async canCalculate( - * data: Record - * ): Promise { - * return data.id === "my-fulfillment-dynamic" - * } - * } - */ - canCalculate(data: ShippingOptionData): Promise - - /** - * This method is used in different places, including: - * - * 1. When the shipping options for a cart are retrieved during checkout. If a shipping option has their `price_type` set to calculated, this method is used to set the amount of the returned shipping option. - * 2. When a shipping method is created. If the shipping option associated with the method has their `price_type` set to `calculated`, this method is used to set the `price` attribute of the shipping method in the database. - * 3. When the cart's totals are calculated. - * - * @param {ShippingOptionData} optionData - The `data` object of the selected shipping option. - * @param {FulfillmentProviderData} data - - * A `data` object that is different based on the context it's used in: - * - * 1. If the price is being calculated for the list of shipping options available for a cart, it's the `data` object of the shipping option. - * 2. If the price is being calculated when the shipping method is being created, it's the data returned by the {@link validateFulfillmentData} method used during the shipping method creation. - * 3. If the price is being calculated while calculating the cart's totals, it will be the data object of the cart's shipping method. - * @param {Cart} cart - Either the Cart or the Order object. - * @returns {Promise} Used to set the price of the shipping method or option, based on the context the method is used in. - * - * @example - * An example of calculating the price based on some custom logic: - * - * ```ts - * class MyFulfillmentService extends AbstractFulfillmentService { - * // ... - * async calculatePrice( - * optionData: Record, - * data: Record, - * cart: Cart - * ): Promise { - * return cart.items.length * 1000 - * } - * } - * ``` - * - * If your fulfillment provider does not provide any dynamically calculated rates you can return any static value or throw an error. For example: - * - * ```ts - * class MyFulfillmentService extends AbstractFulfillmentService { - * // ... - * async calculatePrice( - * optionData: Record, - * data: Record, - * cart: Cart - * ): Promise { - * throw new Error("Method not implemented.") - * } - * } - * ``` - */ - calculatePrice( - optionData: ShippingOptionData, - data: FulfillmentProviderData, - cart: Cart - ): Promise - - /** - * This method is used when a fulfillment is created for an order, a claim, or a swap. - * - * @param {ShippingMethodData} data - - * The `data` object of the shipping method associated with the resource, such as the order. - * You can use it to access the data specific to the shipping option. This is based on your implementation of previous methods. - * @param {LineItem[]} items - The line items in the order to be fulfilled. The admin can choose all or some of the items to fulfill. - * @param {Order} order - - * The details of the created resource, which is either an order, a claim, or a swap: - * - If the resource the fulfillment is being created for is a claim, the `is_claim` property in the object will be `true`. - * - If the resource the fulfillment is being created for is a swap, the `is_swap` property in the object will be `true`. - * - Otherwise, the resource is an order. - * @param {Fulfillment} fulfillment - The fulfillment being created. - * @returns {Promise} The data that will be stored in the `data` attribute of the created fulfillment. - * - * @example - * Here is a basic implementation of `createFulfillment` for a fulfillment provider that does not interact with any third-party provider to create the fulfillment: - * - * ```ts - * class MyFulfillmentService extends AbstractFulfillmentService { - * // ... - * async createFulfillment( - * data: Record, - * items: LineItem[], - * order: Order, - * fulfillment: Fulfillment - * ) { - * // No data is being sent anywhere - * // No data to be stored in the fulfillment's data object - * return {} - * } - * } - * ``` - */ - createFulfillment( - data: ShippingMethodData, - items: LineItem[], - order: Order, - fulfillment: Fulfillment - ): Promise - - /** - * This method is called when a fulfillment is cancelled by the admin. This fulfillment can be for an order, a claim, or a swap. - * - * @param {FulfillmentProviderData} fulfillmentData - The `data` attribute of the fulfillment being canceled - * @returns {Promise} The method isn't expected to return any specific data. - * - * @example - * This is the basic implementation of the method for a fulfillment provider that doesn't interact with a third-party provider to cancel the fulfillment: - * - * ```ts - * class MyFulfillmentService extends FulfillmentService { - * // ... - * async cancelFulfillment( - * fulfillment: Record - * ): Promise { - * return {} - * } - * } - * ``` - */ - cancelFulfillment(fulfillmentData: FulfillmentProviderData): Promise - - /** - * Fulfillment providers can also be used to return products. A shipping option can be used for returns if the `is_return` property is true or if an admin creates a Return Shipping Option from the settings. - * This method is used when the admin [creates a return request](https://docs.medusajs.com/api/admin#orders_postordersorderreturns) for an order, - * [creates a swap](https://docs.medusajs.com/api/admin#orders_postordersorderswaps) for an order, or when the - * [customer creates a return of their order](https://docs.medusajs.com/api/store#returns_postreturns). The fulfillment is created automatically for the order return. - * - * @param {CreateReturnType} returnOrder - the return that the fulfillment is being created for. - * @returns {Promise>} Used to set the value of the `shipping_data` attribute of the return being created. - * - * @example - * This is the basic implementation of the method for a fulfillment provider that does not contact with a third-party provider to fulfill the return: - * - * ```ts - * class MyFulfillmentService extends AbstractFulfillmentService { - * // ... - * async createReturn( - * returnOrder: CreateReturnType - * ): Promise> { - * return {} - * } - * } - * ``` - */ - createReturn(returnOrder: CreateReturnType): Promise> - - /** - * This method is used to retrieve any documents associated with a fulfillment. This method isn't used by default in the backend, but you can use it for custom use cases such as allowing admins to download these documents. - * - * @param {FulfillmentProviderData} data - The `data` attribute of the fulfillment that you're retrieving the documents for. - * @returns {Promise} There are no restrictions on the returned response. If your fulfillment provider doesn't provide this functionality, you can leave the method empty or through an error. - * - * @example - * class MyFulfillmentService extends FulfillmentService { - * // ... - * async getFulfillmentDocuments( - * data: Record - * ): Promise { - * // assuming you contact a client to - * // retrieve the document - * return this.client.getFulfillmentDocuments() - * } - * } - */ - getFulfillmentDocuments(data: FulfillmentProviderData): Promise - - /** - * This method is used to retrieve any documents associated with a return. This method isn't used by default in the backend, but you can use it for custom use cases such as allowing admins to download these documents. - * - * @param {Record} data - The data attribute of the return that you're retrieving the documents for. - * @returns {Promise} There are no restrictions on the returned response. If your fulfillment provider doesn't provide this functionality, you can leave the method empty or through an error. - * - * @example - * class MyFulfillmentService extends FulfillmentService { - * // ... - * async getReturnDocuments( - * data: Record - * ): Promise { - * // assuming you contact a client to - * // retrieve the document - * return this.client.getReturnDocuments() - * } - * } - */ - getReturnDocuments(data: Record): Promise - - /** - * This method is used to retrieve any documents associated with a shipment. This method isn't used by default in the backend, but you can use it for custom use cases such as allowing admins to download these documents. - * - * @param {Record} data - The `data` attribute of the shipment that you're retrieving the documents for. - * @returns {Promise} There are no restrictions on the returned response. If your fulfillment provider doesn't provide this functionality, you can leave the method empty or through an error. - * - * @example - * class MyFulfillmentService extends FulfillmentService { - * // ... - * async getShipmentDocuments( - * data: Record - * ): Promise { - * // assuming you contact a client to - * // retrieve the document - * return this.client.getShipmentDocuments() - * } - * } - */ - getShipmentDocuments(data: Record): Promise - - /** - * This method is used to retrieve any documents associated with an order and its fulfillments. This method isn't used by default in the backend, but you can use it for - * custom use cases such as allowing admins to download these documents. - * - * @param {FulfillmentProviderData} fulfillmentData - The `data` attribute of the order's fulfillment. - * @param documentType - The type of document to retrieve. - * @returns {Promise} There are no restrictions on the returned response. If your fulfillment provider doesn't provide this functionality, you can leave the method empty or through an error. - * - * @example - * class MyFulfillmentService extends FulfillmentService { - * // ... - * async retrieveDocuments( - * fulfillmentData: Record, - * documentType: "invoice" | "label" - * ): Promise { - * // assuming you contact a client to - * // retrieve the document - * return this.client.getDocuments() - * } - * } - */ - retrieveDocuments( - fulfillmentData: FulfillmentProviderData, - documentType: "invoice" | "label" - ): Promise -} - -/** - * @parentIgnore activeManager_,atomicPhase_,shouldRetryTransaction_,withTransaction - */ -export abstract class AbstractFulfillmentService - extends TransactionBaseService - implements FulfillmentService -{ - /** - * @ignore - */ - static _isFulfillmentService = true - - /** - * @ignore - */ - static isFulfillmentService(object): boolean { - return object?.constructor?._isFulfillmentService - } - - /** - * You can use the `constructor` of your fulfillment provider to access the different services in Medusa through dependency injection. - * - * You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs, you can initialize it in the constructor and use it in other methods in the service. - * Additionally, if you’re creating your fulfillment provider as an external plugin to be installed on any Medusa backend and you want to access the options added for the plugin, you can access it in the constructor. - * - * @param {Record} container - An instance of `MedusaContainer` that allows you to access other resources, such as services, in your Medusa backend. - * @param {Record} config - If this fulfillment provider is created in a plugin, the plugin's options are passed in this parameter. - * - * @example - * class MyFulfillmentService extends AbstractFulfillmentService { - * // ... - * constructor(container, options) { - * super(container) - * // you can access options here - * - * // you can also initialize a client that - * // communicates with a third-party service. - * this.client = new Client(options) - * } - * // ... - * } - */ - protected constructor( - protected readonly container: Record, - protected readonly config?: Record // eslint-disable-next-line @typescript-eslint/no-empty-function - ) { - super(container, config) - } - - /** - * The `FulfillmentProvider` entity has 2 properties: `identifier` and `is_installed`. The `identifier` property in the class is used when the fulfillment provider is created in the database. - * The value of this property is also used to reference the fulfillment provider throughout Medusa. For example, it is used to [add a fulfillment provider](https://docs.medusajs.com/api/admin#regions_postregionsregionfulfillmentproviders) to a region. - * - * @example - * class MyFulfillmentService extends AbstractFulfillmentService { - * static identifier = "my-fulfillment" - * - * // ... - * } - */ - public static identifier: string - - /** - * @ignore - */ - public getIdentifier(): string { - const ctr = this.constructor as typeof AbstractFulfillmentService - - if (!ctr.identifier) { - throw new Error(`Missing static property "identifier".`) - } - - return ctr.identifier - } - - abstract getFulfillmentOptions(): Promise - - abstract validateFulfillmentData( - optionData: ShippingOptionData, - data: FulfillmentProviderData, - cart: Cart - ): Promise> - - abstract validateOption(data: ShippingOptionData): Promise - - abstract canCalculate(data: ShippingOptionData): Promise - - abstract calculatePrice( - optionData: ShippingOptionData, - data: FulfillmentProviderData, - cart: Cart - ): Promise - - abstract createFulfillment( - data: ShippingMethodData, - items: LineItem[], - order: Order, - fulfillment: Fulfillment - ): Promise - - abstract cancelFulfillment(fulfillment: FulfillmentProviderData): Promise - - abstract createReturn( - returnOrder: CreateReturnType - ): Promise> - - abstract getFulfillmentDocuments(data: FulfillmentProviderData): Promise - - abstract getReturnDocuments(data: Record): Promise - - abstract getShipmentDocuments(data: Record): Promise - - abstract retrieveDocuments( - fulfillmentData: Record, - documentType: "invoice" | "label" - ): Promise -} - -export default AbstractFulfillmentService diff --git a/packages/medusa/src/interfaces/index.ts b/packages/medusa/src/interfaces/index.ts index fcda0f172d..1351f8d00d 100644 --- a/packages/medusa/src/interfaces/index.ts +++ b/packages/medusa/src/interfaces/index.ts @@ -1,13 +1,3 @@ -export * from "./batch-job-strategy" -export * from "./cart-completion-strategy" -export * from "./file-service" -export * from "./fulfillment-service" export * from "./models/base-entity" export * from "./models/soft-deletable-entity" -export * from "./notification-service" -export * from "./payment-processor" -export * from "./payment-service" -export * from "./price-selection-strategy" -export * from "./tax-calculation-strategy" -export * from "./tax-service" export * from "./transaction-base-service" diff --git a/packages/medusa/src/interfaces/notification-service.ts b/packages/medusa/src/interfaces/notification-service.ts deleted file mode 100644 index edf62ef60d..0000000000 --- a/packages/medusa/src/interfaces/notification-service.ts +++ /dev/null @@ -1,284 +0,0 @@ -import { MedusaContainer } from "@medusajs/types" -import { TransactionBaseService } from "./transaction-base-service" - -/** - * @interface - * - * The details of a sent or resent notification. - */ -export type ReturnedData = { - /** - * The receiver of the Notification. For example, if you sent an email to the customer then `to` is the email address of the customer. - * In other cases, it might be a phone number or a username. - */ - to: string - /** - * The status of the sent notification. There are no restriction on the returned status. - */ - status: string - /** - * The data used to send the Notification. For example, if you sent an order confirmation email to the customer, then the `data` object - * might include the order items or the subject of the email. This `data` is necessary if the notification is resent later as you can use the same data. - */ - data: Record -} - -/** - * ## Overview - * - * :::note[Prerequisites] - * - * Before creating a Notification Provider, [install an event bus module](https://docs.medusajs.com/development/events/modules/redis). - * - * ::: - * - * A Notification Provider is a provider that handles sending and resending of notifications. - * - * To create a Notification Provider, create a TypeScript or JavaScript file in `src/services`. The name of the file is the name of the provider - * (for example, `sendgrid.ts`). The file must export a class that extends the `AbstractNotificationService` class imported from `@medusajs/medusa`. - * - * For example, create the file `src/services/email-sender.ts` with the following content: - * - * ```ts title="src/services/email-sender.ts" - * import { AbstractNotificationService } from "@medusajs/medusa" - * import { EntityManager } from "typeorm" - * - * class EmailSenderService extends AbstractNotificationService { - * protected manager_: EntityManager - * protected transactionManager_: EntityManager - * - * sendNotification( - * event: string, - * data: unknown, - * attachmentGenerator: unknown - * ): Promise<{ - * to: string; - * status: string; - * data: Record; - * }> { - * throw new Error("Method not implemented.") - * } - * resendNotification( - * notification: unknown, - * config: unknown, - * attachmentGenerator: unknown - * ): Promise<{ - * to: string; - * status: string; - * data: Record; - * }> { - * throw new Error("Method not implemented.") - * } - * - * } - * - * export default EmailSenderService - * ``` - * - * --- - * - * ## Identifier Property - * - * The `NotificationProvider` entity has 2 properties: `identifier` and `is_installed`. The value of the `identifier` property in the notification provider - * class is used when the Notification Provider is created in the database. - * - * The value of this property is also used later when you want to subscribe the Notification Provider to events in a [Loader](https://docs.medusajs.com/development/loaders/overview). - * - * For example: - * - * ```ts - * class EmailSenderService extends AbstractNotificationService { - * static identifier = "email-sender" - * // ... - * } - * ``` - * - * --- - */ -export interface INotificationService extends TransactionBaseService { - /** - * When an event is triggered that your Notification Provider is registered as a handler for, the [`NotificationService`](https://docs.medusajs.com/references/services/classes/services.NotificationService) - * in the Medusa backend executes this method of your Notification Provider. - * - * In this method, you can perform the necessary operation to send the Notification. For example, you can send an email to the customer when they place an order. - * - * @param {string} event - The name of the event that was triggered. For example, `order.placed`. - * @param {unknown} data - The data payload of the event that was triggered. For example, if the `order.placed` event is triggered, - * the `eventData` object contains the property `id` which is the ID of the order that was placed. You can refer to the - * [Events reference](https://docs.medusajs.com/development/events/events-list) for information on all events and their payloads. - * @param {unknown} attachmentGenerator - If you’ve previously register an attachment generator to the `NotificationService` using the - * [`registerAttachmentGenerator`](https://docs.medusajs.com/references/services/classes/services.NotificationService#registerattachmentgenerator) method, - * you have access to it here. You can use the `attachmentGenerator` to generate on-demand invoices or other documents. The default value of this parameter is `null`. - * @returns {Promise} The sending details. - * - * @example - * class EmailSenderService extends AbstractNotificationService { - * // ... - * async sendNotification( - * event: string, - * data: any, - * attachmentGenerator: unknown - * ): Promise<{ - * to: string; - * status: string; - * data: Record; - * }> { - * if (event === "order.placed") { - * // retrieve order - * const order = await this.orderService.retrieve(data.id) - * // TODO send email - * - * console.log("Notification sent") - * return { - * to: order.email, - * status: "done", - * data: { - * // any data necessary to send the email - * // for example: - * subject: "You placed a new order!", - * items: order.items, - * }, - * } - * } - * } - * // ... - * } - */ - sendNotification( - event: string, - data: unknown, - attachmentGenerator: unknown - ): Promise - - /** - * This method is used to resend notifications, which is typically triggered by the - * [Resend Notification API Route](https://docs.medusajs.com/api/admin#notifications_postnotificationsnotificationresend). - * - * @param {unknown} notification - The original [Notification record](https://docs.medusajs.com/references/entities/classes/Notification) that was created after you sent the - * notification with `sendNotification`. It includes the `to` and `data` attributes which are populated originally using the `to` and `data` properties of - * the object you return in {@link sendNotification}. - * @param {unknown} config - The new configuration used to resend the notification. The [Resend Notification API Route](https://docs.medusajs.com/api/admin#notifications_postnotificationsnotificationresend), - * allows you to pass a new `to` field. If specified, it will be available in this config object. - * @param {unknown} attachmentGenerator - f you’ve previously register an attachment generator to the `NotificationService` using the - * [`registerAttachmentGenerator`](https://docs.medusajs.com/references/services/classes/services.NotificationService#registerattachmentgenerator) method, - * you have access to it here. You can use the `attachmentGenerator` to generate on-demand invoices or other documents. The default value of this parameter is `null`. - * @returns {Promise} The resend details. - * - * @example - * class EmailSenderService extends AbstractNotificationService { - * // ... - * async resendNotification( - * notification: any, - * config: any, - * attachmentGenerator: unknown - * ): Promise<{ - * to: string; - * status: string; - * data: Record; - * }> { - * // check if the receiver should be changed - * const to: string = config.to || notification.to - * - * // TODO resend the notification using the same data - * // that is saved under notification.data - * - * console.log("Notification resent") - * return { - * to, - * status: "done", - * data: notification.data, // make changes to the data - * } - * } - * } - */ - resendNotification( - notification: unknown, - config: unknown, - attachmentGenerator: unknown - ): Promise -} - -/** - * @parentIgnore activeManager_,atomicPhase_,shouldRetryTransaction_,withTransaction - */ -export abstract class AbstractNotificationService - extends TransactionBaseService - implements INotificationService -{ - /** - * @ignore - */ - static _isNotificationService = true - static identifier: string - - /** - * @ignore - */ - static isNotificationService(object): boolean { - return object?.constructor?._isNotificationService - } - - /** - * @ignore - */ - getIdentifier(): string { - return (this.constructor as any).identifier - } - - /** - * You can use the `constructor` of your notification provider to access the different services in Medusa through dependency injection. - * - * You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs, - * you can initialize it in the constructor and use it in other methods in the service. - * - * Additionally, if you’re creating your notification provider as an external plugin to be installed on any Medusa backend and you want to access the options - * added for the plugin, you can access it in the constructor. - * - * @param {Record} container - An instance of `MedusaContainer` that allows you to access other resources, such as services, in your Medusa backend. - * @param {Record} config - If this notification provider is created in a plugin, the plugin's options are passed in this parameter. - * - * @example - * // ... - * import { AbstractNotificationService, OrderService } from "@medusajs/medusa" - * import { EntityManager } from "typeorm" - * - * class EmailSenderService extends AbstractNotificationService { - * // ... - * protected orderService: OrderService - * - * constructor(container, options) { - * super(container) - * // you can access options here in case you're - * // using a plugin - * - * this.orderService = container.orderService - * - * // you can also initialize a client that - * // communicates with a third-party service. - * this.client = new Client(options) - * } - * - * // ... - * } - * - * export default EmailSenderService - */ - protected constructor( - protected readonly container: Record, - protected readonly config?: Record // eslint-disable-next-line @typescript-eslint/no-empty-function - ) { - super(container, config) - } - - abstract sendNotification( - event: string, - data: unknown, - attachmentGenerator: unknown - ): Promise - - abstract resendNotification( - notification: unknown, - config: unknown, - attachmentGenerator: unknown - ): Promise -} diff --git a/packages/medusa/src/interfaces/payment-processor.ts b/packages/medusa/src/interfaces/payment-processor.ts deleted file mode 100644 index 697138fa8f..0000000000 --- a/packages/medusa/src/interfaces/payment-processor.ts +++ /dev/null @@ -1,787 +0,0 @@ -import { Address, Customer, PaymentSessionStatus } from "../models" -import { MedusaContainer } from "../types/global" - -/** - * @interface - * - * A payment's context. - */ -export type PaymentProcessorContext = { - /** - * The payment's billing address. - */ - billing_address?: Address | null - /** - * The customer's email. - */ - email: string - /** - * The selected currency code, typically associated with the customer's cart. - */ - currency_code: string - /** - * The payment's amount. - */ - amount: number - /** - * The ID of the resource the payment is associated with. For example, the cart's ID. - */ - resource_id: string - /** - * The customer associated with this payment. - */ - customer?: Customer - /** - * The cart's context. - */ - context: Record - /** - * If the payment session hasn't been created or initiated yet, it'll be an empty object. - * If the payment session exists, it'll be the value of the payment session's `data` field. - */ - paymentSessionData: Record -} - -/** - * @interface - * - * The response of operations on a payment. - */ -export type PaymentProcessorSessionResponse = { - /** - * Used to specify data that should be updated in the Medusa backend. - */ - update_requests?: { - /** - * Specifies a new value of the `metadata` field of the customer associated with the payment. - */ - customer_metadata?: Record - } - /** - * The data to be stored in the `data` field of the Payment Session to be created. - * The `data` field is useful to hold any data required by the third-party provider to process the payment or retrieve its details at a later point. - */ - session_data: Record -} - -/** - * An object that is returned in case of an error. - */ -export interface PaymentProcessorError { - /** - * The error message - */ - error: string - /** - * The error code. - */ - code?: string - /** - * Any additional helpful details. - */ - detail?: any -} - -/** - * ## Overview - * - * A Payment Processor is the payment method used to authorize, capture, and refund payment, among other actions. An example of a Payment Processor is Stripe. - * - * By default, Medusa has a `manual` payment provider that has minimal implementation. It can be synonymous with a Cash on Delivery payment method. It allows - * store operators to manage the payment themselves but still keep track of its different stages on Medusa. - * - * A payment processor is a service that extends the `AbstractPaymentProcessor` and implements its methods. So, adding a Payment Processor is as simple as - * creating a service file in `src/services`. The file's name is the payment processor's class name as a slug and without the word `Service`. - * For example, if you're creating a `MyPaymentService` class, the file name is `src/services/my-payment.ts`. - * - * ```ts - * import { AbstractPaymentProcessor } from "@medusajs/medusa"; - * - * class MyPaymentService extends AbstractPaymentProcessor { - * // methods here... - * } - * - * export default MyPaymentService - * ``` - * - * The methods of the payment processor are used at different points in the Checkout flow as well as when processing an order after it’s placed. - * - * ![Checkout Flow - Payment](https://res.cloudinary.com/dza7lstvk/image/upload/v1680177820/Medusa%20Docs/Diagrams/checkout-payment_cy9efp.jpg) - * - * --- - * - * ## Identifier Property - * - * The `PaymentProvider` entity has 2 properties: `id` and `is_installed`. The `identifier` property in the payment processor service is used when the payment processor is added to the database. - * - * The value of this property is also used to reference the payment processor throughout Medusa. - * For example, it is used to [add a payment processor](https://docs.medusajs.com/api/admin#regions_postregionsregionpaymentproviders) to a region. - * - * ```ts - * class MyPaymentService extends AbstractPaymentProcessor { - * static identifier = "my-payment" - * // ... - * } - * ``` - * - * --- - * - * ## PaymentProcessorError - * - * Before diving into the methods of the Payment Processor, you'll notice that part of the expected return signature of these method includes `PaymentProcessorError`. - * - * ```ts - * interface PaymentProcessorError { - * error: string - * code?: string - * detail?: any - * } - * ``` - * - * While implementing the Payment Processor's methods, if you need to inform the Medusa core that an error occurred at a certain stage, - * return an object having the attributes defined in the `PaymentProcessorError` interface. - * - * For example, the Stripe payment processor has the following method to create the error object, which is used within other methods: - * - * ```ts - * abstract class StripeBase extends AbstractPaymentProcessor { - * // ... - * protected buildError( - * message: string, - * e: Stripe.StripeRawError | PaymentProcessorError | Error - * ): PaymentProcessorError { - * return { - * error: message, - * code: "code" in e ? e.code : "", - * detail: isPaymentProcessorError(e) - * ? `${e.error}${EOL}${e.detail ?? ""}` - * : "detail" in e - * ? e.detail - * : e.message ?? "", - * } - * } - * - * // used in other methods - * async retrievePayment( - * paymentSessionData: Record - * ): Promise< - * PaymentProcessorError | - * PaymentProcessorSessionResponse["session_data"] - * > { - * try { - * // ... - * } catch (e) { - * return this.buildError( - * "An error occurred in retrievePayment", - * e - * ) - * } - * } - * } - * ``` - * - * --- - * - */ -export interface PaymentProcessor { - /** - * @ignore - * - * Return a unique identifier to retrieve the payment plugin provider - */ - getIdentifier(): string - - /** - * This method is called either if a region has only one payment provider enabled or when [a Payment Session is selected](https://docs.medusajs.com/api/store#carts_postcartscartpaymentsession), - * which occurs when the customer selects their preferred payment method during checkout. - * - * It is used to allow you to make any necessary calls to the third-party provider to initialize the payment. For example, in Stripe this method is used to create a Payment Intent for the customer. - * - * @param {PaymentProcessorContext} context - The context of the payment. - * @returns {Promise} Either the payment's data or an error object. - * - * @example - * import { - * PaymentContext, - * PaymentSessionResponse, - * // ... - * } from "@medusajs/medusa" - * - * class MyPaymentService extends AbstractPaymentProcessor { - * // ... - * async initiatePayment( - * context: PaymentProcessorContext - * ): Promise< - * PaymentProcessorError | PaymentProcessorSessionResponse - * > { - * // assuming client is an initialized client - * // communicating with a third-party service. - * const clientPayment = await this.client.initiate(context) - * - * return { - * session_data: { - * id: clientPayment.id - * }, - * } - * } - * } - */ - initiatePayment( - context: PaymentProcessorContext - ): Promise - - /** - * This method is used to update the payment session when the payment amount changes. It's called whenever the cart or any of its related data is updated. - * For example, when a [line item is added to the cart](https://docs.medusajs.com/api/store#carts_postcartscartlineitems) or when a - * [shipping method is selected](https://docs.medusajs.com/api/store#carts_postcartscartshippingmethod). - * - * @param {PaymentProcessorContext} context - The context of the payment. - * @returns {Promise} Either the payment's data or an error object. - * - * @example - * import { - * PaymentProcessorContext, - * PaymentProcessorError, - * PaymentProcessorSessionResponse, - * // ... - * } from "@medusajs/medusa" - * // ... - * - * class MyPaymentService extends AbstractPaymentProcessor { - * // ... - * async updatePayment( - * context: PaymentProcessorContext - * ): Promise< - * void | - * PaymentProcessorError | - * PaymentProcessorSessionResponse - * > { - * // assuming client is an initialized client - * // communicating with a third-party service. - * const paymentId = context.paymentSessionData.id - * - * await this.client.update(paymentId, context) - * - * return { - * session_data: context.paymentSessionData - * } - * } - * } - */ - updatePayment( - context: PaymentProcessorContext - ): Promise - - /** - * This method is used to refund an order’s payment. This is typically triggered manually by the store operator from the admin. The refund amount might be the total order amount or part of it. - * - * This method is also used for refunding payments of a swap or a claim of an order, or when a request is sent to the [Refund Payment API Route](https://docs.medusajs.com/api/admin#payments_postpaymentspaymentrefunds). - * - * You can utilize this method to interact with the third-party provider and perform any actions necessary to refund the payment. - * - * @param {Record} paymentSessionData - The `data` field of a Payment. - * @param {number} refundAmount - the amount to refund. - * @returns Either an error object or a value that's stored in the `data` field of the Payment. - * - * @example - * import { - * PaymentProcessorError, - * // ... - * } from "@medusajs/medusa" - * // ... - * - * class MyPaymentService extends AbstractPaymentProcessor { - * // ... - * async refundPayment( - * paymentSessionData: Record, - * refundAmount: number - * ): Promise | PaymentProcessorError> { - * const paymentId = paymentSessionData.id - * - * // assuming client is an initialized client - * // communicating with a third-party service. - * const refundData = this.client.refund(paymentId, refundAmount) - * - * return { - * id: paymentId, - * ...refundData - * } - * } - * } - */ - refundPayment( - paymentSessionData: Record, - refundAmount: number - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > - - /** - * This method is used to authorize payment using the Payment Session of an order. This is called when the - * [cart is completed](https://docs.medusajs.com/api/store#carts_postcartscartcomplete) and before the order is created. - * - * This method is also used for authorizing payments of a swap of an order and when authorizing sessions in a payment collection. - * You can interact with a third-party provider and perform any actions necessary to authorize the payment. - * - * The payment authorization might require additional action from the customer before it is declared authorized. Once that additional action is performed, - * the `authorizePayment` method will be called again to validate that the payment is now fully authorized. So, make sure to implement it for this case as well, if necessary. - * - * Once the payment is authorized successfully and the Payment Session status is set to `authorized`, the associated order or swap can then be placed or created. - * If the payment authorization fails, then an error will be thrown and the order will not be created. - * - * :::note - * - * The payment authorization status is determined using the {@link getPaymentStatus} method. If the status is `requires_more`, then it means additional actions are required - * from the customer. If you try to create the order with a status that isn't `authorized`, the process will fail. - * - * ::: - * - * @param {Record} paymentSessionData - The `data` field of the payment session. - * @param {Record} context - - * The context of the authorization. It may include some of the following fields: - * - * - `ip`: The customer’s IP. - * - `idempotency_key`: The [Idempotency Key](https://docs.medusajs.com/modules/carts-and-checkout/payment#idempotency-key) that is associated with the current cart. It is useful when retrying payments, retrying checkout at a failed point, or for payments that require additional actions from the customer. - * - `cart_id`: The ID of a cart. This is only during operations like placing an order or creating a swap. - * - * @returns The authorization details or an error object. - * - * @example - * import { - * PaymentProcessorError, - * PaymentSessionStatus, - * // ... - * } from "@medusajs/medusa" - * // ... - * - * class MyPaymentService extends AbstractPaymentProcessor { - * // ... - * async authorizePayment( - * paymentSessionData: Record, - * context: Record - * ): Promise< - * PaymentProcessorError | - * { - * status: PaymentSessionStatus; - * data: Record; - * } - * > { - * try { - * await this.client.authorize(paymentSessionData.id) - * - * return { - * status: PaymentSessionStatus.AUTHORIZED, - * data: { - * id: paymentSessionData.id - * } - * } - * } catch (e) { - * return { - * error: e.message - * } - * } - * } - * } - */ - authorizePayment( - paymentSessionData: Record, - context: Record - ): Promise< - | PaymentProcessorError - | { - /** - * The status of the payment, which will be stored in the payment session's `status` field. - */ - status: PaymentSessionStatus - /** - * The `data` to be stored in the payment session's `data` field. - */ - data: PaymentProcessorSessionResponse["session_data"] - } - > - - /** - * This method is used to capture the payment amount of an order. This is typically triggered manually by the store operator from the admin. - * - * This method is also used for capturing payments of a swap of an order, or when a request is sent to the [Capture Payment API Route](https://docs.medusajs.com/api/admin#payments_postpaymentspaymentcapture). - * - * You can utilize this method to interact with the third-party provider and perform any actions necessary to capture the payment. - * - * @param {Record} paymentSessionData - The `data` field of the Payment for its first parameter. - * @returns Either an error object or a value that's stored in the `data` field of the Payment. - * - * @example - * import { - * PaymentProcessorError, - * // ... - * } from "@medusajs/medusa" - * // ... - * - * class MyPaymentService extends AbstractPaymentProcessor { - * // ... - * async capturePayment( - * paymentSessionData: Record - * ): Promise | PaymentProcessorError> { - * const paymentId = paymentSessionData.id - * - * // assuming client is an initialized client - * // communicating with a third-party service. - * const captureData = this.client.catch(paymentId) - * - * return { - * id: paymentId, - * ...captureData - * } - * } - * } - */ - capturePayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > - - /** - * This method is used to perform any actions necessary before a Payment Session is deleted. The Payment Session is deleted in one of the following cases: - * - * 1. When a request is sent to [delete the Payment Session](https://docs.medusajs.com/api/store#carts_deletecartscartpaymentsessionssession). - * 2. When the [Payment Session is refreshed](https://docs.medusajs.com/api/store#carts_postcartscartpaymentsessionssession). The Payment Session is deleted so that a newer one is initialized instead. - * 3. When the Payment Processor is no longer available. This generally happens when the store operator removes it from the available Payment Processor in the admin. - * 4. When the region of the store is changed based on the cart information and the Payment Processor is not available in the new region. - * - * @param {Record} paymentSessionData - The `data` field of the Payment Session. - * @returns Either an error object or an empty object. - * - * @example - * import { - * PaymentProcessorError, - * // ... - * } from "@medusajs/medusa" - * // ... - * - * class MyPaymentService extends AbstractPaymentProcessor { - * // ... - * async deletePayment( - * paymentSessionData: Record - * ): Promise | PaymentProcessorError> { - * const paymentId = paymentSessionData.id - * // assuming client is an initialized client - * // communicating with a third-party service. - * this.client.delete(paymentId) - * - * return {} - * } - * } - */ - deletePayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > - - /** - * This method is used to provide a uniform way of retrieving the payment information from the third-party provider. - * For example, in Stripe’s Payment Processor this method is used to retrieve the payment intent details from Stripe. - * - * @param {Record} paymentSessionData - - * The `data` field of a Payment Session. Make sure to store in the `data` field any necessary data that would allow you to retrieve the payment data from the third-party provider. - * @returns {Promise} The payment's data, typically retrieved from a third-party provider. - * - * @example - * import { - * PaymentProcessorError - * // ... - * } from "@medusajs/medusa" - * // ... - * - * class MyPaymentService extends AbstractPaymentProcessor { - * // ... - * async retrievePayment( - * paymentSessionData: Record - * ): Promise | PaymentProcessorError> { - * const paymentId = paymentSessionData.id - * - * // assuming client is an initialized client - * // communicating with a third-party service. - * return await this.client.retrieve(paymentId) - * } - * } - */ - retrievePayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > - - /** - * This method is used to cancel an order’s payment. This method is typically triggered by one of the following situations: - * - * 1. Before an order is placed and after the payment is authorized, an inventory check is done on products to ensure that products are still available for purchase. If the inventory check fails for any of the products, the payment is canceled. - * 2. If the store operator cancels the order from the admin. - * 3. When the payment of an order's swap is canceled. - * - * You can utilize this method to interact with the third-party provider and perform any actions necessary to cancel the payment. - * - * @param {Record} paymentSessionData - The `data` field of the Payment. - * @returns Either an error object or a value that's stored in the `data` field of the Payment. - * - * @example - * import { - * PaymentProcessorError, - * // ... - * } from "@medusajs/medusa" - * // ... - * - * class MyPaymentService extends AbstractPaymentProcessor { - * // ... - * async cancelPayment( - * paymentSessionData: Record - * ): Promise | PaymentProcessorError> { - * const paymentId = paymentSessionData.id - * - * // assuming client is an initialized client - * // communicating with a third-party service. - * const cancelData = this.client.cancel(paymentId) - * - * return { - * id: paymentId, - * ...cancelData - * } - * } - * } - */ - cancelPayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > - - /** - * This method is used to get the status of a Payment or a Payment Session. Its main usage is within the place order and create swap flows. - * If the status returned is not `authorized` within these flows, then the payment is considered failed and an error will be thrown, stopping the flow from completion. - * - * @param {Record} paymentSessionData - - * The `data` field of a Payment as a parameter. You can use this data to interact with the third-party provider to check the status of the payment if necessary. - * @returns {Promise} The status of the Payment or Payment Session. - * - * @example - * import { - * PaymentSessionStatus - * // ... - * } from "@medusajs/medusa" - * // ... - * - * class MyPaymentService extends AbstractPaymentProcessor { - * // ... - * async getPaymentStatus( - * paymentSessionData: Record - * ): Promise { - * const paymentId = paymentSessionData.id - * - * // assuming client is an initialized client - * // communicating with a third-party service. - * return await this.client.getStatus(paymentId) as PaymentSessionStatus - * } - * } - */ - getPaymentStatus( - paymentSessionData: Record - ): Promise - - /** - * This method is used to update the `data` field of a payment session. It's called when a request is sent to the - * [Update Payment Session API Route](https://docs.medusajs.com/api/store#carts_postcartscartpaymentsessionupdate), or when the `CartService`'s `updatePaymentSession` is used. - * - * This method can also be used to update the data in the third-party payment provider, if necessary. - * - * @param {string} sessionId - The ID of the payment session. - * @param {Record} data - The data to be updated in the payment session. - * @returns {Promise} the data to store in the `data` field of the payment session. - * You can keep the data as-is, or make changes to it by communicating with the third-party provider. - * - * @example - * import { - * PaymentProcessorError, - * PaymentProviderService, - * // ... - * } from "@medusajs/medusa" - * // ... - * - * class MyPaymentService extends AbstractPaymentProcessor { - * protected paymentProviderService: PaymentProviderService - * // ... - * constructor(container, options) { - * super(container) - * this.paymentProviderService = container.paymentProviderService - * // ... - * } - * // ... - * async updatePaymentData( - * sessionId: string, - * data: Record - * ): Promise< - * Record | - * PaymentProcessorError - * > { - * const paymentSession = await this.paymentProviderService.retrieveSession(sessionId) - * // assuming client is an initialized client - * // communicating with a third-party service. - * const clientPayment = await this.client.update(paymentSession.data.id, data) - * - * return { - * id: clientPayment.id - * } - * } - * } - */ - updatePaymentData( - sessionId: string, - data: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > -} - -export abstract class AbstractPaymentProcessor implements PaymentProcessor { - /** - * You can use the `constructor` of your Payment Processor to have access to different services in Medusa through [dependency injection](https://docs.medusajs.com/development/fundamentals/dependency-injection). - * - * You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs, - * you can initialize it in the constructor and use it in other methods in the service. - * - * Additionally, if you’re creating your Payment Processor as an external plugin to be installed on any Medusa backend and you want to access the options added for the plugin, - * you can access it in the constructor. The options are passed as a second parameter. - * - * @param {Record} container - An instance of `MedusaContainer` that allows you to access other resources, such as services, in your Medusa backend through [dependency injection](https://docs.medusajs.com/development/fundamentals/dependency-injection) - * @param {Record} config - If this payment processor is created in a plugin, the plugin's options are passed in this parameter. - * - * @example - * ```ts - * class MyPaymentService extends AbstractPaymentProcessor { - * // ... - * constructor(container, options) { - * super(container) - * // you can access options here - * - * // you can also initialize a client that - * // communicates with a third-party service. - * this.client = new Client(options) - * } - * // ... - * } - * ``` - */ - protected constructor( - protected readonly container: Record, - protected readonly config?: Record // eslint-disable-next-line @typescript-eslint/no-empty-function - ) {} - - /** - * @ignore - */ - static _isPaymentProcessor = true - - /** - * @ignore - */ - static isPaymentProcessor(object): boolean { - return object?.constructor?._isPaymentProcessor - } - - /** - * The `PaymentProvider` entity has 2 properties: `id` and `is_installed`. The `identifier` property in the payment processor service is used when the payment processor is added to the database. - * - * The value of this property is also used to reference the payment processor throughout Medusa. - * For example, it is used to [add a payment processor](https://docs.medusajs.com/api/admin#regions_postregionsregionpaymentproviders) to a region. - * - * ```ts - * class MyPaymentService extends AbstractPaymentProcessor { - * static identifier = "my-payment" - * // ... - * } - * ``` - */ - public static identifier: string - - /** - * @ignore - * - * Return a unique identifier to retrieve the payment plugin provider - */ - public getIdentifier(): string { - const ctr = this.constructor as typeof AbstractPaymentProcessor - - if (!ctr.identifier) { - throw new Error(`Missing static property "identifier".`) - } - - return ctr.identifier - } - - abstract capturePayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > - - abstract authorizePayment( - paymentSessionData: Record, - context: Record - ): Promise< - | PaymentProcessorError - | { - status: PaymentSessionStatus - data: PaymentProcessorSessionResponse["session_data"] - } - > - - abstract cancelPayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > - - abstract initiatePayment( - context: PaymentProcessorContext - ): Promise - - abstract deletePayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > - - abstract getPaymentStatus( - paymentSessionData: Record - ): Promise - - abstract refundPayment( - paymentSessionData: Record, - refundAmount: number - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > - - abstract retrievePayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > - - abstract updatePayment( - context: PaymentProcessorContext - ): Promise - - abstract updatePaymentData( - sessionId: string, - data: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > -} - -export function isPaymentProcessorError( - obj: any -): obj is PaymentProcessorError { - return obj && typeof obj === "object" && obj.error && obj.code && obj.detail -} diff --git a/packages/medusa/src/interfaces/payment-service.ts b/packages/medusa/src/interfaces/payment-service.ts deleted file mode 100644 index c71fd5f0e5..0000000000 --- a/packages/medusa/src/interfaces/payment-service.ts +++ /dev/null @@ -1,269 +0,0 @@ -import { TransactionBaseService } from "./transaction-base-service" -import { - Address, - Cart, - Customer, - Payment, - PaymentSession, - PaymentSessionStatus, - ShippingMethod, -} from "../models" -import { PaymentService } from "medusa-interfaces" - -export type Data = Record -export type PaymentData = Data -export type PaymentSessionData = Data - -export type PaymentContext = { - cart: { - context: Record - id: string - email: string - shipping_address: Address | null - shipping_methods: ShippingMethod[] - billing_address?: Address | null - } - currency_code: string - amount: number - resource_id: string - customer?: Customer - paymentSessionData: Record -} - -export type PaymentSessionResponse = { - update_requests: { customer_metadata: Record } - session_data: Record -} - -/** - * This will be @deprecated in the near future use the new PaymentProcessor interface instead - */ -export interface PaymentService extends TransactionBaseService { - getIdentifier(): string - - /** - * This will be @deprecated in the near future use PaymentProcessor.retrievePayment instead - * @param paymentSession - */ - getPaymentData(paymentSession: PaymentSession): Promise - - /** - * This will be @deprecated in the near future use PaymentProcessor.updatePayment instead - * @param paymentSessionData - * @param data - */ - updatePaymentData( - paymentSessionData: PaymentSessionData, - data: Data - ): Promise - - /** - * This will be @deprecated in the near future use PaymentProcessor.initiatePayment instead - * @param context The type of this argument is meant to be temporary and once the previous method signature - * will be removed, the type will only be PaymentContext instead of Cart & PaymentContext - */ - createPayment(context: Cart & PaymentContext): Promise - - /** - * This will be @deprecated in the near future use createPayment(context: `Cart & PaymentContext): Promise` instead - * @param cart - */ - createPayment(cart: Cart): Promise - - /** - * This will be @deprecated in the near future use PaymentProcessor.retrievePayment instead - * @param paymentData - */ - retrievePayment(paymentData: PaymentData): Promise - - updatePayment( - paymentSessionData: PaymentSessionData, - context: Cart & PaymentContext - ): Promise - - /** - * This will be @deprecated in the near future use PaymentProcessor.updatePayment instead - * @param paymentSessionData - * @param cart - */ - updatePayment( - paymentSessionData: PaymentSessionData, - cart: Cart - ): Promise - - /** - * This will be @deprecated in the near future use PaymentProcessor.authorizePayment instead - * @param paymentSession - * @param context - */ - authorizePayment( - paymentSession: PaymentSession, - context: Data - ): Promise<{ data: PaymentSessionData; status: PaymentSessionStatus }> - - /** - * This will be @deprecated in the near future use PaymentProcessor.capturePayment instead - * @param payment - */ - capturePayment(payment: Payment): Promise - - /** - * This will be @deprecated in the near future use PaymentProcessor.refundPayment instead - * @param payment - * @param refundAmount - */ - refundPayment(payment: Payment, refundAmount: number): Promise - - /** - * This will be @deprecated in the near future use PaymentProcessor.cancelPayment instead - * @param payment - */ - cancelPayment(payment: Payment): Promise - - /** - * This will be @deprecated in the near future use PaymentProcessor.cancelPayment instead - * @param paymentSession - */ - deletePayment(paymentSession: PaymentSession): Promise - - /** - * This will be @deprecated in the near future use PaymentProcessor.getSavedMethods instead - * @param customer - */ - retrieveSavedMethods(customer: Customer): Promise - - /** - * This will be @deprecated in the near future use PaymentProcessor.getPaymentStatus instead - * @param data - */ - getStatus(data: Data): Promise -} - -/** - * This will be @deprecated in the near future use the AbstractPaymentProcessor instead - */ -export abstract class AbstractPaymentService - extends TransactionBaseService - implements PaymentService -{ - static _isPaymentService = true - - /** - * @ignore - */ - static isPaymentService(object): boolean { - return object?.constructor?._isPaymentService - } - - protected constructor(container: unknown, config?: Record) { - super(container, config) - } - - public static identifier: string - - public getIdentifier(): string { - if (!(this.constructor as typeof AbstractPaymentService).identifier) { - throw new Error(`Missing static property "identifier".`) - } - return (this.constructor as typeof AbstractPaymentService).identifier - } - - /** - * @deprecated - */ - public abstract getPaymentData( - paymentSession: PaymentSession - ): Promise - - /** - * @deprecated - */ - public abstract updatePaymentData( - paymentSessionData: PaymentSessionData, - data: Data - ): Promise - - /** - * @param context The type of this argument is meant to be temporary and once the previous method signature - * will be removed, the type will only be PaymentContext instead of Cart & PaymentContext - */ - public abstract createPayment( - context: Cart & PaymentContext - ): Promise - - /** - * This will be @deprecated in the near future use `createPayment(context: Cart & PaymentContext): Promise` instead - * @param cart - */ - public abstract createPayment(cart: Cart): Promise - - /** - * @deprecated - */ - public abstract retrievePayment(paymentData: PaymentData): Promise - - /** - * @param paymentSessionData - * @param context The type of this argument is meant to be temporary and once the previous method signature - * will be removed, the type will only be PaymentContext instead of Cart & PaymentContext - * @return it return either a PaymentSessionResponse or PaymentSessionResponse["session_data"] to maintain backward compatibility - */ - public abstract updatePayment( - paymentSessionData: PaymentSessionData, - context: Cart & PaymentContext - ): Promise - - /** - * This will be @deprecated in the near future use `updatePayment(paymentSessionData: PaymentSessionData, context: Cart & PaymentContext): Promise` instead - * @param paymentSessionData - * @param cart - */ - public abstract updatePayment( - paymentSessionData: PaymentSessionData, - cart: Cart - ): Promise - - /** - * @deprecated - */ - public abstract authorizePayment( - paymentSession: PaymentSession, - context: Data - ): Promise<{ data: PaymentSessionData; status: PaymentSessionStatus }> - - /** - * This will be @deprecated in the near future - */ - public abstract capturePayment(payment: Payment): Promise - - /** - * This will be @deprecated in the near future - */ - public abstract refundPayment( - payment: Payment, - refundAmount: number - ): Promise - - /** - * This will be @deprecated in the near future - */ - public abstract cancelPayment(payment: Payment): Promise - - /** - * This will be @deprecated in the near future - */ - public abstract deletePayment(paymentSession: PaymentSession): Promise - - /** - * This will be @deprecated in the near future - */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - public async retrieveSavedMethods(customer: Customer): Promise { - return [] - } - - /** - * This will be @deprecated in the near future - */ - public abstract getStatus(data: Data): Promise -} diff --git a/packages/medusa/src/interfaces/price-selection-strategy.ts b/packages/medusa/src/interfaces/price-selection-strategy.ts deleted file mode 100644 index 4070c6371e..0000000000 --- a/packages/medusa/src/interfaces/price-selection-strategy.ts +++ /dev/null @@ -1,374 +0,0 @@ -import { MoneyAmount } from "../models" -import { PriceListType } from "../types/price-list" -import { TaxServiceRate } from "../types/tax-service" -import { ITransactionBaseService, MedusaContainer } from "@medusajs/types" -import { TransactionBaseService } from "./transaction-base-service" - -/** - * ## Overview - * - * The price selection strategy retrieves the best price for a product variant for a specific context such as selected region, taxes applied, - * the quantity in cart, and more. - * - * Medusa provides a default price selection strategy, but you can override it. A price selecion strategy is a TypeScript or JavaScript file in the `src/strategies` directory of your Medusa backend project. It exports a class that extends the `AbstractPriceSelectionStrategy` class. - * - * For example: - * - * ```ts title="src/strategies/price.ts" - * import { - * AbstractPriceSelectionStrategy, - * PriceSelectionContext, - * PriceSelectionResult, - * } from "@medusajs/medusa" - * - * export default class MyStrategy extends - * AbstractPriceSelectionStrategy { - * - * async calculateVariantPrice( - * data: { - * variantId: string; - * quantity?: number - * }[], - * context: PriceSelectionContext - * ): Promise> { - * throw new Error("Method not implemented.") - * } - * } - * ``` - * - * --- - */ -export interface IPriceSelectionStrategy extends ITransactionBaseService { - /** - * This method retrieves one or more product variants' prices. It's used when retrieving product variants or their associated line items. - * It's also used when retrieving other entities that product variants and line items belong to, such as products and carts respectively. - * - * @param data - The necessary data to perform the price selection for each variant ID. - * @param context - The context of the price selection. - * @returns {Promise>} A map, each key is an ID of a variant, and its value is an object holding the price selection result. - * - * @example - * For example, here's a snippet of how the price selection strategy is implemented in the Medusa backend: - * - * ```ts - * import { - * AbstractPriceSelectionStrategy, - * CustomerService, - * PriceSelectionContext, - * PriceSelectionResult, - * } from "@medusajs/medusa" - * - * type InjectedDependencies = { - * customerService: CustomerService - * } - * - * export default class MyStrategy extends - * AbstractPriceSelectionStrategy { - * - * async calculateVariantPrice( - * data: { - * variantId: string - * quantity?: number - * }[], - * context: PriceSelectionContext - * ): Promise> { - * const dataMap = new Map(data.map((d) => [d.variantId, d])) - * - * const cacheKeysMap = new Map( - * data.map(({ variantId, quantity }) => [ - * variantId, - * this.getCacheKey(variantId, { ...context, quantity }), - * ]) - * ) - * - * const nonCachedData: { - * variantId: string - * quantity?: number - * }[] = [] - * - * const variantPricesMap = new Map() - * - * if (!context.ignore_cache) { - * const cacheHits = await promiseAll( - * [...cacheKeysMap].map(async ([, cacheKey]) => { - * return await this.cacheService_.get(cacheKey) - * }) - * ) - * - * if (!cacheHits.length) { - * nonCachedData.push(...dataMap.values()) - * } - * - * for (const [index, cacheHit] of cacheHits.entries()) { - * const variantId = data[index].variantId - * if (cacheHit) { - * variantPricesMap.set(variantId, cacheHit) - * continue - * } - * - * nonCachedData.push(dataMap.get(variantId)!) - * } - * } else { - * nonCachedData.push(...dataMap.values()) - * } - * - * let results: Map = new Map() - * - * if ( - * this.featureFlagRouter_.isFeatureEnabled( - * TaxInclusivePricingFeatureFlag.key - * ) - * ) { - * results = await this.calculateVariantPrice_new(nonCachedData, context) - * } else { - * results = await this.calculateVariantPrice_old(nonCachedData, context) - * } - * - * await promiseAll( - * [...results].map(async ([variantId, prices]) => { - * variantPricesMap.set(variantId, prices) - * if (!context.ignore_cache) { - * await this.cacheService_.set(cacheKeysMap.get(variantId)!, prices) - * } - * }) - * ) - * - * return variantPricesMap - * } - * - * // ... - * } - * ``` - */ - calculateVariantPrice( - data: { - /** - * The ID of the variant to retrieve its prices. - */ - variantId: string - /** - * The variant's quantity in the cart, if available. - */ - quantity?: number - }[], - /** - * Details relevant to determine the correct pricing of the variant - */ - context: PriceSelectionContext - ): Promise> - - /** - * This method is called when prices of product variants have changed. - * You can use it to invalidate prices stored in the cache. - * - * @param {string[]} variantIds - The IDs of the updated variants. - * @returns {Promise} Resolves after any necessary actions are performed. - * - * @example - * For example, this is how this method is implemented in the Medusa backend's default - * price selection strategy: - * - * ```ts - * import { - * AbstractPriceSelectionStrategy, - * CustomerService, - * } from "@medusajs/medusa" - * import { promiseAll } from "@medusajs/utils" - * - * type InjectedDependencies = { - * customerService: CustomerService - * } - * - * export default class MyStrategy extends - * AbstractPriceSelectionStrategy { - * - * public async onVariantsPricesUpdate(variantIds: string[]): Promise { - * await promiseAll( - * variantIds.map( - * async (id: string) => await this.cacheService_.invalidate(`ps:${id}:*`) - * ) - * ) - * } - * - * // ... - * } - * ``` - * - * :::note - * - * Learn more about the cache service in [this documentation](https://docs.medusajs.com/development/cache/overview). - * - * ::: - */ - onVariantsPricesUpdate(variantIds: string[]): Promise -} - -/** - * @parentIgnore activeManager_,atomicPhase_,shouldRetryTransaction_,withTransaction - */ -export abstract class AbstractPriceSelectionStrategy - extends TransactionBaseService - implements IPriceSelectionStrategy -{ - /** - * @ignore - */ - static _isPriceSelectionStrategy = true - - /** - * @ignore - */ - static isPriceSelectionStrategy(object): boolean { - return object?.constructor?._isPriceSelectionStrategy - } - - /** - * You can use the `constructor` of your price-selection strategy to access the different services in Medusa through dependency injection. - * - * @param {Record} container - An instance of `MedusaContainer` that allows you to access other resources, such as services, in your Medusa backend. - * @param {Record} config - If this price-selection strategy is created in a plugin, the plugin's options are passed in this parameter. - * - * @example - * // ... - * import { - * AbstractPriceSelectionStrategy, - * CustomerService, - * } from "@medusajs/medusa" - * type InjectedDependencies = { - * customerService: CustomerService - * } - * - * class MyStrategy extends - * AbstractPriceSelectionStrategy { - * - * protected customerService_: CustomerService - * - * constructor(container: InjectedDependencies) { - * super(container) - * this.customerService_ = container.customerService - * } - * - * // ... - * } - * - * export default MyStrategy - */ - protected constructor( - protected readonly container: Record, - protected readonly config?: Record // eslint-disable-next-line @typescript-eslint/no-empty-function - ) { - super(container, config) - } - - public abstract calculateVariantPrice( - data: { - variantId: string - /** - * @ignore - */ - taxRates: TaxServiceRate[] - quantity?: number - }[], - context: PriceSelectionContext - ): Promise> - - public async onVariantsPricesUpdate(variantIds: string[]): Promise { - return void 0 - } -} - -/** - * @interface - * - * The context of the price selection. - */ -export type PriceSelectionContext = { - /** - * The cart's ID. This is used when the prices are being retrieved for the variant of a line item, - * as it is used to determine the current region and currency code of the context. - */ - cart_id?: string - /** - * The ID of the customer viewing the variant. - */ - customer_id?: string - /** - * The region's ID. - */ - region_id?: string - /** - * The quantity of the item in the cart. This is used to filter out price lists that have - * `min_quantity` or `max_quantity` conditions set. - */ - quantity?: number - /** - * The currency code the customer is using. - */ - currency_code?: string - /** - * Whether the price list's prices should be retrieved or not. - */ - include_discount_prices?: boolean - /** - * The tax rates to be applied. This is only used for - * [Tax-Inclusive Pricing](https://docs.medusajs.com/modules/taxes/inclusive-pricing). - */ - tax_rates?: TaxServiceRate[] - /** - * Whether to calculate the prices even if the value of an earlier price calculation - * is available in the cache. - */ - ignore_cache?: boolean -} - -/** - * @enum - * - * The type of default price type. - */ -enum DefaultPriceType { - /** - * The `calculatedPrice` is the original price. - */ - DEFAULT = "default", -} - -// both exports are needed in order to get proper typing of the calculatedPriceType field. -export type PriceType = DefaultPriceType | PriceListType -export const PriceType = { ...DefaultPriceType, ...PriceListType } - -/** - * @interface - * - * The price selection result of a variant. - */ -export type PriceSelectionResult = { - /** - * The original price of the variant which depends on the selected region or currency code in the context object. - * If both region ID and currency code are available in the context object, the region has higher precedence. - */ - originalPrice: number | null - /** - * Whether the original price includes taxes or not. This is only available - * for [Tax-Inclusive Pricing](https://docs.medusajs.com/modules/taxes/inclusive-pricing). - */ - originalPriceIncludesTax?: boolean | null - /** - * The lowest price among the prices of the product variant retrieved using the context object. - */ - calculatedPrice: number | null - /** - * Whether the calculated price includes taxes or not. - * This is only available for [Tax-Inclusive Pricing](https://docs.medusajs.com/modules/taxes/inclusive-pricing). - */ - calculatedPriceIncludesTax?: boolean | null - /** - * The type of price applied in `calculatedPrice`. - */ - calculatedPriceType?: PriceType - /** - * All possible prices of the variant that are retrieved using the `context` object. - * It can include its original price and its price lists if there are any. - */ - prices: MoneyAmount[] -} diff --git a/packages/medusa/src/interfaces/tax-calculation-strategy.ts b/packages/medusa/src/interfaces/tax-calculation-strategy.ts deleted file mode 100644 index 9ab102f5e4..0000000000 --- a/packages/medusa/src/interfaces/tax-calculation-strategy.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { LineItem } from "../models/line-item" -import { TaxCalculationContext } from "./tax-service" -import { LineItemTaxLine } from "../models/line-item-tax-line" -import { ShippingMethodTaxLine } from "../models/shipping-method-tax-line" -import { TransactionBaseService } from "./transaction-base-service" -import { MedusaContainer } from "@medusajs/types" - -/** - * ## Overview - * - * A tax calculation strategy is used to calculate taxes when calculating a cart's totals. The Medusa - * backend provides a tax calculation strategy that handles calculating the taxes, taking into account the - * defined tax rates and settings such as whether tax-inclusive pricing is enabled. - * - * You can override the tax calculation strategy to implement different calculation logic or to - * integrate a third-party service that handles the tax calculation. You can override it either - * in a Medusa backend setup or in a plugin. - * - * A tax calculation strategy should be defined in a TypeScript or JavaScript file created under the `src/strategies` directory. - * The class must also implement the `ITaxCalculationStrategy` interface imported from the `@medusajs/medusa` package. - * - * For example, you can create the file `src/strategies/tax-calculation.ts` with the following content: - * - * ```ts title="src/strategies/tax-calculation.ts" - * import { - * ITaxCalculationStrategy, - * LineItem, - * LineItemTaxLine, - * ShippingMethodTaxLine, - * TaxCalculationContext, - * } from "@medusajs/medusa" - * - * class TaxCalculationStrategy - * implements ITaxCalculationStrategy { - * - * async calculate( - * items: LineItem[], - * taxLines: (ShippingMethodTaxLine | LineItemTaxLine)[], - * calculationContext: TaxCalculationContext - * ): Promise { - * throw new Error("Method not implemented.") - * } - * - * } - * - * export default TaxCalculationStrategy - * ``` - * - * --- - */ -export interface ITaxCalculationStrategy { - /** - * This method calculates the tax amount for a given set of line items under applicable - * tax conditions and calculation contexts. - * - * This method is used whenever taxes are calculated. If automatic tax calculation is disabled in a region, - * then it's only triggered when taxes are calculated manually as explained in - * [this guide](https://docs.medusajs.com/modules/taxes/storefront/manual-calculation). - * - * @param {LineItem[]} items - The line items to calculate the tax total for. - * @param {(ShippingMethodTaxLine | LineItemTaxLine)[]} taxLines - The tax lines used for the calculation - * @param {TaxCalculationContext} calculationContext - Other details relevant for the calculation - * @returns {Promise} The calculated tax total - * - * @example - * An example of the general implementation of this method in the Medusa backend's tax calculation strategy: - * - * ```ts - * async calculate( - * items: LineItem[], - * taxLines: (ShippingMethodTaxLine | LineItemTaxLine)[], - * calculationContext: TaxCalculationContext - * ): Promise { - * const lineItemsTaxLines = taxLines.filter( - * (tl) => "item_id" in tl - * ) as LineItemTaxLine[] - * const shippingMethodsTaxLines = taxLines.filter( - * (tl) => "shipping_method_id" in tl - * ) as ShippingMethodTaxLine[] - * - * const lineItemsTax = this.calculateLineItemsTax( - * items, - * lineItemsTaxLines, - * calculationContext - * ) - * - * const shippingMethodsTax = this.calculateShippingMethodsTax( - * calculationContext.shipping_methods, - * shippingMethodsTaxLines - * ) - * - * return Math.round(lineItemsTax + shippingMethodsTax) - * } - * ``` - */ - calculate( - items: LineItem[], - taxLines: (ShippingMethodTaxLine | LineItemTaxLine)[], - calculationContext: TaxCalculationContext - ): Promise -} - -/** - * @parentIgnore activeManager_,atomicPhase_,shouldRetryTransaction_,withTransaction - */ -export abstract class AbstractTaxCalculationStrategy - extends TransactionBaseService - implements ITaxCalculationStrategy -{ - /** - * @ignore - */ - static _isTaxCalculationStrategy = true - - /** - * @ignore - */ - static isTaxCalculationStrategy(object): boolean { - return ( - typeof object.calculate === "function" || - object?.constructor?._isTaxCalculationStrategy - ) - } - - /** - * You can use the `constructor` of your tax calculation strategy to access the different services in Medusa through dependency injection. - * - * You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs, you can initialize it in the constructor and use it in other methods in the service. - * Additionally, if you’re creating your tax calculation strategy as an external plugin to be installed on any Medusa backend and you want to access the options added for the plugin, you can access it in the constructor. - * - * @param {Record} container - An instance of `MedusaContainer` that allows you to access other resources, such as services, in your Medusa backend. - * @param {Record} config - If this tax calculation strategy is created in a plugin, the plugin's options are passed in this parameter. - * - * @example - * import { - * ITaxCalculationStrategy, - * LineItemService, - * } from "@medusajs/medusa" - * - * type InjectedDependencies = { - * lineItemService: LineItemService - * } - * - * class TaxCalculationStrategy - * implements ITaxCalculationStrategy { - * - * protected readonly lineItemService_: LineItemService - * - * constructor({ lineItemService }: InjectedDependencies) { - * this.lineItemService_ = lineItemService - * } - * - * // ... - * } - * - * export default TaxCalculationStrategy - */ - protected constructor( - protected readonly container: Record, - protected readonly config?: Record // eslint-disable-next-line @typescript-eslint/no-empty-function - ) { - super(container, config) - } - - abstract calculate( - items: LineItem[], - taxLines: (ShippingMethodTaxLine | LineItemTaxLine)[], - calculationContext: TaxCalculationContext - ): Promise -} diff --git a/packages/medusa/src/interfaces/tax-service.ts b/packages/medusa/src/interfaces/tax-service.ts deleted file mode 100644 index c4dff54c69..0000000000 --- a/packages/medusa/src/interfaces/tax-service.ts +++ /dev/null @@ -1,259 +0,0 @@ -import { LineItem } from "../models/line-item" -import { Region } from "../models/region" -import { Address } from "../models/address" -import { ShippingMethod } from "../models/shipping-method" -import { Customer } from "../models/customer" -import { ProviderTaxLine, TaxServiceRate } from "../types/tax-service" -import { LineAllocationsMap } from "../types/totals" -import { TransactionBaseService } from "./transaction-base-service" -import { MedusaContainer } from "@medusajs/types" - -/** - * A shipping method and the tax rates configured to apply to the - * shipping method. - */ -export type ShippingTaxCalculationLine = { - /** - * The shipping method to calculate taxes for. - */ - shipping_method: ShippingMethod - /** - * The rates applicable on the shipping method. - */ - rates: TaxServiceRate[] -} - -/** - * A line item and the tax rates configured to apply to the - * product contained in the line item. - */ -export type ItemTaxCalculationLine = { - /** - * The line item to calculate taxes for. - */ - item: LineItem - /** - * The rates applicable on the item. - */ - rates: TaxServiceRate[] -} - -/** - * Information relevant to a tax calculation, such as the shipping address where - * the items are going. - */ -export type TaxCalculationContext = { - /** - * The shipping address used in the cart. - */ - shipping_address: Address | null - /** - * The customer that the cart belongs to. - */ - customer: Customer - /** - * The cart's region. - */ - region: Region - /** - * Whether the cart is used in a return flow. - */ - is_return: boolean - /** - * The shipping methods used in the cart. - */ - shipping_methods: ShippingMethod[] - /** - * The gift cards and discounts applied on line items. - * Each object key or property is an ID of a line item - */ - allocation_map: LineAllocationsMap -} - -/** - * ## Overview - * - * A tax provider is used to retrieve the tax lines in a cart. The Medusa backend provides a default `system` provider. You can create your own tax provider, - * either in a plugin or directly in your Medusa backend, then use it in any region. - * - * A tax provider class is defined in a TypeScript or JavaScript file under the `src/services` directory and the class must extend the - * `AbstractTaxService` class imported from `@medusajs/medusa`. The file's name is the tax provider's class name as a slug and without the word `Service`. - * - * For example, you can create the file `src/services/my-tax.ts` with the following content: - * - * ```ts title="src/services/my-tax.ts" - * import { - * AbstractTaxService, - * ItemTaxCalculationLine, - * ShippingTaxCalculationLine, - * TaxCalculationContext, - * } from "@medusajs/medusa" - * import { - * ProviderTaxLine, - * } from "@medusajs/medusa/dist/types/tax-service" - * - * class MyTaxService extends AbstractTaxService { - * async getTaxLines( - * itemLines: ItemTaxCalculationLine[], - * shippingLines: ShippingTaxCalculationLine[], - * context: TaxCalculationContext): - * Promise { - * throw new Error("Method not implemented.") - * } - * } - * - * export default MyTaxService - * ``` - * - * --- - * - * ## Identifier Property - * - * The `TaxProvider` entity has 2 properties: `identifier` and `is_installed`. The `identifier` property in the tax provider service is used when the tax provider is added to the database. - * - * The value of this property is also used to reference the tax provider throughout Medusa. For example, it is used to [change the tax provider](https://docs.medusajs.com/modules/taxes/admin/manage-tax-settings#change-tax-provider-of-a-region) to a region. - * - * ```ts title="src/services/my-tax.ts" - * class MyTaxService extends AbstractTaxService { - * static identifier = "my-tax" - * // ... - * } - * ``` - * - * --- - */ -export interface ITaxService { - /** - * This method is used when retrieving the tax lines for line items and shipping methods. - * This occurs during checkout or when calculating totals for orders, swaps, or returns. - * - * @param {ItemTaxCalculationLine[]} itemLines - The line item lines to calculate taxes for. - * @param {ShippingTaxCalculationLine[]} shippingLines - The shipping method lines to calculate taxes for. - * @param {TaxCalculationContext} context - Context relevant and useful for the taxes calculation. - * @return {Promise} The list of calculated line item and shipping method tax lines. - * If an item in the array has the `shipping_method_id` property, then it's a shipping method tax line. Otherwise, if it has - * the `item_id` property, then it's a line item tax line. - * - * @example - * An example of how this method is implemented in the `system` provider implemented in the Medusa backend: - * - * ```ts - * // ... - * - * class SystemTaxService extends AbstractTaxService { - * // ... - * - * async getTaxLines( - * itemLines: ItemTaxCalculationLine[], - * shippingLines: ShippingTaxCalculationLine[], - * context: TaxCalculationContext - * ): Promise { - * let taxLines: ProviderTaxLine[] = itemLines.flatMap((l) => { - * return l.rates.map((r) => ({ - * rate: r.rate || 0, - * name: r.name, - * code: r.code, - * item_id: l.item.id, - * })) - * }) - * - * taxLines = taxLines.concat( - * shippingLines.flatMap((l) => { - * return l.rates.map((r) => ({ - * rate: r.rate || 0, - * name: r.name, - * code: r.code, - * shipping_method_id: l.shipping_method.id, - * })) - * }) - * ) - * - * return taxLines - * } - * } - * ``` - */ - getTaxLines( - itemLines: ItemTaxCalculationLine[], - shippingLines: ShippingTaxCalculationLine[], - context: TaxCalculationContext - ): Promise -} - -/** - * @parentIgnore activeManager_,atomicPhase_,shouldRetryTransaction_,withTransaction - */ -export abstract class AbstractTaxService - extends TransactionBaseService - implements ITaxService -{ - /** - * @ignore - */ - static _isTaxService = true - protected static identifier: string - - /** - * @ignore - */ - static isTaxService(object): boolean { - return object?.constructor?._isTaxService - } - - /** - * You can use the `constructor` of your tax provider to access the different services in Medusa through dependency injection. - * - * You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs, you can initialize it in the constructor and use it in other methods in the service. - * Additionally, if you’re creating your tax provider as an external plugin to be installed on any Medusa backend and you want to access the options added for the plugin, you can access it in the constructor. - * - * @param {Record} container - An instance of `MedusaContainer` that allows you to access other resources, such as services, in your Medusa backend. - * @param {Record} config - If this tax provider is created in a plugin, the plugin's options are passed in this parameter. - * - * @example - * // ... - * import { LineItemService } from "@medusajs/medusa" - * - * type InjectedDependencies = { - * lineItemService: LineItemService - * } - * - * class MyTaxService extends AbstractTaxService { - * protected readonly lineItemService_: LineItemService - * - * constructor({ lineItemService }: InjectedDependencies) { - * super(arguments[0]) - * this.lineItemService_ = lineItemService - * - * // you can also initialize a client that - * // communicates with a third-party service. - * this.client = new Client(options) - * } - * - * // ... - * } - * - * export default MyTaxService - */ - protected constructor( - protected readonly container: Record, - protected readonly config?: Record // eslint-disable-next-line @typescript-eslint/no-empty-function - ) { - super(container, config) - } - - /** - * @ignore - */ - public getIdentifier(): string { - if (!(this.constructor as typeof AbstractTaxService).identifier) { - throw new Error(`Missing static property "identifier".`) - } - return (this.constructor as typeof AbstractTaxService).identifier - } - - public abstract getTaxLines( - itemLines: ItemTaxCalculationLine[], - shippingLines: ShippingTaxCalculationLine[], - context: TaxCalculationContext - ): Promise -} diff --git a/packages/medusa/src/loaders/__tests__/default.spec.ts b/packages/medusa/src/loaders/__tests__/default.spec.ts deleted file mode 100644 index 6b3278da47..0000000000 --- a/packages/medusa/src/loaders/__tests__/default.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { asValue, createContainer } from "awilix" -import { MockManager, MockRepository } from "medusa-test-utils" -import { StoreServiceMock } from "../../services/__mocks__/store" -import { - ShippingProfileServiceMock -} from "../../services/__mocks__/shipping-profile" -import Logger from "../logger" -import featureFlagsLoader from "../feature-flags" -import { default as defaultLoader } from "../defaults" -import { SalesChannelServiceMock } from "../../services/__mocks__/sales-channel" -import { - PaymentProviderServiceMock -} from "../../services/__mocks__/payment-provider" - -describe("default", () => { - describe("sales channel default", () => { - let featureFlagRouter - const container = createContainer() - - beforeAll(async () => { - featureFlagRouter = await featureFlagsLoader( - { - featureFlags: { - sales_channels: true, - }, - }, - Logger - ) - - container.register({ - storeService: asValue(StoreServiceMock), - currencyRepository: asValue(MockRepository()), - countryRepository: asValue( - MockRepository({ - count: jest.fn().mockImplementation(() => 1), - }) - ), - shippingProfileService: asValue(ShippingProfileServiceMock), - salesChannelService: asValue(SalesChannelServiceMock), - logger: asValue(Logger), - featureFlagRouter: asValue(featureFlagRouter), - manager: asValue(MockManager), - paymentProviders: asValue([]), - paymentProviderService: asValue(PaymentProviderServiceMock), - notificationProviders: asValue([]), - notificationService: asValue({ - withTransaction: function () { - return this - }, - registerInstalledProviders: jest.fn(), - }), - fulfillmentProviders: asValue([]), - fulfillmentProviderService: asValue({ - withTransaction: function () { - return this - }, - registerInstalledProviders: jest.fn(), - }), - taxProviders: asValue([]), - taxProviderService: asValue({ - withTransaction: function () { - return this - }, - registerInstalledProviders: jest.fn(), - }), - }) - }) - - it("should create a new default sales channel attach to the store", async () => { - await defaultLoader({ container }) - expect(SalesChannelServiceMock.createDefault).toHaveBeenCalledTimes(1) - expect(SalesChannelServiceMock.createDefault).toHaveBeenCalledTimes(1) - }) - }) -}) diff --git a/packages/medusa/src/loaders/__tests__/plugins.spec.ts b/packages/medusa/src/loaders/__tests__/plugins.spec.ts index 373c438ec4..4d7b93972d 100644 --- a/packages/medusa/src/loaders/__tests__/plugins.spec.ts +++ b/packages/medusa/src/loaders/__tests__/plugins.spec.ts @@ -32,7 +32,7 @@ const buildTransactionBaseServiceServiceTemplate = (name: string) => { ` } -const buildBatchJobStrategyTemplate = (name: string, type: string): string => { +/*const buildBatchJobStrategyTemplate = (name: string, type: string): string => { return ` import { AbstractBatchJobStrategy } from "../../../../interfaces/batch-job-strategy" @@ -92,7 +92,7 @@ const buildTaxCalcStrategyTemplate = (name: string): string => { export default ${name}TaxCalculationStrategy ` -} +}*/ // ***** UTILS ***** @@ -113,7 +113,7 @@ function asArray( // ***** TESTS ***** -describe("plugins loader", () => { +describe.skip("plugins loader", () => { const container = createMedusaContainer() container.register("logger", asValue(Logger)) @@ -139,7 +139,7 @@ describe("plugins loader", () => { mode: "777", recursive: true, }) - writeFileSync( + /*writeFileSync( resolve( getFolderTestTargetDirectoryPath("strategies"), "test-batch-1.js" @@ -170,7 +170,7 @@ describe("plugins loader", () => { writeFileSync( resolve(getFolderTestTargetDirectoryPath("strategies"), "test-tax.js"), buildTaxCalcStrategyTemplate("test") - ) + )*/ try { await registerStrategies(pluginsDetails, container) @@ -187,7 +187,7 @@ describe("plugins loader", () => { expect(err).toBeFalsy() }) - it("registers price selection strategy", () => { + it.skip("registers price selection strategy", () => { const priceSelectionStrategy = container.resolve( "priceSelectionStrategy" ) as (...args: unknown[]) => any @@ -198,7 +198,7 @@ describe("plugins loader", () => { ) }) - it("registers tax calculation strategy", () => { + it.skip("registers tax calculation strategy", () => { const taxCalculationStrategy = container.resolve( "taxCalculationStrategy" ) as (...args: unknown[]) => any @@ -209,7 +209,7 @@ describe("plugins loader", () => { ) }) - it("registers batch job strategies as single array", () => { + it.skip("registers batch job strategies as single array", () => { const batchJobStrategies = container.resolve("batchJobStrategies") as ( ...args: unknown[] ) => any @@ -219,7 +219,7 @@ describe("plugins loader", () => { expect(batchJobStrategies.length).toBe(3) }) - it("registers batch job strategies by type and only keep the last", () => { + it.skip("registers batch job strategies by type and only keep the last", () => { const batchJobStrategy = container.resolve("batchType_type-1") as ( ...args: unknown[] ) => any @@ -232,7 +232,7 @@ describe("plugins loader", () => { ) }) - it("registers batch job strategies by identifier", () => { + it.skip("registers batch job strategies by identifier", () => { const batchJobStrategy = container.resolve( "batch_testBatch3-identifier" ) as (...args: unknown[]) => any diff --git a/packages/medusa/src/loaders/api.ts b/packages/medusa/src/loaders/api.ts index cbad34afe6..5125aadc06 100644 --- a/packages/medusa/src/loaders/api.ts +++ b/packages/medusa/src/loaders/api.ts @@ -1,10 +1,8 @@ -import { FeatureFlagUtils, FlagRouter } from "@medusajs/utils" +import { FlagRouter } from "@medusajs/utils" import { AwilixContainer } from "awilix" -import bodyParser from "body-parser" import { Express } from "express" import path from "path" import qs from "qs" -import routes from "../api" import { ConfigModule } from "../types/global" import { RoutesLoader } from "./helpers/routing" @@ -33,27 +31,22 @@ export default async ({ next() }) - if (featureFlagRouter?.isFeatureEnabled(FeatureFlagUtils.MedusaV2Flag.key)) { - // TODO: Figure out why this is causing issues with test when placed inside ./api.ts - // Adding this here temporarily - // Test: (packages/medusa/src/api/routes/admin/currencies/update-currency.ts) - try { - /** - * Register the Medusa CORE API routes using the file based routing. - */ - await new RoutesLoader({ - app: app, - rootDir: path.join(__dirname, "../api-v2"), - configModule, - }).load() - } catch (err) { - throw Error( - "An error occurred while registering Medusa Core API Routes. See error in logs for more details." - ) - } - } else { - app.use(bodyParser.json()) - app.use("/", routes(container, configModule.projectConfig)) + // TODO: Figure out why this is causing issues with test when placed inside ./api.ts + // Adding this here temporarily + // Test: (packages/medusa/src/api/routes/admin/currencies/update-currency.ts) + try { + /** + * Register the Medusa CORE API routes using the file based routing. + */ + await new RoutesLoader({ + app: app, + rootDir: path.join(__dirname, "../api-v2"), + configModule, + }).load() + } catch (err) { + throw Error( + "An error occurred while registering Medusa Core API Routes. See error in logs for more details." + ) } return app diff --git a/packages/medusa/src/loaders/database.ts b/packages/medusa/src/loaders/database.ts index 447d0da66e..f356c3d780 100644 --- a/packages/medusa/src/loaders/database.ts +++ b/packages/medusa/src/loaders/database.ts @@ -7,7 +7,6 @@ import { TreeRepository, } from "typeorm" import { ConfigModule } from "../types/global" -import "../utils/naming-strategy" type Options = { configModule: ConfigModule diff --git a/packages/medusa/src/loaders/defaults.ts b/packages/medusa/src/loaders/defaults.ts deleted file mode 100644 index 07fcdb6271..0000000000 --- a/packages/medusa/src/loaders/defaults.ts +++ /dev/null @@ -1,288 +0,0 @@ -import { FlagRouter, promiseAll } from "@medusajs/utils" -import { AwilixContainer } from "awilix" -import { - BaseFulfillmentService, - BaseNotificationService, - BasePaymentService, -} from "medusa-interfaces" -import { EntityManager } from "typeorm" -import { - AbstractFulfillmentService, - AbstractPaymentProcessor, - AbstractPaymentService, - AbstractTaxService, -} from "../interfaces" -import { CountryRepository } from "../repositories/country" -import { CurrencyRepository } from "../repositories/currency" -import { - FulfillmentProviderService, - NotificationService, - PaymentProviderService, - SalesChannelService, - ShippingProfileService, - StoreService, - TaxProviderService, -} from "../services" -import { Logger } from "../types/global" -import { countries } from "../utils/countries" -import { currencies } from "../utils/currencies" -import SalesChannelFeatureFlag from "./feature-flags/sales-channels" - -const silentResolution = ( - container: AwilixContainer, - name: string, - logger: Logger -): T | never | undefined => { - try { - return container.resolve(name) - } catch (err) { - if (err.name !== "AwilixResolutionError") { - throw err - } else { - let identifier - switch (name) { - case "paymentProviders": - identifier = "payment" - break - case "notificationProviders": - identifier = "notification" - break - case "fulfillmentProviders": - identifier = "fulfillment" - break - default: - identifier = name - } - logger.warn( - `You don't have any ${identifier} provider plugins installed. You may want to add one to your project.` - ) - } - return - } -} - -export default async ({ - container, -}: { - container: AwilixContainer -}): Promise => { - const storeService = container.resolve("storeService") - const currencyRepository = - container.resolve("currencyRepository") - const countryRepository = - container.resolve("countryRepository") - const profileService = container.resolve( - "shippingProfileService" - ) - const salesChannelService = container.resolve( - "salesChannelService" - ) - const logger = container.resolve("logger") - const featureFlagRouter = container.resolve("featureFlagRouter") - - const entityManager = container.resolve("manager") - - await entityManager.transaction(async (manager: EntityManager) => { - const countryRepo = manager.withRepository(countryRepository) - const hasCountries = !!(await countryRepo.count()) - if (!hasCountries) { - for (const c of countries) { - const query = `INSERT INTO "country" ("iso_2", "iso_3", "num_code", "name", "display_name") - VALUES ($1, $2, $3, $4, $5)` - - const iso2 = c.alpha2.toLowerCase() - const iso3 = c.alpha3.toLowerCase() - const numeric = c.numeric - const name = c.name.toUpperCase() - const display = c.name - - await manager.queryRunner?.query(query, [ - iso2, - iso3, - numeric, - name, - display, - ]) - } - } - }) - - await entityManager.transaction(async (manager: EntityManager) => { - const currencyRepo = manager.withRepository(currencyRepository) - const hasCurrencies = !!(await currencyRepo.count()) - if (!hasCurrencies) { - for (const [, c] of Object.entries(currencies)) { - const query = `INSERT INTO "currency" ("code", "symbol", "symbol_native", "name") - VALUES ($1, $2, $3, $4)` - - const code = c.code.toLowerCase() - const sym = c.symbol - const nat = c.symbol_native - const name = c.name - - await manager.queryRunner?.query(query, [code, sym, nat, name]) - } - } - }) - - await entityManager.transaction(async (manager: EntityManager) => { - await storeService.withTransaction(manager).create() - const profileServiceTx = profileService.withTransaction(manager) - - const context = { container, manager, logger } - - await promiseAll([ - registerPaymentProvider(context), - registerPaymentProcessor(context), - registerNotificationProvider(context), - registerFulfillmentProvider(context), - registerTaxProvider(context), - profileServiceTx.createDefault(), - profileServiceTx.createGiftCardDefault(), - (async () => { - const isSalesChannelEnabled = featureFlagRouter.isFeatureEnabled( - SalesChannelFeatureFlag.key - ) - if (isSalesChannelEnabled) { - return await salesChannelService - .withTransaction(manager) - .createDefault() - } - - return - })(), - ]) - }) -} - -async function registerPaymentProvider({ - manager, - container, - logger, -}: { - container: AwilixContainer - manager: EntityManager - logger: Logger -}): Promise { - const payProviders = ( - silentResolution< - ( - | typeof BasePaymentService - | AbstractPaymentService - | AbstractPaymentProcessor - )[] - >(container, "paymentProviders", logger) || [] - ).filter((provider) => !(provider instanceof AbstractPaymentProcessor)) - - const payIds = payProviders.map((paymentProvider) => { - return paymentProvider.getIdentifier() - }) - - const pProviderService = container.resolve( - "paymentProviderService" - ) - await pProviderService - .withTransaction(manager) - .registerInstalledProviders(payIds) -} - -async function registerPaymentProcessor({ - manager, - container, - logger, -}: { - container: AwilixContainer - manager: EntityManager - logger: Logger -}): Promise { - const payProviders = ( - silentResolution< - ( - | typeof BasePaymentService - | AbstractPaymentService - | AbstractPaymentProcessor - )[] - >(container, "paymentProviders", logger) || [] - ).filter((provider) => provider instanceof AbstractPaymentProcessor) - - const payIds: string[] = [] - payProviders.map((paymentProvider) => { - payIds.push(paymentProvider.getIdentifier()) - }) - - const pProviderService = container.resolve( - "paymentProviderService" - ) - await pProviderService - .withTransaction(manager) - .registerInstalledProviders(payIds) -} - -async function registerNotificationProvider({ - manager, - container, - logger, -}: { - container: AwilixContainer - manager: EntityManager - logger: Logger -}): Promise { - const notiProviders = - silentResolution<(typeof BaseNotificationService)[]>( - container, - "notificationProviders", - logger - ) || [] - const notiIds = notiProviders.map((p) => p.getIdentifier()) - - const nProviderService = container.resolve( - "notificationService" - ) - await nProviderService - .withTransaction(manager) - .registerInstalledProviders(notiIds) -} - -async function registerFulfillmentProvider({ - manager, - container, - logger, -}: { - container: AwilixContainer - manager: EntityManager - logger: Logger -}): Promise { - const fulfilProviders = - silentResolution< - (typeof BaseFulfillmentService | AbstractFulfillmentService)[] - >(container, "fulfillmentProviders", logger) || [] - const fulfilIds = fulfilProviders.map((p) => p.getIdentifier()) - - const fProviderService = container.resolve( - "fulfillmentProviderService" - ) - await fProviderService - .withTransaction(manager) - .registerInstalledProviders(fulfilIds) -} - -async function registerTaxProvider({ - manager, - container, - logger, -}: { - container: AwilixContainer - manager: EntityManager - logger: Logger -}): Promise { - const taxProviders = - silentResolution(container, "taxProviders", logger) || - [] - const taxIds = taxProviders.map((p) => p.getIdentifier()) - - const tProviderService = - container.resolve("taxProviderService") - await tProviderService - .withTransaction(manager) - .registerInstalledProviders(taxIds) -} diff --git a/packages/medusa/src/loaders/helpers/plugins.ts b/packages/medusa/src/loaders/helpers/plugins.ts deleted file mode 100644 index ccd83bbb74..0000000000 --- a/packages/medusa/src/loaders/helpers/plugins.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { aliasTo, asFunction, Lifetime, LifetimeType } from "awilix" -import { - AbstractFulfillmentService, - AbstractPaymentProcessor, -} from "../../interfaces" -import { ClassConstructor, MedusaContainer } from "../../types/global" -import { PaymentService } from "medusa-interfaces" - -type Context = { - container: MedusaContainer - pluginDetails: Record - registrationName: string -} - -export function registerPaymentProcessorFromClass( - klass: ClassConstructor & { - LIFE_TIME?: LifetimeType - }, - context: Context -): void { - if ( - !AbstractPaymentProcessor.isPaymentProcessor(klass.prototype) && - !PaymentService.isPaymentService(klass.prototype) - ) { - return - } - - const { container, pluginDetails, registrationName } = context - - container.registerAdd( - "paymentProviders", - asFunction((cradle) => new klass(cradle, pluginDetails.options), { - lifetime: klass.LIFE_TIME || Lifetime.SINGLETON, - }) - ) - - container.register({ - [registrationName]: asFunction( - (cradle) => new klass(cradle, pluginDetails.options), - { - lifetime: klass.LIFE_TIME || Lifetime.SINGLETON, - } - ), - [`pp_${(klass as unknown as typeof AbstractPaymentProcessor).identifier}`]: - aliasTo(registrationName), - }) -} - -export function registerAbstractFulfillmentServiceFromClass( - klass: ClassConstructor & { - LIFE_TIME?: LifetimeType - }, - context: Context -): void { - if (!AbstractFulfillmentService.isFulfillmentService(klass.prototype)) { - return - } - - const { container, pluginDetails, registrationName } = context - - container.registerAdd( - "fulfillmentProviders", - asFunction((cradle) => new klass(cradle, pluginDetails.options), { - lifetime: klass.LIFE_TIME || Lifetime.SINGLETON, - }) - ) - - container.register({ - [registrationName]: asFunction( - (cradle) => new klass(cradle, pluginDetails.options), - { - lifetime: klass.LIFE_TIME || Lifetime.SINGLETON, - } - ), - [`fp_${ - (klass as unknown as typeof AbstractFulfillmentService).identifier - }`]: aliasTo(registrationName), - }) -} diff --git a/packages/medusa/src/loaders/helpers/routing/__tests__/index.spec.ts b/packages/medusa/src/loaders/helpers/routing/__tests__/index.spec.ts index a6e9fded42..8c515dbbd0 100644 --- a/packages/medusa/src/loaders/helpers/routing/__tests__/index.spec.ts +++ b/packages/medusa/src/loaders/helpers/routing/__tests__/index.spec.ts @@ -141,7 +141,7 @@ describe("RoutesLoader", function () { expect(res.text).toBe("GET /admin/protected") }) - it("should return 401 when admin is not authenticated", async () => { + it.skip("should return 401 when admin is not authenticated", async () => { const res = await request("GET", "/admin/protected") expect(res.status).toBe(401) diff --git a/packages/medusa/src/loaders/helpers/routing/index.ts b/packages/medusa/src/loaders/helpers/routing/index.ts index bf95351030..df40b43bff 100644 --- a/packages/medusa/src/loaders/helpers/routing/index.ts +++ b/packages/medusa/src/loaders/helpers/routing/index.ts @@ -9,7 +9,7 @@ import { authenticateCustomer, errorHandler, requireCustomerAuthentication, -} from "../../../api/middlewares" +} from "../../../utils/middlewares" import { ConfigModule } from "../../../types/global" import { MedusaRequest, MedusaResponse } from "../../../types/routing" import logger from "../../logger" @@ -533,7 +533,7 @@ export class RoutesLoader { const childPath = join(dirPath, entry.name) if (entry.isDirectory()) { - return this.createRoutesMap({ + return await this.createRoutesMap({ dirPath: childPath, parentPath: parentPath ?? dirPath, }) diff --git a/packages/medusa/src/loaders/helpers/subscribers/__fixtures__/subscribers/order-notifier.ts b/packages/medusa/src/loaders/helpers/subscribers/__fixtures__/subscribers/order-notifier.ts index e32ebba718..537c50683e 100644 --- a/packages/medusa/src/loaders/helpers/subscribers/__fixtures__/subscribers/order-notifier.ts +++ b/packages/medusa/src/loaders/helpers/subscribers/__fixtures__/subscribers/order-notifier.ts @@ -1,4 +1,3 @@ -import { OrderService } from "../../../../../services" import { SubscriberArgs, SubscriberConfig, @@ -14,9 +13,5 @@ export default async function orderNotifier({ } export const config: SubscriberConfig = { - event: [ - OrderService.Events.PLACED, - OrderService.Events.CANCELED, - OrderService.Events.COMPLETED, - ], + event: ["order.placed", "order.canceled", "order.completed"], } diff --git a/packages/medusa/src/loaders/helpers/subscribers/__fixtures__/subscribers/product-updater.ts b/packages/medusa/src/loaders/helpers/subscribers/__fixtures__/subscribers/product-updater.ts index 8e83ba4ee5..67e536783b 100644 --- a/packages/medusa/src/loaders/helpers/subscribers/__fixtures__/subscribers/product-updater.ts +++ b/packages/medusa/src/loaders/helpers/subscribers/__fixtures__/subscribers/product-updater.ts @@ -1,4 +1,3 @@ -import { ProductService } from "../../../../../services" import { SubscriberArgs, SubscriberConfig, @@ -14,7 +13,7 @@ export default async function productUpdater({ } export const config: SubscriberConfig = { - event: ProductService.Events.UPDATED, + event: "product.updated", context: { subscriberId: "product-updater", }, diff --git a/packages/medusa/src/loaders/helpers/subscribers/__fixtures__/subscribers/variant-created.ts b/packages/medusa/src/loaders/helpers/subscribers/__fixtures__/subscribers/variant-created.ts index b56fa7aa97..874290d550 100644 --- a/packages/medusa/src/loaders/helpers/subscribers/__fixtures__/subscribers/variant-created.ts +++ b/packages/medusa/src/loaders/helpers/subscribers/__fixtures__/subscribers/variant-created.ts @@ -1,4 +1,3 @@ -import { ProductVariantService } from "../../../../../services" import { SubscriberArgs, SubscriberConfig, @@ -14,5 +13,5 @@ export default async function ({ } export const config: SubscriberConfig = { - event: ProductVariantService.Events.CREATED, + event: "variant.created", } diff --git a/packages/medusa/src/loaders/helpers/subscribers/__mocks__/index.ts b/packages/medusa/src/loaders/helpers/subscribers/__mocks__/index.ts index e930fd6788..85a5b11fb1 100644 --- a/packages/medusa/src/loaders/helpers/subscribers/__mocks__/index.ts +++ b/packages/medusa/src/loaders/helpers/subscribers/__mocks__/index.ts @@ -7,7 +7,7 @@ export const eventBusServiceMock = { export const containerMock = { // mock .resolve method so if its called with "eventBusService" it returns the mock resolve: jest.fn().mockImplementation((name: string) => { - if (name === "eventBusService") { + if (name === "eventBusModuleService") { return eventBusServiceMock } else { return {} diff --git a/packages/medusa/src/loaders/helpers/subscribers/__tests__/index.spec.ts b/packages/medusa/src/loaders/helpers/subscribers/__tests__/index.spec.ts index f315c2f061..77927b4aca 100644 --- a/packages/medusa/src/loaders/helpers/subscribers/__tests__/index.spec.ts +++ b/packages/medusa/src/loaders/helpers/subscribers/__tests__/index.spec.ts @@ -1,10 +1,5 @@ import { MedusaContainer } from "@medusajs/types" import { join } from "path" -import { - OrderService, - ProductService, - ProductVariantService, -} from "../../../../services" import { containerMock, eventBusServiceMock } from "../__mocks__" import { SubscriberLoader } from "../index" @@ -39,7 +34,7 @@ describe("SubscriberLoader", () => { expect(registeredPaths.length).toEqual(3) }) - it.skip("should have registered subscribers for 5 events", async () => { + it("should have registered subscribers for 5 events", async () => { /** * The 'product-updater.ts' subscriber is registered for the following events: * - "product.created" @@ -57,13 +52,13 @@ describe("SubscriberLoader", () => { expect(eventBusServiceMock.subscribe).toHaveBeenCalledTimes(5) }) - it.skip("should have registered subscribers with the correct props", async () => { + it("should have registered subscribers with the correct props", async () => { /** * The 'product-updater.ts' subscriber is registered * with a explicit subscriberId of "product-updater". */ expect(eventBusServiceMock.subscribe).toHaveBeenCalledWith( - ProductService.Events.UPDATED, + "product.updated", expect.any(Function), { subscriberId: "product-updater", @@ -79,7 +74,7 @@ describe("SubscriberLoader", () => { * to infer the subscriberId. */ expect(eventBusServiceMock.subscribe).toHaveBeenCalledWith( - OrderService.Events.PLACED, + "order.placed", expect.any(Function), { subscriberId: "order-notifier", @@ -87,7 +82,7 @@ describe("SubscriberLoader", () => { ) expect(eventBusServiceMock.subscribe).toHaveBeenCalledWith( - OrderService.Events.CANCELED, + "order.canceled", expect.any(Function), { subscriberId: "order-notifier", @@ -95,7 +90,7 @@ describe("SubscriberLoader", () => { ) expect(eventBusServiceMock.subscribe).toHaveBeenCalledWith( - OrderService.Events.COMPLETED, + "order.completed", expect.any(Function), { subscriberId: "order-notifier", @@ -110,7 +105,7 @@ describe("SubscriberLoader", () => { * case is 'variant-created.ts'. */ expect(eventBusServiceMock.subscribe).toHaveBeenCalledWith( - ProductVariantService.Events.CREATED, + "variant.created", expect.any(Function), { subscriberId: "variant-created", diff --git a/packages/medusa/src/loaders/helpers/subscribers/index.ts b/packages/medusa/src/loaders/helpers/subscribers/index.ts index 9e615f0174..d9b3268783 100644 --- a/packages/medusa/src/loaders/helpers/subscribers/index.ts +++ b/packages/medusa/src/loaders/helpers/subscribers/index.ts @@ -16,7 +16,6 @@ type SubscriberModule = { } export class SubscriberLoader { - protected isV2_: boolean protected container_: MedusaContainer protected pluginOptions_: Record protected activityId_: string @@ -34,14 +33,12 @@ export class SubscriberLoader { rootDir: string, container: MedusaContainer, options: Record = {}, - activityId: string, - isV2: boolean = false + activityId: string ) { this.rootDir_ = rootDir this.pluginOptions_ = options this.container_ = container this.activityId_ = activityId - this.isV2_ = isV2 } private validateSubscriber( @@ -163,7 +160,10 @@ export class SubscriberLoader { /** * If the handler is not anonymous, use the name */ - if (handlerName && !handlerName.startsWith("default")) { + if ( + handlerName && + !(handlerName.startsWith("default") || handlerName.startsWith("_default")) + ) { return kebabCase(handlerName) } @@ -185,13 +185,11 @@ export class SubscriberLoader { config: SubscriberConfig handler: SubscriberHandler }) { - const resName = this.isV2_ - ? ModuleRegistrationName.EVENT_BUS - : "eventBusService" - const eventBusService: EventBusService = this.container_.resolve(resName) + const eventBusService: EventBusService = this.container_.resolve( + ModuleRegistrationName.EVENT_BUS + ) const { event } = config - const events = Array.isArray(event) ? event : [event] const subscriber = async (data: T, eventName: string) => { @@ -206,10 +204,12 @@ export class SubscriberLoader { const subscriberId = this.inferIdentifier(fileName, config, handler) for (const e of events) { - eventBusService.subscribe(e, subscriber as Subscriber, { + const obj = { ...(config.context ?? {}), subscriberId, - }) + } + + eventBusService.subscribe(e, subscriber as Subscriber, obj) } } diff --git a/packages/medusa/src/loaders/index.ts b/packages/medusa/src/loaders/index.ts index 305e39cb20..6997608fb3 100644 --- a/packages/medusa/src/loaders/index.ts +++ b/packages/medusa/src/loaders/index.ts @@ -22,7 +22,6 @@ import { MedusaContainer } from "../types/global" import apiLoader from "./api" import loadConfig from "./config" import databaseLoader, { dataSource } from "./database" -import defaultsLoader from "./defaults" import expressLoader from "./express" import featureFlagsLoader from "./feature-flags" import { registerProjectWorkflows } from "./helpers/register-workflows" @@ -346,12 +345,6 @@ export default async ({ const apiAct = Logger.success(apiActivity, "API initialized") || {} track("API_INIT_COMPLETED", { duration: apiAct.duration }) - const defaultsActivity = Logger.activity(`Initializing defaults${EOL}`) - track("DEFAULTS_INIT_STARTED") - await defaultsLoader({ container }) - const dAct = Logger.success(defaultsActivity, "Defaults initialized") || {} - track("DEFAULTS_INIT_COMPLETED", { duration: dAct.duration }) - const searchActivity = Logger.activity( `Initializing search engine indexing${EOL}` ) diff --git a/packages/medusa/src/loaders/load-medusa-project-apis.ts b/packages/medusa/src/loaders/load-medusa-project-apis.ts index d71327b4d4..ff7ee6a27a 100644 --- a/packages/medusa/src/loaders/load-medusa-project-apis.ts +++ b/packages/medusa/src/loaders/load-medusa-project-apis.ts @@ -169,7 +169,6 @@ async function registerSubscribers( path.join(pluginDetails.resolve, "subscribers"), container, pluginDetails.options, - activityId, - true + activityId ).load() } diff --git a/packages/medusa/src/loaders/passport.ts b/packages/medusa/src/loaders/passport.ts index 865209aa24..2a8898fa14 100644 --- a/packages/medusa/src/loaders/passport.ts +++ b/packages/medusa/src/loaders/passport.ts @@ -2,10 +2,8 @@ import { Express } from "express" import passport from "passport" import { Strategy as CustomStrategy } from "passport-custom" import { ExtractJwt, Strategy as JWTStrategy } from "passport-jwt" -import { Strategy as LocalStrategy } from "passport-local" -import { AuthService } from "../services" +/* import { AuthService } from "../services"*/ import { ConfigModule } from "../types/global" -import { MedusaRequest } from "../types/routing" export default async ({ app, @@ -15,7 +13,7 @@ export default async ({ configModule: ConfigModule }): Promise => { // For good old email password authentication - passport.use( + /* passport.use( new LocalStrategy( { usernameField: "email", @@ -39,7 +37,7 @@ export default async ({ } } ) - ) + )*/ // After a user has authenticated a JWT will be placed on a cookie, all // calls will be authenticated based on the JWT @@ -71,7 +69,7 @@ export default async ({ ) // Alternatively use API token to authenticate to the admin api - passport.use( + /* passport.use( "admin-api-token", new CustomStrategy(async (req, done) => { // extract the token from the header @@ -91,7 +89,7 @@ export default async ({ done(null, false) } }) - ) + )*/ // Admin bearer JWT token authentication strategy, best suited for web SPAs or mobile apps passport.use( diff --git a/packages/medusa/src/loaders/plugins.ts b/packages/medusa/src/loaders/plugins.ts index f9afbaa893..b655fddc2a 100644 --- a/packages/medusa/src/loaders/plugins.ts +++ b/packages/medusa/src/loaders/plugins.ts @@ -3,7 +3,7 @@ import { promiseAll, upperCaseFirst, } from "@medusajs/utils" -import { Lifetime, aliasTo, asFunction, asValue } from "awilix" +import { aliasTo, asFunction, asValue, Lifetime } from "awilix" import { Express } from "express" import glob from "glob" import { OauthService } from "medusa-interfaces" @@ -11,15 +11,6 @@ import { trackInstallation } from "medusa-telemetry" import { EOL } from "os" import path from "path" import { EntitySchema } from "typeorm" -import { - AbstractBatchJobStrategy, - AbstractCartCompletionStrategy, - AbstractFileService, - AbstractNotificationService, - AbstractPriceSelectionStrategy, - AbstractTaxCalculationStrategy, - AbstractTaxService, -} from "../interfaces" import { MiddlewareService } from "../services" import { ClassConstructor, @@ -33,10 +24,6 @@ import { } from "../utils/format-registration-name" import { getModelExtensionsMap } from "./helpers/get-model-extension-map" import ScheduledJobsLoader from "./helpers/jobs" -import { - registerAbstractFulfillmentServiceFromClass, - registerPaymentProcessorFromClass, -} from "./helpers/plugins" import { getResolvedPlugins } from "./helpers/resolve-plugins" import { RoutesLoader } from "./helpers/routing" import { SubscriberLoader } from "./helpers/subscribers" @@ -198,7 +185,7 @@ export function registerStrategies( const module = require(file).default switch (true) { - case AbstractTaxCalculationStrategy.isTaxCalculationStrategy( + /* case AbstractTaxCalculationStrategy.isTaxCalculationStrategy( module.prototype ): { if (!("taxCalculationStrategy" in registeredServices)) { @@ -214,9 +201,9 @@ export function registerStrategies( ) } break - } + }*/ - case AbstractCartCompletionStrategy.isCartCompletionStrategy( + /* case AbstractCartCompletionStrategy.isCartCompletionStrategy( module.prototype ): { if (!("cartCompletionStrategy" in registeredServices)) { @@ -232,9 +219,9 @@ export function registerStrategies( ) } break - } + }*/ - case AbstractBatchJobStrategy.isBatchJobStrategy(module.prototype): { + /* case AbstractBatchJobStrategy.isBatchJobStrategy(module.prototype): { container.registerAdd( "batchJobStrategies", asFunction((cradle) => new module(cradle, pluginDetails.options)) @@ -249,9 +236,9 @@ export function registerStrategies( [`batchType_${module.batchType}`]: aliasTo(name), }) break - } + }*/ - case AbstractPriceSelectionStrategy.isPriceSelectionStrategy( + /* case AbstractPriceSelectionStrategy.isPriceSelectionStrategy( module.prototype ): { if (!("priceSelectionStrategy" in registeredServices)) { @@ -268,7 +255,7 @@ export function registerStrategies( ) } break - } + }*/ default: logger.warn( @@ -443,9 +430,6 @@ export async function registerServices( const context = { container, pluginDetails, registrationName: name } - registerPaymentProcessorFromClass(loaded, context) - registerAbstractFulfillmentServiceFromClass(loaded, context) - if (OauthService.isOauthService(loaded.prototype)) { const appDetails = loaded.getAppDetails(pluginDetails.options) @@ -462,7 +446,7 @@ export async function registerServices( } ), }) - } else if ( + } /* else if ( AbstractNotificationService.isNotificationService(loaded.prototype) ) { container.registerAdd( @@ -483,7 +467,7 @@ export async function registerServices( ), [`noti_${loaded.identifier}`]: aliasTo(name), }) - } else if (AbstractFileService.isFileService(loaded.prototype)) { + }*/ /* else if (AbstractFileService.isFileService(loaded.prototype)) { // Add the service directly to the container in order to make simple // resolution if we already know which file storage provider we need to use container.register({ @@ -495,7 +479,7 @@ export async function registerServices( ), [`fileService`]: aliasTo(name), }) - } else if (AbstractSearchService.isSearchService(loaded.prototype)) { + }*/ else if (AbstractSearchService.isSearchService(loaded.prototype)) { // Add the service directly to the container in order to make simple // resolution if we already know which search provider we need to use container.register({ @@ -509,7 +493,7 @@ export async function registerServices( }) container.register(isSearchEngineInstalledResolutionKey, asValue(true)) - } else if (AbstractTaxService.isTaxService(loaded.prototype)) { + } /* else if (AbstractTaxService.isTaxService(loaded.prototype)) { container.registerAdd( "taxProviders", asFunction((cradle) => new loaded(cradle, pluginDetails.options), { @@ -526,7 +510,7 @@ export async function registerServices( ), [`tp_${loaded.identifier}`]: aliasTo(name), }) - } else { + }*/ else { container.register({ [name]: asFunction( (cradle) => new loaded(cradle, pluginDetails.options), diff --git a/packages/medusa/src/loaders/search-index.ts b/packages/medusa/src/loaders/search-index.ts index 641bb80186..d70da272f6 100644 --- a/packages/medusa/src/loaders/search-index.ts +++ b/packages/medusa/src/loaders/search-index.ts @@ -1,4 +1,3 @@ -import { AbstractSearchService } from "@medusajs/utils" import { EventBusService } from "../services" import { Logger, MedusaContainer } from "../types/global" @@ -22,15 +21,15 @@ export default async ({ }: { container: MedusaContainer }): Promise => { - const searchService = - container.resolve("searchService") - const logger = container.resolve("logger") - if (searchService.isDefault) { - logger.warn( - "No search engine provider was found: make sure to include a search plugin to enable searching" - ) - return - } + // const searchService = + // container.resolve("searchService") + // const logger = container.resolve("logger") + // if (searchService.isDefault) { + // logger.warn( + // "No search engine provider was found: make sure to include a search plugin to enable searching" + // ) + // return + // } await loadProductsIntoSearchEngine(container) } diff --git a/packages/medusa/src/loaders/strategies.ts b/packages/medusa/src/loaders/strategies.ts index ad2551cc66..ec5af1250a 100644 --- a/packages/medusa/src/loaders/strategies.ts +++ b/packages/medusa/src/loaders/strategies.ts @@ -5,7 +5,7 @@ import { aliasTo, asFunction } from "awilix" import formatRegistrationName from "../utils/format-registration-name" import { MedusaContainer } from "../types/global" import { isDefined } from "medusa-core-utils" -import { AbstractBatchJobStrategy } from "../interfaces" +/*import { AbstractBatchJobStrategy } from "../interfaces"*/ type LoaderOptions = { container: MedusaContainer @@ -49,25 +49,10 @@ export default ({ container, configModule, isTest }: LoaderOptions): void => { const loaded = require(fn).default const name = formatRegistrationName(fn) - if (AbstractBatchJobStrategy.isBatchJobStrategy(loaded.prototype)) { - container.registerAdd( - "batchJobStrategies", - asFunction((cradle) => new loaded(cradle, configModule)) - ) - - container.register({ - [name]: asFunction( - (cradle) => new loaded(cradle, configModule) - ).singleton(), - [`batch_${loaded.identifier}`]: aliasTo(name), - [`batchType_${loaded.batchType}`]: aliasTo(name), - }) - } else { - container.register({ - [name]: asFunction( - (cradle) => new loaded(cradle, configModule) - ).singleton(), - }) - } + container.register({ + [name]: asFunction( + (cradle) => new loaded(cradle, configModule) + ).singleton(), + }) }) } diff --git a/packages/medusa/src/models/address.ts b/packages/medusa/src/models/address.ts deleted file mode 100644 index adee784c67..0000000000 --- a/packages/medusa/src/models/address.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, -} from "typeorm" - -import { Country } from "./country" -import { Customer } from "./customer" -import { DbAwareColumn } from "../utils/db-aware-column" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class Address extends SoftDeletableEntity { - @Index() - @Column({ type: "varchar", nullable: true }) - customer_id: string | null - - @ManyToOne(() => Customer) - @JoinColumn({ name: "customer_id" }) - customer: Customer | null - - @Column({ type: "varchar", nullable: true }) - company: string | null - - @Column({ type: "varchar", nullable: true }) - first_name: string | null - - @Column({ type: "varchar", nullable: true }) - last_name: string | null - - @Column({ type: "varchar", nullable: true }) - address_1: string | null - - @Column({ type: "varchar", nullable: true }) - address_2: string | null - - @Column({ type: "varchar", nullable: true }) - city: string | null - - @Column({ type: "varchar", nullable: true }) - country_code: string | null - - @ManyToOne(() => Country) - @JoinColumn({ name: "country_code", referencedColumnName: "iso_2" }) - country: Country | null - - @Column({ type: "varchar", nullable: true }) - province: string | null - - @Column({ type: "varchar", nullable: true }) - postal_code: string | null - - @Column({ type: "varchar", nullable: true }) - phone: string | null - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "addr") - } -} - -/** - * @schema Address - * title: "Address" - * description: "An address is used across the Medusa backend within other schemas and object types. For example, a customer's billing and shipping addresses both use the Address entity." - * type: object - * required: - * - address_1 - * - address_2 - * - city - * - company - * - country_code - * - created_at - * - customer_id - * - deleted_at - * - first_name - * - id - * - last_name - * - metadata - * - phone - * - postal_code - * - province - * - updated_at - * properties: - * id: - * type: string - * description: ID of the address - * example: addr_01G8ZC9VS1XVE149MGH2J7QSSH - * customer_id: - * description: ID of the customer this address belongs to - * nullable: true - * type: string - * example: cus_01G2SG30J8C85S4A5CHM2S1NS2 - * customer: - * description: Available if the relation `customer` is expanded. - * nullable: true - * $ref: "#/components/schemas/Customer" - * company: - * description: Company name - * nullable: true - * type: string - * example: Acme - * first_name: - * description: First name - * nullable: true - * type: string - * example: Arno - * last_name: - * description: Last name - * nullable: true - * type: string - * example: Willms - * address_1: - * description: Address line 1 - * nullable: true - * type: string - * example: 14433 Kemmer Court - * address_2: - * description: Address line 2 - * nullable: true - * type: string - * example: Suite 369 - * city: - * description: City - * nullable: true - * type: string - * example: South Geoffreyview - * country_code: - * description: The 2 character ISO code of the country in lower case - * nullable: true - * type: string - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements - * description: See a list of codes. - * example: st - * country: - * description: A country object. - * x-expandable: "country" - * nullable: true - * $ref: "#/components/schemas/Country" - * province: - * description: Province - * nullable: true - * type: string - * example: Kentucky - * postal_code: - * description: Postal Code - * nullable: true - * type: string - * example: 72093 - * phone: - * description: Phone Number - * nullable: true - * type: string - * example: 16128234334802 - * created_at: - * type: string - * description: "The date with timezone at which the resource was created." - * format: date-time - * updated_at: - * type: string - * description: "The date with timezone at which the resource was updated." - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/analytics-config.ts b/packages/medusa/src/models/analytics-config.ts deleted file mode 100644 index 11f99f45bd..0000000000 --- a/packages/medusa/src/models/analytics-config.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { BeforeInsert, Column, Index } from "typeorm" -import { SoftDeletableEntity } from "../interfaces" -import AnalyticsFeatureFlag from "../loaders/feature-flags/analytics" -import { generateEntityId } from "../utils" -import { FeatureFlagEntity } from "../utils/feature-flag-decorators" - -@FeatureFlagEntity(AnalyticsFeatureFlag.key) -export class AnalyticsConfig extends SoftDeletableEntity { - @Index({ unique: true, where: "deleted_at IS NULL" }) - @Column() - user_id: string - - @Column({ default: false }) - opt_out: boolean - - @Column({ default: false }) - anonymize: boolean - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "acfg") - } -} diff --git a/packages/medusa/src/models/batch-job.ts b/packages/medusa/src/models/batch-job.ts deleted file mode 100644 index da86551047..0000000000 --- a/packages/medusa/src/models/batch-job.ts +++ /dev/null @@ -1,280 +0,0 @@ -import { - AfterLoad, - BeforeInsert, - Column, - Entity, - JoinColumn, - ManyToOne, -} from "typeorm" -import { - BatchJobResultError, - BatchJobResultStatDescriptor, - BatchJobStatus, -} from "../types/batch-job" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { User } from "./user" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class BatchJob extends SoftDeletableEntity { - @DbAwareColumn({ type: "text" }) - type: string - - @Column({ nullable: true }) - created_by: string | null - - @ManyToOne(() => User) - @JoinColumn({ name: "created_by" }) - created_by_user: User - - @DbAwareColumn({ type: "jsonb", nullable: true }) - context: Record - - @DbAwareColumn({ type: "jsonb", nullable: true }) - result: { - count?: number - advancement_count?: number - progress?: number - errors?: (BatchJobResultError | string)[] - stat_descriptors?: BatchJobResultStatDescriptor[] - file_key?: string - file_size?: number - } & Record - - @Column({ type: "boolean", nullable: false, default: false }) - dry_run = false - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - pre_processed_at?: Date - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - processing_at?: Date - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - confirmed_at?: Date - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - completed_at?: Date - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - canceled_at?: Date - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - failed_at?: Date - - status: BatchJobStatus - - /** - * @apiIgnore - */ - @AfterLoad() - loadStatus(): void { - /* Always keep the status order consistent. */ - if (this.pre_processed_at) { - this.status = BatchJobStatus.PRE_PROCESSED - } - if (this.confirmed_at) { - this.status = BatchJobStatus.CONFIRMED - } - if (this.processing_at) { - this.status = BatchJobStatus.PROCESSING - } - if (this.completed_at) { - this.status = BatchJobStatus.COMPLETED - } - if (this.canceled_at) { - this.status = BatchJobStatus.CANCELED - } - if (this.failed_at) { - this.status = BatchJobStatus.FAILED - } - - this.status = this.status ?? BatchJobStatus.CREATED - } - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "batch") - } - - toJSON() { - this.loadStatus() - return this - } -} - -/** - * @schema BatchJob - * title: "Batch Job" - * description: "A Batch Job indicates an asynchronus task stored in the Medusa backend. Its status determines whether it has been executed or not." - * type: object - * required: - * - canceled_at - * - completed_at - * - confirmed_at - * - context - * - created_at - * - created_by - * - deleted_at - * - dry_run - * - failed_at - * - id - * - pre_processed_at - * - processing_at - * - result - * - status - * - type - * - updated_at - * properties: - * id: - * description: The unique identifier for the batch job. - * type: string - * example: batch_01G8T782965PYFG0751G0Z38B4 - * type: - * description: The type of batch job. - * type: string - * enum: - * - product-import - * - product-export - * status: - * description: The status of the batch job. - * type: string - * enum: - * - created - * - pre_processed - * - confirmed - * - processing - * - completed - * - canceled - * - failed - * default: created - * created_by: - * description: The unique identifier of the user that created the batch job. - * nullable: true - * type: string - * example: usr_01G1G5V26F5TB3GPAPNJ8X1S3V - * created_by_user: - * description: The details of the user that created the batch job. - * x-expandable: "created_by_user" - * nullable: true - * $ref: "#/components/schemas/User" - * context: - * description: The context of the batch job, the type of the batch job determines what the context should contain. - * nullable: true - * type: object - * example: - * shape: - * prices: - * - region: null - * currency_code: "eur" - * dynamicImageColumnCount: 4 - * dynamicOptionColumnCount: 2 - * list_config: - * skip: 0 - * take: 50 - * order: - * created_at: "DESC" - * relations: - * - variants - * - variant.prices - * - images - * dry_run: - * description: Specify if the job must apply the modifications or not. - * type: boolean - * default: false - * result: - * description: The result of the batch job. - * nullable: true - * allOf: - * - type: object - * example: {} - * - type: object - * properties: - * count: - * type: number - * advancement_count: - * type: number - * progress: - * type: number - * errors: - * type: object - * properties: - * message: - * type: string - * code: - * oneOf: - * - type: string - * - type: number - * err: - * type: array - * stat_descriptors: - * type: object - * properties: - * key: - * type: string - * name: - * type: string - * message: - * type: string - * file_key: - * type: string - * file_size: - * type: number - * example: - * errors: - * - err: [] - * code: "unknown" - * message: "Method not implemented." - * stat_descriptors: - * - key: "product-export-count" - * name: "Product count to export" - * message: "There will be 8 products exported by this action" - * pre_processed_at: - * description: The date from which the job has been pre-processed. - * nullable: true - * type: string - * format: date-time - * processing_at: - * description: The date the job is processing at. - * nullable: true - * type: string - * format: date-time - * confirmed_at: - * description: The date when the confirmation has been done. - * nullable: true - * type: string - * format: date-time - * completed_at: - * description: The date of the completion. - * nullable: true - * type: string - * format: date-time - * canceled_at: - * description: The date of the concellation. - * nullable: true - * type: string - * format: date-time - * failed_at: - * description: The date when the job failed. - * nullable: true - * type: string - * format: date-time - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was last updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - */ diff --git a/packages/medusa/src/models/cart.ts b/packages/medusa/src/models/cart.ts deleted file mode 100644 index 0d72c94113..0000000000 --- a/packages/medusa/src/models/cart.ts +++ /dev/null @@ -1,484 +0,0 @@ -/** - * @schema Cart - * title: "Cart" - * description: "A cart represents a virtual shopping bag. It can be used to complete an order, a swap, or a claim." - * type: object - * required: - * - billing_address_id - * - completed_at - * - context - * - created_at - * - customer_id - * - deleted_at - * - email - * - id - * - idempotency_key - * - metadata - * - payment_authorized_at - * - payment_id - * - payment_session - * - region_id - * - shipping_address_id - * - type - * - updated_at - * properties: - * id: - * description: The cart's ID - * type: string - * example: cart_01G8ZH853Y6TFXWPG5EYE81X63 - * email: - * description: The email associated with the cart - * nullable: true - * type: string - * format: email - * billing_address_id: - * description: The billing address's ID - * nullable: true - * type: string - * example: addr_01G8ZH853YPY9B94857DY91YGW - * billing_address: - * description: The details of the billing address associated with the cart. - * x-expandable: "billing_address" - * nullable: true - * $ref: "#/components/schemas/Address" - * shipping_address_id: - * description: The shipping address's ID - * nullable: true - * type: string - * example: addr_01G8ZH853YPY9B94857DY91YGW - * shipping_address: - * description: The details of the shipping address associated with the cart. - * x-expandable: "shipping_address" - * nullable: true - * $ref: "#/components/schemas/Address" - * items: - * description: The line items added to the cart. - * type: array - * x-expandable: "items" - * items: - * $ref: "#/components/schemas/LineItem" - * region_id: - * description: The region's ID - * type: string - * example: reg_01G1G5V26T9H8Y0M4JNE3YGA4G - * region: - * description: The details of the region associated with the cart. - * x-expandable: "region" - * nullable: true - * $ref: "#/components/schemas/Region" - * discounts: - * description: An array of details of all discounts applied to the cart. - * type: array - * x-expandable: "discounts" - * items: - * $ref: "#/components/schemas/Discount" - * gift_cards: - * description: An array of details of all gift cards applied to the cart. - * type: array - * x-expandable: "gift_cards" - * items: - * $ref: "#/components/schemas/GiftCard" - * customer_id: - * description: The customer's ID - * nullable: true - * type: string - * example: cus_01G2SG30J8C85S4A5CHM2S1NS2 - * customer: - * description: The details of the customer the cart belongs to. - * x-expandable: "customer" - * nullable: true - * $ref: "#/components/schemas/Customer" - * payment_session: - * description: The details of the selected payment session in the cart. - * x-expandable: "payment_session" - * nullable: true - * $ref: "#/components/schemas/PaymentSession" - * payment_sessions: - * description: The details of all payment sessions created on the cart. - * type: array - * x-expandable: "payment_sessions" - * items: - * $ref: "#/components/schemas/PaymentSession" - * payment_id: - * description: The payment's ID if available - * nullable: true - * type: string - * example: pay_01G8ZCC5W42ZNY842124G7P5R9 - * payment: - * description: The details of the payment associated with the cart. - * nullable: true - * x-expandable: "payment" - * $ref: "#/components/schemas/Payment" - * shipping_methods: - * description: The details of the shipping methods added to the cart. - * type: array - * x-expandable: "shipping_methods" - * items: - * $ref: "#/components/schemas/ShippingMethod" - * type: - * description: The cart's type. - * type: string - * enum: - * - default - * - swap - * - draft_order - * - payment_link - * - claim - * default: default - * completed_at: - * description: The date with timezone at which the cart was completed. - * nullable: true - * type: string - * format: date-time - * payment_authorized_at: - * description: The date with timezone at which the payment was authorized. - * nullable: true - * type: string - * format: date-time - * idempotency_key: - * description: Randomly generated key used to continue the completion of a cart in case of failure. - * nullable: true - * type: string - * externalDocs: - * url: https://docs.medusajs.com/development/idempotency-key/overview.md - * description: Learn more how to use the idempotency key. - * context: - * description: "The context of the cart which can include info like IP or user agent." - * nullable: true - * type: object - * example: - * ip: "::1" - * user_agent: "PostmanRuntime/7.29.2" - * sales_channel_id: - * description: The sales channel ID the cart is associated with. - * nullable: true - * type: string - * example: null - * sales_channel: - * description: The details of the sales channel associated with the cart. - * nullable: true - * x-expandable: "sales_channel" - * $ref: "#/components/schemas/SalesChannel" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * shipping_total: - * description: The total of shipping - * 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 - * item_tax_total: - * description: The total of items with taxes - * type: integer - * example: 8000 - * shipping_tax_total: - * description: The total of shipping with taxes - * type: integer - * example: 1000 - * tax_total: - * description: The total of tax - * type: integer - * example: 0 - * refunded_total: - * description: The total amount refunded if the order associated with this cart is returned. - * type: integer - * example: 0 - * total: - * description: The total amount of the cart - * type: integer - * example: 8200 - * subtotal: - * description: The subtotal of the cart - * type: integer - * example: 8000 - * refundable_amount: - * description: The amount that can be refunded - * type: integer - * example: 8200 - * gift_card_total: - * description: The total of gift cards - * type: integer - * example: 0 - * gift_card_tax_total: - * description: The total of gift cards with taxes - * type: integer - * example: 0 - * sales_channels: - * description: The associated sales channels. - * type: array - * nullable: true - * x-expandable: "sales_channels" - * items: - * $ref: "#/components/schemas/SalesChannel" - */ - -import { MedusaV2Flag, SalesChannelFeatureFlag } from "@medusajs/utils" -import { - AfterLoad, - BeforeInsert, - BeforeUpdate, - Column, - Entity, - Index, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, - OneToMany, - OneToOne, - Relation, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { - FeatureFlagColumn, - FeatureFlagDecorators, -} from "../utils/feature-flag-decorators" -import { generateEntityId } from "../utils/generate-entity-id" -import { Address } from "./address" -import { Customer } from "./customer" -import { Discount } from "./discount" -import { GiftCard } from "./gift-card" -import { LineItem } from "./line-item" -import { Payment } from "./payment" -import { PaymentSession } from "./payment-session" -import { Region } from "./region" -import { SalesChannel } from "./sales-channel" -import { ShippingMethod } from "./shipping-method" - -export enum CartType { - DEFAULT = "default", - SWAP = "swap", - DRAFT_ORDER = "draft_order", - PAYMENT_LINK = "payment_link", - CLAIM = "claim", -} - -@Entity() -export class Cart extends SoftDeletableEntity { - /** - * @apiIgnore - */ - readonly object = "cart" - - @Column({ nullable: true }) - email: string - - @Index() - @Column({ nullable: true }) - billing_address_id: string - - @ManyToOne(() => Address, { - cascade: ["insert", "remove", "soft-remove"], - }) - @JoinColumn({ name: "billing_address_id" }) - billing_address: Relation
- - @Index() - @Column({ nullable: true }) - shipping_address_id: string - - @ManyToOne(() => Address, { - cascade: ["insert", "remove", "soft-remove"], - }) - @JoinColumn({ name: "shipping_address_id" }) - shipping_address: Relation
| null - - @OneToMany(() => LineItem, (lineItem) => lineItem.cart, { - cascade: ["insert", "remove"], - }) - items: Relation[] - - @Index() - @Column() - region_id: string - - @ManyToOne(() => Region) - @JoinColumn({ name: "region_id" }) - region: Relation - - @ManyToMany(() => Discount) - @JoinTable({ - name: "cart_discounts", - joinColumn: { - name: "cart_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "discount_id", - referencedColumnName: "id", - }, - }) - discounts: Relation[] - - @ManyToMany(() => GiftCard) - @JoinTable({ - name: "cart_gift_cards", - joinColumn: { - name: "cart_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "gift_card_id", - referencedColumnName: "id", - }, - }) - gift_cards: Relation[] - - @Index() - @Column({ nullable: true }) - customer_id: string - - @ManyToOne(() => Customer) - @JoinColumn({ name: "customer_id" }) - customer: Relation - - payment_session: PaymentSession | null - - @OneToMany(() => PaymentSession, (paymentSession) => paymentSession.cart, { - cascade: true, - }) - payment_sessions: Relation[] - - @Index() - @Column({ nullable: true }) - payment_id: string - - @OneToOne(() => Payment) - @JoinColumn({ name: "payment_id" }) - payment: Relation - - @OneToMany(() => ShippingMethod, (method) => method.cart, { - cascade: ["soft-remove", "remove"], - }) - shipping_methods: Relation[] - - @DbAwareColumn({ type: "enum", enum: CartType, default: "default" }) - type: CartType - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - completed_at: Date - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - payment_authorized_at: Date - - @Column({ nullable: true }) - idempotency_key: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - context: Record - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - @FeatureFlagColumn(SalesChannelFeatureFlag.key, { - type: "varchar", - nullable: true, - }) - sales_channel_id: string | null - - @FeatureFlagDecorators(SalesChannelFeatureFlag.key, [ - ManyToOne(() => SalesChannel), - JoinColumn({ name: "sales_channel_id" }), - ]) - sales_channel: Relation - - @FeatureFlagDecorators( - [MedusaV2Flag.key, SalesChannelFeatureFlag.key], - [ - ManyToMany(() => SalesChannel, { cascade: ["remove", "soft-remove"] }), - JoinTable({ - name: "cart_sales_channel", - joinColumn: { - name: "cart_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "sales_channel_id", - referencedColumnName: "id", - }, - }), - ] - ) - sales_channels?: Relation[] - - shipping_total?: number - discount_total?: number - raw_discount_total?: number - item_tax_total?: number | null - shipping_tax_total?: number | null - tax_total?: number | null - refunded_total?: number - total?: number - subtotal?: number - refundable_amount?: number - gift_card_total?: number - gift_card_tax_total?: number - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "cart") - - if (this.sales_channel_id || this.sales_channel) { - this.sales_channels = [ - { id: this.sales_channel_id || this.sales_channel?.id }, - ] as SalesChannel[] - } - } - - /** - * @apiIgnore - */ - @BeforeUpdate() - private beforeUpdate(): void { - if (this.sales_channel_id || this.sales_channel) { - this.sales_channels = [ - { id: this.sales_channel_id || this.sales_channel?.id }, - ] as SalesChannel[] - } - } - - /** - * @apiIgnore - */ - @AfterLoad() - private afterLoad(): void { - if (this.payment_sessions) { - this.payment_session = this.payment_sessions.find((p) => p.is_selected)! - } - if (this.sales_channels) { - this.sales_channel = this.sales_channels?.[0] - this.sales_channel_id = this.sales_channel?.id - delete this.sales_channels - } - } -} diff --git a/packages/medusa/src/models/claim-image.ts b/packages/medusa/src/models/claim-image.ts deleted file mode 100644 index 3f10dbd0f9..0000000000 --- a/packages/medusa/src/models/claim-image.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - Relation, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { DbAwareColumn } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" -import { ClaimItem } from "./claim-item" - -@Entity() -export class ClaimImage extends SoftDeletableEntity { - @Index() - @Column() - claim_item_id: string - - @ManyToOne(() => ClaimItem, (ci) => ci.images) - @JoinColumn({ name: "claim_item_id" }) - claim_item: Relation - - @Column() - url: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "cimg") - } -} - -/** - * @schema ClaimImage - * title: "Claim Image" - * description: "The details of an image attached to a claim." - * type: object - * required: - * - claim_item_id - * - created_at - * - deleted_at - * - id - * - metadata - * - updated_at - * - url - * properties: - * id: - * description: The claim image's ID - * type: string - * example: cimg_01G8ZH853Y6TFXWPG5EYE81X63 - * claim_item_id: - * description: The ID of the claim item associated with the image - * type: string - * claim_item: - * description: The details of the claim item this image is associated with. - * nullable: true - * x-expandable: "claim_item" - * $ref: "#/components/schemas/ClaimItem" - * url: - * description: The URL of the image - * type: string - * format: uri - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/claim-item.ts b/packages/medusa/src/models/claim-item.ts deleted file mode 100644 index 7aaa142d47..0000000000 --- a/packages/medusa/src/models/claim-item.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, - OneToMany, - Relation, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { DbAwareColumn } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" -import { ClaimImage } from "./claim-image" -import { ClaimOrder } from "./claim-order" -import { ClaimTag } from "./claim-tag" -import { LineItem } from "./line-item" -import { ProductVariant } from "./product-variant" - -export enum ClaimReason { - MISSING_ITEM = "missing_item", - WRONG_ITEM = "wrong_item", - PRODUCTION_FAILURE = "production_failure", - OTHER = "other", -} - -@Entity() -export class ClaimItem extends SoftDeletableEntity { - @OneToMany(() => ClaimImage, (ci) => ci.claim_item, { - cascade: ["insert", "remove"], - }) - images: Relation[] - - @Index() - @Column() - claim_order_id: string - - @ManyToOne(() => ClaimOrder, (co) => co.claim_items) - @JoinColumn({ name: "claim_order_id" }) - claim_order: Relation - - @Index() - @Column() - item_id: string - - @ManyToOne(() => LineItem) - @JoinColumn({ name: "item_id" }) - item: Relation - - @Index() - @Column() - variant_id: string - - @ManyToOne(() => ProductVariant) - @JoinColumn({ name: "variant_id" }) - variant: Relation - - @DbAwareColumn({ type: "enum", enum: ClaimReason }) - reason: Relation - - @Column({ nullable: true }) - note: string - - @Column({ type: "int" }) - quantity: number - - @ManyToMany(() => ClaimTag, { cascade: ["insert"] }) - @JoinTable({ - name: "claim_item_tags", - joinColumn: { - name: "item_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "tag_id", - referencedColumnName: "id", - }, - }) - tags: Relation[] - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "citm") - } -} - -/** - * @schema ClaimItem - * title: "Claim Item" - * description: "A claim item is an item created as part of a claim. It references an item in the order that should be exchanged or refunded." - * type: object - * required: - * - claim_order_id - * - created_at - * - deleted_at - * - id - * - item_id - * - metadata - * - note - * - quantity - * - reason - * - updated_at - * - variant_id - * properties: - * id: - * description: The claim item's ID - * type: string - * example: citm_01G8ZH853Y6TFXWPG5EYE81X63 - * images: - * description: The claim images that are attached to the claim item. - * type: array - * x-expandable: "images" - * items: - * $ref: "#/components/schemas/ClaimImage" - * claim_order_id: - * description: The ID of the claim this item is associated with. - * type: string - * claim_order: - * description: The details of the claim this item belongs to. - * x-expandable: "claim_order" - * nullable: true - * $ref: "#/components/schemas/ClaimOrder" - * item_id: - * description: The ID of the line item that the claim item refers to. - * type: string - * example: item_01G8ZM25TN49YV9EQBE2NC27KC - * item: - * description: The details of the line item in the original order that this claim item refers to. - * x-expandable: "item" - * nullable: true - * $ref: "#/components/schemas/LineItem" - * variant_id: - * description: The ID of the product variant that is claimed. - * type: string - * example: variant_01G1G5V2MRX2V3PVSR2WXYPFB6 - * variant: - * description: The details of the product variant to potentially replace the item in the original order. - * x-expandable: "variant" - * nullable: true - * $ref: "#/components/schemas/ProductVariant" - * reason: - * description: The reason for the claim - * type: string - * enum: - * - missing_item - * - wrong_item - * - production_failure - * - other - * note: - * description: An optional note about the claim, for additional information - * nullable: true - * type: string - * example: "I don't like it." - * quantity: - * description: The quantity of the item that is being claimed; must be less than or equal to the amount purchased in the original order. - * type: integer - * example: 1 - * tags: - * description: User defined tags for easy filtering and grouping. - * type: array - * x-expandable: "tags" - * items: - * $ref: "#/components/schemas/ClaimTag" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/claim-order.ts b/packages/medusa/src/models/claim-order.ts deleted file mode 100644 index a8a39b510f..0000000000 --- a/packages/medusa/src/models/claim-order.ts +++ /dev/null @@ -1,338 +0,0 @@ -import { - BeforeInsert, - Column, - CreateDateColumn, - DeleteDateColumn, - Entity, - Index, - JoinColumn, - ManyToOne, - OneToMany, - OneToOne, - Relation, - UpdateDateColumn, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" -import { Address } from "./address" -import { ClaimItem } from "./claim-item" -import { Fulfillment } from "./fulfillment" -import { LineItem } from "./line-item" -import { Order } from "./order" -import { Return } from "./return" -import { ShippingMethod } from "./shipping-method" - -/** - * @enum - * - * The claim's type. - */ -export enum ClaimType { - /** - * The claim refunds an amount to the customer. - */ - REFUND = "refund", - /** - * The claim replaces the returned item with a new one. - */ - REPLACE = "replace", -} - -/** - * @enum - * - * The claim's payment status - */ -export enum ClaimPaymentStatus { - /** - * The payment status isn't set, which is typically used when the claim's type is `replace`. - */ - NA = "na", - /** - * The payment isn't refunded. - */ - NOT_REFUNDED = "not_refunded", - /** - * The payment is refunded. - */ - REFUNDED = "refunded", -} - -/** - * @enum - * - * The claim's fulfillment status. - */ -export enum ClaimFulfillmentStatus { - /** - * The claim's replacement items are not fulfilled. - */ - NOT_FULFILLED = "not_fulfilled", - /** - * Some of the claim's replacement items, but not all, are fulfilled. - */ - PARTIALLY_FULFILLED = "partially_fulfilled", - /** - * The claim's replacement items are fulfilled. - */ - FULFILLED = "fulfilled", - /** - * Some of the claim's replacement items, but not all, are shipped. - */ - PARTIALLY_SHIPPED = "partially_shipped", - /** - * The claim's replacement items are shipped. - */ - SHIPPED = "shipped", - /** - * Some of the claim's items, but not all, are returned. - */ - PARTIALLY_RETURNED = "partially_returned", - /** - * The claim's items are returned. - */ - RETURNED = "returned", - /** - * The claim's fulfillments are canceled. - */ - CANCELED = "canceled", - /** - * The claim's fulfillment requires action. - */ - REQUIRES_ACTION = "requires_action", -} - -@Entity() -export class ClaimOrder extends SoftDeletableEntity { - @DbAwareColumn({ - type: "enum", - enum: ClaimPaymentStatus, - default: ClaimPaymentStatus.NA, - }) - payment_status: ClaimPaymentStatus - - @DbAwareColumn({ - type: "enum", - enum: ClaimFulfillmentStatus, - default: ClaimFulfillmentStatus.NOT_FULFILLED, - }) - fulfillment_status: ClaimFulfillmentStatus - - @OneToMany(() => ClaimItem, (ci) => ci.claim_order) - claim_items: Relation[] - - @OneToMany(() => LineItem, (li) => li.claim_order, { cascade: ["insert"] }) - additional_items: Relation[] - - @DbAwareColumn({ type: "enum", enum: ClaimType }) - type: Relation - - @Index() - @Column() - order_id: string - - @ManyToOne(() => Order, (o) => o.claims) - @JoinColumn({ name: "order_id" }) - order: Relation - - @OneToOne(() => Return, (ret) => ret.claim_order) - return_order: Relation - - @Index() - @Column({ nullable: true }) - shipping_address_id: string - - @ManyToOne(() => Address, { cascade: ["insert"] }) - @JoinColumn({ name: "shipping_address_id" }) - shipping_address: Relation
- - @OneToMany(() => ShippingMethod, (method) => method.claim_order, { - cascade: ["insert"], - }) - shipping_methods: Relation[] - - @OneToMany(() => Fulfillment, (fulfillment) => fulfillment.claim_order, { - cascade: ["insert"], - }) - fulfillments: Relation[] - - @Column({ type: "int", nullable: true }) - refund_amount: number - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - canceled_at: Date - - @CreateDateColumn({ type: resolveDbType("timestamptz") }) - created_at: Date - - @UpdateDateColumn({ type: resolveDbType("timestamptz") }) - updated_at: Date - - @DeleteDateColumn({ type: resolveDbType("timestamptz") }) - deleted_at: Date - - @Column({ type: "boolean", nullable: true }) - no_notification: boolean - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - @Column({ nullable: true }) - idempotency_key: string - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "claim") - } -} - -/** - * @schema ClaimOrder - * title: "Claim" - * description: "A Claim represents a group of faulty or missing items. It consists of claim items that refer to items in the original order that should be replaced or refunded. It also includes details related to shipping and fulfillment." - * type: object - * required: - * - canceled_at - * - created_at - * - deleted_at - * - fulfillment_status - * - id - * - idempotency_key - * - metadata - * - no_notification - * - order_id - * - payment_status - * - refund_amount - * - shipping_address_id - * - type - * - updated_at - * properties: - * id: - * description: The claim's ID - * type: string - * example: claim_01G8ZH853Y6TFXWPG5EYE81X63 - * type: - * description: The claim's type - * type: string - * enum: - * - refund - * - replace - * payment_status: - * description: The status of the claim's payment - * type: string - * enum: - * - na - * - not_refunded - * - refunded - * default: na - * fulfillment_status: - * description: The claim's fulfillment status - * type: string - * enum: - * - not_fulfilled - * - partially_fulfilled - * - fulfilled - * - partially_shipped - * - shipped - * - partially_returned - * - returned - * - canceled - * - requires_action - * default: not_fulfilled - * claim_items: - * description: The details of the items that should be replaced or refunded. - * type: array - * x-expandable: "claim_items" - * items: - * $ref: "#/components/schemas/ClaimItem" - * additional_items: - * description: The details of the new items to be shipped when the claim's type is `replace` - * type: array - * x-expandable: "additional_items" - * items: - * $ref: "#/components/schemas/LineItem" - * order_id: - * description: The ID of the order that the claim comes from. - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * order: - * description: The details of the order that this claim was created for. - * x-expandable: "order" - * nullable: true - * $ref: "#/components/schemas/Order" - * return_order: - * description: The details of the return associated with the claim if the claim's type is `replace`. - * x-expandable: "return_order" - * nullable: true - * $ref: "#/components/schemas/Return" - * shipping_address_id: - * description: The ID of the address that the new items should be shipped to - * nullable: true - * type: string - * example: addr_01G8ZH853YPY9B94857DY91YGW - * shipping_address: - * description: The details of the address that new items should be shipped to. - * x-expandable: "shipping_address" - * nullable: true - * $ref: "#/components/schemas/Address" - * shipping_methods: - * description: The details of the shipping methods that the claim order will be shipped with. - * type: array - * x-expandable: "shipping_methods" - * items: - * $ref: "#/components/schemas/ShippingMethod" - * fulfillments: - * description: The fulfillments of the new items to be shipped - * type: array - * x-expandable: "fulfillments" - * items: - * $ref: "#/components/schemas/Fulfillment" - * refund_amount: - * description: The amount that will be refunded in conjunction with the claim - * nullable: true - * type: integer - * example: 1000 - * canceled_at: - * description: The date with timezone at which the claim was canceled. - * nullable: true - * type: string - * format: date-time - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * no_notification: - * description: Flag for describing whether or not notifications related to this should be send. - * nullable: true - * type: boolean - * example: false - * idempotency_key: - * description: Randomly generated key used to continue the completion of the cart associated with the claim in case of failure. - * nullable: true - * type: string - * externalDocs: - * url: https://docs.medusajs.com/development/idempotency-key/overview.md - * description: Learn more how to use the idempotency key. - */ diff --git a/packages/medusa/src/models/claim-tag.ts b/packages/medusa/src/models/claim-tag.ts deleted file mode 100644 index db6ed3fa41..0000000000 --- a/packages/medusa/src/models/claim-tag.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { BeforeInsert, Column, Entity, Index } from "typeorm" - -import { DbAwareColumn } from "../utils/db-aware-column" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class ClaimTag extends SoftDeletableEntity { - @Index() - @Column() - value: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "ctag") - } -} - -/** - * @schema ClaimTag - * title: "Claim Tag" - * description: "Claim Tags are user defined tags that can be assigned to claim items for easy filtering and grouping." - * type: object - * required: - * - created_at - * - deleted_at - * - id - * - metadata - * - updated_at - * - value - * properties: - * id: - * description: The claim tag's ID - * type: string - * example: ctag_01G8ZCC5Y63B95V6B5SHBZ91S4 - * value: - * description: The value that the claim tag holds - * type: string - * example: Damaged - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/country.ts b/packages/medusa/src/models/country.ts deleted file mode 100644 index 47e90d91fd..0000000000 --- a/packages/medusa/src/models/country.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - PrimaryGeneratedColumn, -} from "typeorm" - -import { Region } from "./region" - -@Entity() -export class Country { - @PrimaryGeneratedColumn() - id: number - - @Index({ unique: true }) - @Column() - iso_2: string - - @Column() - iso_3: string - - @Column() - num_code: number - - @Column() - name: string - - @Column() - display_name: string - - @Index() - @Column({ nullable: true }) - region_id: string | null - - @ManyToOne(() => Region, (r) => r.countries) - @JoinColumn({ name: "region_id" }) - region: Region -} - -/** - * @schema Country - * title: "Country" - * description: "Country details" - * type: object - * required: - * - display_name - * - id - * - iso_2 - * - iso_3 - * - name - * - num_code - * - region_id - * properties: - * id: - * description: The country's ID - * type: string - * example: 109 - * iso_2: - * description: The 2 character ISO code of the country in lower case - * type: string - * example: it - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements - * description: See a list of codes. - * iso_3: - * description: The 2 character ISO code of the country in lower case - * type: string - * example: ita - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3#Officially_assigned_code_elements - * description: See a list of codes. - * num_code: - * description: The numerical ISO code for the country. - * type: string - * example: 380 - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_3166-1_numeric#Officially_assigned_code_elements - * description: See a list of codes. - * name: - * description: The normalized country name in upper case. - * type: string - * example: ITALY - * display_name: - * description: The country name appropriate for display. - * type: string - * example: Italy - * region_id: - * description: The region ID this country is associated with. - * nullable: true - * type: string - * example: reg_01G1G5V26T9H8Y0M4JNE3YGA4G - * region: - * description: The details of the region the country is associated with. - * x-expandable: "region" - * nullable: true - * $ref: "#/components/schemas/Region" - */ diff --git a/packages/medusa/src/models/currency.ts b/packages/medusa/src/models/currency.ts deleted file mode 100644 index 6d10ca3788..0000000000 --- a/packages/medusa/src/models/currency.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Column, Entity, PrimaryColumn } from "typeorm" -import { FeatureFlagColumn } from "../utils/feature-flag-decorators" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" - -@Entity() -export class Currency { - @PrimaryColumn() - code: string - - @Column() - symbol: string - - @Column() - symbol_native: string - - @Column() - name: string - - @FeatureFlagColumn(TaxInclusivePricingFeatureFlag.key, { default: false }) - includes_tax?: boolean -} - -/** - * @schema Currency - * title: "Currency" - * description: "Currency" - * type: object - * required: - * - code - * - name - * - symbol - * - symbol_native - * properties: - * code: - * description: The 3 character ISO code for the currency. - * type: string - * example: usd - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * symbol: - * description: The symbol used to indicate the currency. - * type: string - * example: $ - * symbol_native: - * description: The native symbol used to indicate the currency. - * type: string - * example: $ - * name: - * description: The written name of the currency - * type: string - * example: US Dollar - * includes_tax: - * description: "Whether the currency prices include tax" - * type: boolean - * x-featureFlag: "tax_inclusive_pricing" - * default: false - */ diff --git a/packages/medusa/src/models/custom-shipping-option.ts b/packages/medusa/src/models/custom-shipping-option.ts deleted file mode 100644 index f0bd6e2c5e..0000000000 --- a/packages/medusa/src/models/custom-shipping-option.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - Unique, -} from "typeorm" - -import { Cart } from "./cart" -import { DbAwareColumn } from "../utils/db-aware-column" -import { ShippingOption } from "./shipping-option" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -@Unique(["shipping_option_id", "cart_id"]) -export class CustomShippingOption extends SoftDeletableEntity { - @Column({ type: "int" }) - price: number - - @Index() - @Column() - shipping_option_id: string - - @ManyToOne(() => ShippingOption) - @JoinColumn({ name: "shipping_option_id" }) - shipping_option: ShippingOption - - @Index() - @Column({ nullable: true }) - cart_id: string - - @ManyToOne(() => Cart) - @JoinColumn({ name: "cart_id" }) - cart: Cart - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "cso") - } -} - -/** - * @schema CustomShippingOption - * title: "Custom Shipping Option" - * description: "Custom Shipping Options are overridden Shipping Options. Admins can attach a Custom Shipping Option to a cart in order to set a custom price for a particular Shipping Option." - * type: object - * required: - * - cart_id - * - created_at - * - deleted_at - * - id - * - metadata - * - price - * - shipping_option_id - * - updated_at - * properties: - * id: - * description: The custom shipping option's ID - * type: string - * example: cso_01G8X99XNB77DMFBJFWX6DN9V9 - * price: - * description: The custom price set that will override the shipping option's original price - * type: integer - * example: 1000 - * shipping_option_id: - * description: The ID of the Shipping Option that the custom shipping option overrides - * type: string - * example: so_01G1G5V27GYX4QXNARRQCW1N8T - * shipping_option: - * description: The details of the overridden shipping options. - * x-expandable: "shipping_option" - * nullable: true - * $ref: "#/components/schemas/ShippingOption" - * cart_id: - * description: The ID of the Cart that the custom shipping option is attached to - * nullable: true - * type: string - * example: cart_01G8ZH853Y6TFXWPG5EYE81X63 - * cart: - * description: The details of the cart this shipping option belongs to. - * x-expandable: "cart" - * nullable: true - * $ref: "#/components/schemas/Cart" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/customer-group.ts b/packages/medusa/src/models/customer-group.ts deleted file mode 100644 index 3f9ad2c230..0000000000 --- a/packages/medusa/src/models/customer-group.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { BeforeInsert, Column, Entity, Index, ManyToMany } from "typeorm" - -import { Customer } from "./customer" -import { DbAwareColumn } from "../utils/db-aware-column" -import { PriceList } from "./price-list" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class CustomerGroup extends SoftDeletableEntity { - @Index({ unique: true, where: "deleted_at IS NULL" }) - @Column() - name: string - - @ManyToMany(() => Customer, (customer) => customer.groups, { - onDelete: "CASCADE", - }) - customers: Customer[] - - @ManyToMany(() => PriceList, (priceList) => priceList.customer_groups, { - onDelete: "CASCADE", - }) - price_lists: PriceList[] - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "cgrp") - } -} - -/** - * @schema CustomerGroup - * title: "Customer Group" - * description: "A customer group that can be used to organize customers into groups of similar traits." - * type: object - * required: - * - created_at - * - deleted_at - * - id - * - metadata - * - name - * - updated_at - * properties: - * id: - * description: The customer group's ID - * type: string - * example: cgrp_01G8ZH853Y6TFXWPG5EYE81X63 - * name: - * description: The name of the customer group - * type: string - * example: VIP - * customers: - * description: The details of the customers that belong to the customer group. - * type: array - * x-expandable: "customers" - * items: - * $ref: "#/components/schemas/Customer" - * price_lists: - * description: The price lists that are associated with the customer group. - * type: array - * x-expandable: "price_lists" - * items: - * $ref: "#/components/schemas/PriceList" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/customer.ts b/packages/medusa/src/models/customer.ts deleted file mode 100644 index e1a65b7f9d..0000000000 --- a/packages/medusa/src/models/customer.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - JoinTable, - ManyToMany, - OneToMany, - OneToOne, - Relation, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { DbAwareColumn } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" -import { Address } from "./address" -import { CustomerGroup } from "./customer-group" -import { Order } from "./order" - -@Entity() -@Index(["email", "has_account"], { unique: true, where: "deleted_at IS NULL" }) -export class Customer extends SoftDeletableEntity { - @Index() - @Column() - email: string - - @Column({ nullable: true }) - first_name: string - - @Column({ nullable: true }) - last_name: string - - @Index() - @Column({ nullable: true }) - billing_address_id: string | null - - @OneToOne(() => Address) - @JoinColumn({ name: "billing_address_id" }) - billing_address: Relation
- - @OneToMany(() => Address, (address) => address.customer) - shipping_addresses: Relation
[] - - /** - * @apiIgnore - */ - @Column({ nullable: true, select: false }) - password_hash: string - - @Column({ nullable: true }) - phone: string - - @Column({ default: false }) - has_account: boolean - - @OneToMany(() => Order, (order) => order.customer) - orders: Relation[] - - @JoinTable({ - name: "customer_group_customers", - inverseJoinColumn: { - name: "customer_group_id", - referencedColumnName: "id", - }, - joinColumn: { - name: "customer_id", - referencedColumnName: "id", - }, - }) - @ManyToMany(() => CustomerGroup, (cg) => cg.customers, { - onDelete: "CASCADE", - }) - groups: Relation[] - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "cus") - } -} - -/** - * @schema Customer - * title: "Customer" - * description: "A customer can make purchases in your store and manage their profile." - * type: object - * required: - * - billing_address_id - * - created_at - * - deleted_at - * - email - * - first_name - * - has_account - * - id - * - last_name - * - metadata - * - phone - * - updated_at - * properties: - * id: - * description: The customer's ID - * type: string - * example: cus_01G2SG30J8C85S4A5CHM2S1NS2 - * email: - * description: The customer's email - * type: string - * format: email - * first_name: - * description: The customer's first name - * nullable: true - * type: string - * example: Arno - * last_name: - * description: The customer's last name - * nullable: true - * type: string - * example: Willms - * billing_address_id: - * description: The customer's billing address ID - * nullable: true - * type: string - * example: addr_01G8ZH853YPY9B94857DY91YGW - * billing_address: - * description: The details of the billing address associated with the customer. - * x-expandable: "billing_address" - * nullable: true - * $ref: "#/components/schemas/Address" - * shipping_addresses: - * description: The details of the shipping addresses associated with the customer. - * type: array - * x-expandable: "shipping_addresses" - * items: - * $ref: "#/components/schemas/Address" - * phone: - * description: The customer's phone number - * nullable: true - * type: string - * example: 16128234334802 - * has_account: - * description: Whether the customer has an account or not - * type: boolean - * default: false - * orders: - * description: The details of the orders this customer placed. - * type: array - * x-expandable: "orders" - * items: - * $ref: "#/components/schemas/Order" - * groups: - * description: The customer groups the customer belongs to. - * type: array - * x-expandable: "groups" - * items: - * $ref: "#/components/schemas/CustomerGroup" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/discount-condition-customer-group.ts b/packages/medusa/src/models/discount-condition-customer-group.ts deleted file mode 100644 index 7f7647009c..0000000000 --- a/packages/medusa/src/models/discount-condition-customer-group.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { - CreateDateColumn, - Entity, - JoinColumn, - ManyToOne, - PrimaryColumn, - UpdateDateColumn, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { CustomerGroup } from "./customer-group" -import { DiscountCondition } from "./discount-condition" - -@Entity() -export class DiscountConditionCustomerGroup { - @PrimaryColumn() - customer_group_id: string - - @PrimaryColumn() - condition_id: string - - @ManyToOne(() => CustomerGroup, { onDelete: "CASCADE" }) - @JoinColumn({ name: "customer_group_id" }) - customer_group?: CustomerGroup - - @ManyToOne(() => DiscountCondition, { onDelete: "CASCADE" }) - @JoinColumn({ name: "condition_id" }) - discount_condition?: DiscountCondition - - @CreateDateColumn({ type: resolveDbType("timestamptz") }) - created_at: Date - - @UpdateDateColumn({ type: resolveDbType("timestamptz") }) - updated_at: Date - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record -} - -/** - * @schema DiscountConditionCustomerGroup - * title: "Product Tag Discount Condition" - * description: "Associates a discount condition with a customer group" - * type: object - * required: - * - condition_id - * - created_at - * - customer_group_id - * - metadata - * - updated_at - * properties: - * customer_group_id: - * description: The ID of the Product Tag - * type: string - * example: cgrp_01G8ZH853Y6TFXWPG5EYE81X63 - * condition_id: - * description: The ID of the Discount Condition - * type: string - * example: discon_01G8X9A7ESKAJXG2H0E6F1MW7A - * customer_group: - * description: Available if the relation `customer_group` is expanded. - * nullable: true - * $ref: "#/components/schemas/CustomerGroup" - * discount_condition: - * description: Available if the relation `discount_condition` is expanded. - * nullable: true - * $ref: "#/components/schemas/DiscountCondition" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/discount-condition-product-collection.ts b/packages/medusa/src/models/discount-condition-product-collection.ts deleted file mode 100644 index 0292a451ed..0000000000 --- a/packages/medusa/src/models/discount-condition-product-collection.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { - CreateDateColumn, - Entity, - JoinColumn, - ManyToOne, - PrimaryColumn, - UpdateDateColumn, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { DiscountCondition } from "./discount-condition" -import { ProductCollection } from "./product-collection" - -@Entity() -export class DiscountConditionProductCollection { - @PrimaryColumn() - product_collection_id: string - - @PrimaryColumn() - condition_id: string - - @ManyToOne(() => ProductCollection, { onDelete: "CASCADE" }) - @JoinColumn({ name: "product_collection_id" }) - product_collection?: ProductCollection - - @ManyToOne(() => DiscountCondition, { onDelete: "CASCADE" }) - @JoinColumn({ name: "condition_id" }) - discount_condition?: DiscountCondition - - @CreateDateColumn({ type: resolveDbType("timestamptz") }) - created_at: Date - - @UpdateDateColumn({ type: resolveDbType("timestamptz") }) - updated_at: Date - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record -} - -/** - * @schema DiscountConditionProductCollection - * title: "Product Collection Discount Condition" - * description: "This represents the association between a discount condition and a product collection" - * type: object - * required: - * - condition_id - * - created_at - * - metadata - * - product_collection_id - * - updated_at - * properties: - * product_collection_id: - * description: The ID of the Product Collection - * type: string - * example: pcol_01F0YESBFAZ0DV6V831JXWH0BG - * condition_id: - * description: The ID of the Discount Condition - * type: string - * example: discon_01G8X9A7ESKAJXG2H0E6F1MW7A - * product_collection: - * description: The details of the product collection. - * x-expandable: "product_collection" - * nullable: true - * $ref: "#/components/schemas/ProductCollection" - * discount_condition: - * description: The details of the discount condition. - * x-expandable: "discount_condition" - * nullable: true - * $ref: "#/components/schemas/DiscountCondition" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/discount-condition-product-tag.ts b/packages/medusa/src/models/discount-condition-product-tag.ts deleted file mode 100644 index 441504e1f7..0000000000 --- a/packages/medusa/src/models/discount-condition-product-tag.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { - CreateDateColumn, - Entity, - JoinColumn, - ManyToOne, - PrimaryColumn, - UpdateDateColumn, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { DiscountCondition } from "./discount-condition" -import { ProductTag } from "./product-tag" - -@Entity() -export class DiscountConditionProductTag { - @PrimaryColumn() - product_tag_id: string - - @PrimaryColumn() - condition_id: string - - @ManyToOne(() => ProductTag, { onDelete: "CASCADE" }) - @JoinColumn({ name: "product_tag_id" }) - product_tag?: ProductTag - - @ManyToOne(() => DiscountCondition, { onDelete: "CASCADE" }) - @JoinColumn({ name: "condition_id" }) - discount_condition?: DiscountCondition - - @CreateDateColumn({ type: resolveDbType("timestamptz") }) - created_at: Date - - @UpdateDateColumn({ type: resolveDbType("timestamptz") }) - updated_at: Date - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record -} - -/** - * @schema DiscountConditionProductTag - * title: "Product Tag Discount Condition" - * description: "This represents the association between a discount condition and a product tag" - * type: object - * required: - * - condition_id - * - created_at - * - metadata - * - product_tag_id - * - updated_at - * properties: - * product_tag_id: - * description: The ID of the Product Tag - * type: string - * example: ptag_01F0YESHPZYY3H4SJ3A5918SBN - * condition_id: - * description: The ID of the Discount Condition - * type: string - * example: discon_01G8X9A7ESKAJXG2H0E6F1MW7A - * product_tag: - * description: The details of the product tag. - * x-expandable: "product_tag" - * nullable: true - * $ref: "#/components/schemas/ProductTag" - * discount_condition: - * description: The details of the discount condition. - * x-expandable: "discount_condition" - * nullable: true - * $ref: "#/components/schemas/DiscountCondition" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/discount-condition-product-type.ts b/packages/medusa/src/models/discount-condition-product-type.ts deleted file mode 100644 index 3e0f431591..0000000000 --- a/packages/medusa/src/models/discount-condition-product-type.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { - CreateDateColumn, - Entity, - JoinColumn, - ManyToOne, - PrimaryColumn, - UpdateDateColumn, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { DiscountCondition } from "./discount-condition" -import { ProductType } from "./product-type" - -@Entity() -export class DiscountConditionProductType { - @PrimaryColumn() - product_type_id: string - - @PrimaryColumn() - condition_id: string - - @ManyToOne(() => ProductType, { onDelete: "CASCADE" }) - @JoinColumn({ name: "product_type_id" }) - product_type?: ProductType - - @ManyToOne(() => DiscountCondition, { onDelete: "CASCADE" }) - @JoinColumn({ name: "condition_id" }) - discount_condition?: DiscountCondition - - @CreateDateColumn({ type: resolveDbType("timestamptz") }) - created_at: Date - - @UpdateDateColumn({ type: resolveDbType("timestamptz") }) - updated_at: Date - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record -} - -/** - * @schema DiscountConditionProductType - * title: "Product Type Discount Condition" - * description: "This represents the association between a discount condition and a product type" - * type: object - * required: - * - condition_id - * - created_at - * - metadata - * - product_type_id - * - updated_at - * properties: - * product_type_id: - * description: The ID of the Product Tag - * type: string - * example: ptyp_01G8X9A7ESKAJXG2H0E6F1MW7A - * condition_id: - * description: The ID of the Discount Condition - * type: string - * example: discon_01G8X9A7ESKAJXG2H0E6F1MW7A - * product_type: - * description: The details of the product type. - * x-expandable: "product_type" - * nullable: true - * $ref: "#/components/schemas/ProductType" - * discount_condition: - * description: The details of the discount condition. - * x-expandable: "discount_condition" - * nullable: true - * $ref: "#/components/schemas/DiscountCondition" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/discount-condition-product.ts b/packages/medusa/src/models/discount-condition-product.ts deleted file mode 100644 index 4896de54c5..0000000000 --- a/packages/medusa/src/models/discount-condition-product.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { - CreateDateColumn, - Entity, - JoinColumn, - ManyToOne, - PrimaryColumn, - UpdateDateColumn, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { DiscountCondition } from "./discount-condition" -import { Product } from "./product" - -@Entity() -export class DiscountConditionProduct { - @PrimaryColumn() - product_id: string - - @PrimaryColumn() - condition_id: string - - @ManyToOne(() => Product, { onDelete: "CASCADE" }) - @JoinColumn({ name: "product_id" }) - product?: Product - - @ManyToOne(() => DiscountCondition, { onDelete: "CASCADE" }) - @JoinColumn({ name: "condition_id" }) - discount_condition?: DiscountCondition - - @CreateDateColumn({ type: resolveDbType("timestamptz") }) - created_at: Date - - @UpdateDateColumn({ type: resolveDbType("timestamptz") }) - updated_at: Date - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record -} - -/** - * @schema DiscountConditionProduct - * title: "Product Discount Condition" - * description: "This represents the association between a discount condition and a product" - * type: object - * required: - * - condition_id - * - created_at - * - metadata - * - product_id - * - updated_at - * properties: - * product_id: - * description: The ID of the Product Tag - * type: string - * example: prod_01G1G5V2MBA328390B5AXJ610F - * condition_id: - * description: The ID of the Discount Condition - * type: string - * example: discon_01G8X9A7ESKAJXG2H0E6F1MW7A - * product: - * description: The details of the product. - * x-expandable: "product" - * nullable: true - * $ref: "#/components/schemas/Product" - * discount_condition: - * description: The details of the discount condition. - * x-expandable: "discount_condition" - * nullable: true - * $ref: "#/components/schemas/DiscountCondition" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/discount-condition.ts b/packages/medusa/src/models/discount-condition.ts deleted file mode 100644 index 0d6d5cb995..0000000000 --- a/packages/medusa/src/models/discount-condition.ts +++ /dev/null @@ -1,270 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, - Relation, - Unique, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { DbAwareColumn } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" -import { CustomerGroup } from "./customer-group" -import { DiscountRule } from "./discount-rule" -import { Product } from "./product" -import { ProductCollection } from "./product-collection" -import { ProductTag } from "./product-tag" -import { ProductType } from "./product-type" - -/** - * @enum - * - * The discount condition's type. - */ -export enum DiscountConditionType { - /** - * The discount condition is used for products. - */ - PRODUCTS = "products", - /** - * The discount condition is used for product types. - */ - PRODUCT_TYPES = "product_types", - /** - * The discount condition is used for product collections. - */ - PRODUCT_COLLECTIONS = "product_collections", - /** - * The discount condition is used for product tags. - */ - PRODUCT_TAGS = "product_tags", - /** - * The discount condition is used for customer groups. - */ - CUSTOMER_GROUPS = "customer_groups", -} - -/** - * @enum - * - * The possible operators used for a discount condition. - */ -export enum DiscountConditionOperator { - /** - * The discountable resources are within the specified resources. - */ - IN = "in", - /** - * The discountable resources are everything but the specified resources. - */ - NOT_IN = "not_in", -} - -@Entity() -@Unique("dctypeuniq", ["type", "operator", "discount_rule_id"]) -export class DiscountCondition extends SoftDeletableEntity { - @DbAwareColumn({ - type: "enum", - enum: DiscountConditionType, - }) - type: DiscountConditionType - - @DbAwareColumn({ - type: "enum", - enum: DiscountConditionOperator, - }) - operator: DiscountConditionOperator - - @Index() - @Column() - discount_rule_id: string - - @ManyToOne(() => DiscountRule, (dr) => dr.conditions) - @JoinColumn({ name: "discount_rule_id" }) - discount_rule: Relation - - @ManyToMany(() => Product) - @JoinTable({ - name: "discount_condition_product", - joinColumn: { - name: "condition_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "product_id", - referencedColumnName: "id", - }, - }) - products: Product[] - - @ManyToMany(() => ProductType) - @JoinTable({ - name: "discount_condition_product_type", - joinColumn: { - name: "condition_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "product_type_id", - referencedColumnName: "id", - }, - }) - product_types: ProductType[] - - @ManyToMany(() => ProductTag) - @JoinTable({ - name: "discount_condition_product_tag", - joinColumn: { - name: "condition_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "product_tag_id", - referencedColumnName: "id", - }, - }) - product_tags: ProductTag[] - - @ManyToMany(() => ProductCollection) - @JoinTable({ - name: "discount_condition_product_collection", - joinColumn: { - name: "condition_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "product_collection_id", - referencedColumnName: "id", - }, - }) - product_collections: ProductCollection[] - - @ManyToMany(() => CustomerGroup) - @JoinTable({ - name: "discount_condition_customer_group", - joinColumn: { - name: "condition_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "customer_group_id", - referencedColumnName: "id", - }, - }) - customer_groups: CustomerGroup[] - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "discon") - } -} - -/** - * @schema DiscountCondition - * title: "Discount Condition" - * description: "Holds rule conditions for when a discount is applicable" - * type: object - * required: - * - created_at - * - deleted_at - * - discount_rule_id - * - id - * - metadata - * - operator - * - type - * - updated_at - * properties: - * id: - * description: The discount condition's ID - * type: string - * example: discon_01G8X9A7ESKAJXG2H0E6F1MW7A - * type: - * description: "The type of the condition. The type affects the available resources associated with the condition. For example, if the type is `products`, - * that means the `products` relation will hold the products associated with this condition and other relations will be empty." - * type: string - * enum: - * - products - * - product_types - * - product_collections - * - product_tags - * - customer_groups - * operator: - * description: >- - * The operator of the condition. `in` indicates that discountable resources are within the specified resources. `not_in` indicates that - * discountable resources are everything but the specified resources. - * type: string - * enum: - * - in - * - not_in - * discount_rule_id: - * description: The ID of the discount rule associated with the condition - * type: string - * example: dru_01F0YESMVK96HVX7N419E3CJ7C - * discount_rule: - * description: The details of the discount rule associated with the condition. - * x-expandable: "discount_rule" - * nullable: true - * $ref: "#/components/schemas/DiscountRule" - * products: - * description: products associated with this condition if `type` is `products`. - * type: array - * x-expandable: "products" - * items: - * $ref: "#/components/schemas/Product" - * product_types: - * description: Product types associated with this condition if `type` is `product_types`. - * type: array - * x-expandable: "product_types" - * items: - * $ref: "#/components/schemas/ProductType" - * product_tags: - * description: Product tags associated with this condition if `type` is `product_tags`. - * type: array - * x-expandable: "product_tags" - * items: - * $ref: "#/components/schemas/ProductTag" - * product_collections: - * description: Product collections associated with this condition if `type` is `product_collections`. - * type: array - * x-expandable: "product_collections" - * items: - * $ref: "#/components/schemas/ProductCollection" - * customer_groups: - * description: Customer groups associated with this condition if `type` is `customer_groups`. - * type: array - * x-expandable: "customer_groups" - * items: - * $ref: "#/components/schemas/CustomerGroup" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/discount-rule.ts b/packages/medusa/src/models/discount-rule.ts deleted file mode 100644 index 305cb7c3c8..0000000000 --- a/packages/medusa/src/models/discount-rule.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { BeforeInsert, Column, Entity, OneToMany } from "typeorm" - -import { DbAwareColumn } from "../utils/db-aware-column" -import { DiscountCondition } from "./discount-condition" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" - -/** - * @enum - * - * The possible types of discount rules. - */ -export enum DiscountRuleType { - /** - * Discounts that reduce the price by a fixed amount. - */ - FIXED = "fixed", - /** - * Discounts that reduce the price by a percentage reduction. - */ - PERCENTAGE = "percentage", - /** - * Discounts that sets the shipping price to `0`. - */ - FREE_SHIPPING = "free_shipping", -} - -/** - * @enum - * - * The scope that the discount should apply to. - */ -export enum AllocationType { - /** - * The discount should be applied to the checkout total. - */ - TOTAL = "total", - /** - * The discount should be applied to applicable items in the cart. - */ - ITEM = "item", -} - -@Entity() -export class DiscountRule extends SoftDeletableEntity { - @Column({ nullable: true }) - description: string - - @DbAwareColumn({ - type: "enum", - enum: DiscountRuleType, - }) - type: DiscountRuleType - - @Column() - value: number - - @DbAwareColumn({ - type: "enum", - enum: AllocationType, - nullable: true, - }) - allocation: AllocationType - - @OneToMany(() => DiscountCondition, (conditions) => conditions.discount_rule) - conditions: DiscountCondition[] - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "dru") - } -} - -/** - * @schema DiscountRule - * title: "Discount Rule" - * description: "A discount rule defines how a Discount is calculated when applied to a Cart." - * type: object - * required: - * - allocation - * - created_at - * - deleted_at - * - description - * - id - * - metadata - * - type - * - updated_at - * - value - * properties: - * id: - * description: The discount rule's ID - * type: string - * example: dru_01F0YESMVK96HVX7N419E3CJ7C - * type: - * description: >- - * The type of the Discount, can be `fixed` for discounts that reduce the price by a fixed amount, `percentage` for percentage reductions or `free_shipping` for shipping vouchers. - * type: string - * enum: - * - fixed - * - percentage - * - free_shipping - * example: percentage - * description: - * description: A short description of the discount - * nullable: true - * type: string - * example: 10 Percent - * value: - * description: The value that the discount represents; this will depend on the type of the discount - * type: integer - * example: 10 - * allocation: - * description: The scope that the discount should apply to. - * nullable: true - * type: string - * enum: - * - total - * - item - * example: total - * conditions: - * description: The details of the discount conditions associated with the rule. They can be used to limit when the discount can be used. - * type: array - * x-expandable: "conditions" - * items: - * $ref: "#/components/schemas/DiscountCondition" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/discount.ts b/packages/medusa/src/models/discount.ts deleted file mode 100644 index 5cfb9d04d8..0000000000 --- a/packages/medusa/src/models/discount.ts +++ /dev/null @@ -1,203 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" -import { DiscountRule } from "./discount-rule" -import { Region } from "./region" - -@Entity() -export class Discount extends SoftDeletableEntity { - @Index({ unique: true, where: "deleted_at IS NULL" }) - @Column() - code: string - - @Column() - is_dynamic: boolean - - @Index() - @Column({ nullable: true }) - rule_id: string - - @ManyToOne(() => DiscountRule, { cascade: true }) - @JoinColumn({ name: "rule_id" }) - rule: DiscountRule - - @Column() - is_disabled: boolean - - @Column({ nullable: true }) - parent_discount_id: string - - @ManyToOne(() => Discount) - @JoinColumn({ name: "parent_discount_id" }) - parent_discount: Discount - - @Column({ - type: resolveDbType("timestamptz"), - default: () => "CURRENT_TIMESTAMP", - }) - starts_at: Date - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - ends_at: Date | null - - @Column({ type: String, nullable: true }) - valid_duration: string | null - - @ManyToMany(() => Region, { cascade: true }) - @JoinTable({ - name: "discount_regions", - joinColumn: { - name: "discount_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "region_id", - referencedColumnName: "id", - }, - }) - regions: Region[] - - @Column({ type: Number, nullable: true }) - usage_limit: number | null - - @Column({ default: 0 }) - usage_count: number - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private upperCaseCodeAndTrim(): void { - this.code = this.code.toUpperCase().trim() - if (this.id) { - return - } - - this.id = generateEntityId(this.id, "disc") - } -} - -/** - * @schema Discount - * title: "Discount" - * description: "A discount can be applied to a cart for promotional purposes." - * type: object - * required: - * - code - * - created_at - * - deleted_at - * - ends_at - * - id - * - is_disabled - * - is_dynamic - * - metadata - * - parent_discount_id - * - rule_id - * - starts_at - * - updated_at - * - usage_count - * - usage_limit - * - valid_duration - * properties: - * id: - * description: The discount's ID - * type: string - * example: disc_01F0YESMW10MGHWJKZSDDMN0VN - * code: - * description: A unique code for the discount - this will be used by the customer to apply the discount - * type: string - * example: 10DISC - * is_dynamic: - * description: A flag to indicate if multiple instances of the discount can be generated. I.e. for newsletter discounts - * type: boolean - * example: false - * rule_id: - * description: The ID of the discount rule that defines how the discount will be applied to a cart. - * nullable: true - * type: string - * example: dru_01F0YESMVK96HVX7N419E3CJ7C - * rule: - * description: The details of the discount rule that defines how the discount will be applied to a cart.. - * x-expandable: "rule" - * nullable: true - * $ref: "#/components/schemas/DiscountRule" - * is_disabled: - * description: Whether the Discount has been disabled. Disabled discounts cannot be applied to carts - * type: boolean - * example: false - * parent_discount_id: - * description: The Discount that the discount was created from. This will always be a dynamic discount - * nullable: true - * type: string - * example: disc_01G8ZH853YPY9B94857DY91YGW - * parent_discount: - * description: The details of the parent discount that this discount was created from. - * x-expandable: "parent_discount" - * nullable: true - * $ref: "#/components/schemas/Discount" - * starts_at: - * description: The time at which the discount can be used. - * type: string - * format: date-time - * ends_at: - * description: The time at which the discount can no longer be used. - * nullable: true - * type: string - * format: date-time - * valid_duration: - * description: Duration the discount runs between - * nullable: true - * type: string - * example: P3Y6M4DT12H30M5S - * regions: - * description: The details of the regions in which the Discount can be used. - * type: array - * x-expandable: "regions" - * items: - * $ref: "#/components/schemas/Region" - * usage_limit: - * description: The maximum number of times that a discount can be used. - * nullable: true - * type: integer - * example: 100 - * usage_count: - * description: The number of times a discount has been used. - * type: integer - * example: 50 - * default: 0 - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/draft-order.ts b/packages/medusa/src/models/draft-order.ts deleted file mode 100644 index 95e451bc6d..0000000000 --- a/packages/medusa/src/models/draft-order.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Generated, - Index, - JoinColumn, - OneToOne, - Relation, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { BaseEntity } from "../interfaces/models/base-entity" -import { generateEntityId } from "../utils/generate-entity-id" -import { manualAutoIncrement } from "../utils/manual-auto-increment" -import { Cart } from "./cart" -import { Order } from "./order" - -/** - * @enum - * - * The draft order's status. - */ -export enum DraftOrderStatus { - /** - * The draft order is open. - */ - OPEN = "open", - /** - * The draft order is completed, and an order has been created from it. - */ - COMPLETED = "completed", -} - -@Entity() -export class DraftOrder extends BaseEntity { - @DbAwareColumn({ type: "enum", enum: DraftOrderStatus, default: "open" }) - status: DraftOrderStatus - - @Index() - @Column() - @Generated("increment") - display_id: number - - @Index() - @Column({ nullable: true }) - cart_id: string - - @OneToOne(() => Cart, { onDelete: "CASCADE" }) - @JoinColumn({ name: "cart_id" }) - cart: Relation - - @Index() - @Column({ nullable: true }) - order_id: string - - @OneToOne(() => Order) - @JoinColumn({ name: "order_id" }) - order: Relation - - @Column({ nullable: true, type: resolveDbType("timestamptz") }) - canceled_at: Date - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - completed_at: Date - - @Column({ nullable: true }) - no_notification_order: boolean - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - @Column({ nullable: true }) - idempotency_key: string - - /** - * @apiIgnore - */ - @BeforeInsert() - private async beforeInsert(): Promise { - this.id = generateEntityId(this.id, "dorder") - - if (process.env.NODE_ENV === "development" && !this.display_id) { - const disId = await manualAutoIncrement("draft_order") - - if (disId) { - this.display_id = disId - } - } - } -} - -/** - * @schema DraftOrder - * title: "DraftOrder" - * description: "A draft order is created by an admin without direct involvement of the customer. Once its payment is marked as captured, it is transformed into an order." - * type: object - * required: - * - canceled_at - * - cart_id - * - completed_at - * - created_at - * - display_id - * - id - * - idempotency_key - * - metadata - * - no_notification_order - * - order_id - * - status - * - updated_at - * properties: - * id: - * description: The draft order's ID - * type: string - * example: dorder_01G8TJFKBG38YYFQ035MSVG03C - * status: - * description: The status of the draft order. It's changed to `completed` when it's transformed to an order. - * type: string - * enum: - * - open - * - completed - * default: open - * display_id: - * description: The draft order's display ID - * type: string - * example: 2 - * cart_id: - * description: The ID of the cart associated with the draft order. - * nullable: true - * type: string - * example: cart_01G8ZH853Y6TFXWPG5EYE81X63 - * cart: - * description: The details of the cart associated with the draft order. - * x-expandable: "cart" - * nullable: true - * $ref: "#/components/schemas/Cart" - * order_id: - * description: The ID of the order created from the draft order when its payment is captured. - * nullable: true - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * order: - * description: The details of the order created from the draft order when its payment is captured. - * x-expandable: "order" - * nullable: true - * $ref: "#/components/schemas/Order" - * canceled_at: - * description: The date the draft order was canceled at. - * nullable: true - * type: string - * format: date-time - * completed_at: - * description: The date the draft order was completed at. - * nullable: true - * type: string - * format: date-time - * no_notification_order: - * description: Whether to send the customer notifications regarding order updates. - * nullable: true - * type: boolean - * example: false - * idempotency_key: - * description: Randomly generated key used to continue the completion of the cart associated with the draft order in case of failure. - * nullable: true - * type: string - * externalDocs: - * url: https://docs.medusajs.com/development/idempotency-key/overview.md - * description: Learn more how to use the idempotency key. - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/fulfillment-item.ts b/packages/medusa/src/models/fulfillment-item.ts deleted file mode 100644 index 17ae0a60b3..0000000000 --- a/packages/medusa/src/models/fulfillment-item.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { - Column, - Entity, - JoinColumn, - ManyToOne, - PrimaryColumn, - Relation, -} from "typeorm" - -import { Fulfillment } from "./fulfillment" -import { LineItem } from "./line-item" - -@Entity() -export class FulfillmentItem { - @PrimaryColumn() - fulfillment_id: string - - @PrimaryColumn() - item_id: string - - @ManyToOne(() => Fulfillment) - @JoinColumn({ name: "fulfillment_id" }) - fulfillment: Relation - - @ManyToOne(() => LineItem) - @JoinColumn({ name: "item_id" }) - item: Relation - - @Column({ type: "int" }) - quantity: number -} - -/** - * @schema FulfillmentItem - * title: "Fulfillment Item" - * description: "This represents the association between a Line Item and a Fulfillment." - * type: object - * required: - * - fulfillment_id - * - item_id - * - quantity - * properties: - * fulfillment_id: - * description: The ID of the Fulfillment that the Fulfillment Item belongs to. - * type: string - * example: ful_01G8ZRTMQCA76TXNAT81KPJZRF - * item_id: - * description: The ID of the Line Item that the Fulfillment Item references. - * type: string - * example: item_01G8ZC9GWT6B2GP5FSXRXNFNGN - * fulfillment: - * description: The details of the fulfillment. - * x-expandable: "fulfillment" - * nullable: true - * $ref: "#/components/schemas/Fulfillment" - * item: - * description: The details of the line item. - * x-expandable: "item" - * nullable: true - * $ref: "#/components/schemas/LineItem" - * quantity: - * description: The quantity of the Line Item that is included in the Fulfillment. - * type: integer - * example: 1 - */ diff --git a/packages/medusa/src/models/fulfillment-provider.ts b/packages/medusa/src/models/fulfillment-provider.ts deleted file mode 100644 index b750d2c321..0000000000 --- a/packages/medusa/src/models/fulfillment-provider.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Column, Entity, PrimaryColumn } from "typeorm" - -@Entity() -export class FulfillmentProvider { - @PrimaryColumn() - id: string - - @Column({ default: true }) - is_installed: boolean -} - -/** - * @schema FulfillmentProvider - * title: "Fulfillment Provider" - * description: "A fulfillment provider represents a fulfillment service installed in the Medusa backend, either through a plugin or backend customizations. - * It holds the fulfillment service's installation status." - * type: object - * required: - * - id - * - is_installed - * properties: - * id: - * description: The ID of the fulfillment provider as given by the fulfillment service. - * type: string - * example: manual - * is_installed: - * description: Whether the fulfillment service is installed in the current version. If a fulfillment service is no longer installed, the `is_installed` attribute is set to `false`. - * type: boolean - * default: true - */ diff --git a/packages/medusa/src/models/fulfillment.ts b/packages/medusa/src/models/fulfillment.ts deleted file mode 100644 index 090893a3bd..0000000000 --- a/packages/medusa/src/models/fulfillment.ts +++ /dev/null @@ -1,230 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - OneToMany, - Relation, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { BaseEntity } from "../interfaces/models/base-entity" -import { generateEntityId } from "../utils/generate-entity-id" -import { ClaimOrder } from "./claim-order" -import { FulfillmentItem } from "./fulfillment-item" -import { FulfillmentProvider } from "./fulfillment-provider" -import { Order } from "./order" -import { Swap } from "./swap" -import { TrackingLink } from "./tracking-link" - -@Entity() -export class Fulfillment extends BaseEntity { - @Index() - @Column({ nullable: true }) - claim_order_id: string - - @ManyToOne(() => ClaimOrder, (co) => co.fulfillments) - @JoinColumn({ name: "claim_order_id" }) - claim_order: Relation - - @Index() - @Column({ nullable: true }) - swap_id: string - - @ManyToOne(() => Swap, (swap) => swap.fulfillments) - @JoinColumn({ name: "swap_id" }) - swap: Swap - - @Index() - @Column({ nullable: true }) - order_id: string - - @ManyToOne(() => Order, (o) => o.fulfillments) - @JoinColumn({ name: "order_id" }) - order: Relation - - @Column({ type: "boolean", nullable: true }) - no_notification: boolean - - @Index() - @Column() - provider_id: string - - @Column({ nullable: true, type: "text" }) - location_id: string | null - - @ManyToOne(() => FulfillmentProvider) - @JoinColumn({ name: "provider_id" }) - provider: Relation - - @OneToMany(() => FulfillmentItem, (i) => i.fulfillment, { - eager: true, - cascade: true, - }) - items: Relation[] - - @OneToMany(() => TrackingLink, (tl) => tl.fulfillment, { - cascade: ["insert"], - }) - tracking_links: Relation[] - - @DbAwareColumn({ type: "jsonb", default: [] }) - tracking_numbers: string[] - - @DbAwareColumn({ type: "jsonb" }) - data: Record - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - shipped_at: Date - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - canceled_at: Date - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - @Column({ nullable: true }) - idempotency_key: string - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "ful") - } -} - -/** - * @schema Fulfillment - * title: "Fulfillment" - * description: "A Fulfillment is created once an admin can prepare the purchased goods. Fulfillments will eventually be shipped and hold information about how to track shipments. Fulfillments are created through a fulfillment provider, which typically integrates a third-party shipping service. Fulfillments can be associated with orders, claims, swaps, and returns." - * type: object - * required: - * - canceled_at - * - claim_order_id - * - created_at - * - data - * - id - * - idempotency_key - * - location_id - * - metadata - * - no_notification - * - order_id - * - provider_id - * - shipped_at - * - swap_id - * - tracking_numbers - * - updated_at - * properties: - * id: - * description: The fulfillment's ID - * type: string - * example: ful_01G8ZRTMQCA76TXNAT81KPJZRF - * claim_order_id: - * description: The ID of the Claim that the Fulfillment belongs to. - * nullable: true - * type: string - * example: null - * claim_order: - * description: The details of the claim that the fulfillment may belong to. - * x-expandable: "claim_order" - * nullable: true - * $ref: "#/components/schemas/ClaimOrder" - * swap_id: - * description: The ID of the Swap that the Fulfillment belongs to. - * nullable: true - * type: string - * example: null - * swap: - * description: The details of the swap that the fulfillment may belong to. - * x-expandable: "swap" - * nullable: true - * $ref: "#/components/schemas/Swap" - * order_id: - * description: The ID of the Order that the Fulfillment belongs to. - * nullable: true - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * order: - * description: The details of the order that the fulfillment may belong to. - * x-expandable: "order" - * nullable: true - * $ref: "#/components/schemas/Order" - * provider_id: - * description: The ID of the Fulfillment Provider responsible for handling the fulfillment. - * type: string - * example: manual - * provider: - * description: The details of the fulfillment provider responsible for handling the fulfillment. - * x-expandable: "provider" - * nullable: true - * $ref: "#/components/schemas/FulfillmentProvider" - * location_id: - * description: The ID of the stock location the fulfillment will be shipped from - * nullable: true - * type: string - * example: sloc_01G8TJSYT9M6AVS5N4EMNFS1EK - * items: - * description: The Fulfillment Items in the Fulfillment. These hold information about how many of each Line Item has been fulfilled. - * type: array - * x-expandable: "items" - * items: - * $ref: "#/components/schemas/FulfillmentItem" - * tracking_links: - * description: The Tracking Links that can be used to track the status of the Fulfillment. These will usually be provided by the Fulfillment Provider. - * type: array - * x-expandable: "tracking_links" - * items: - * $ref: "#/components/schemas/TrackingLink" - * tracking_numbers: - * description: The tracking numbers that can be used to track the status of the fulfillment. - * deprecated: true - * type: array - * items: - * type: string - * data: - * description: This contains all the data necessary for the Fulfillment provider to handle the fulfillment. - * type: object - * example: {} - * shipped_at: - * description: The date with timezone at which the Fulfillment was shipped. - * nullable: true - * type: string - * format: date-time - * no_notification: - * description: Flag for describing whether or not notifications related to this should be sent. - * nullable: true - * type: boolean - * example: false - * canceled_at: - * description: The date with timezone at which the Fulfillment was canceled. - * nullable: true - * type: string - * format: date-time - * idempotency_key: - * description: Randomly generated key used to continue the completion of the fulfillment in case of failure. - * nullable: true - * type: string - * externalDocs: - * url: https://docs.medusajs.com/development/idempotency-key/overview.md - * description: Learn more how to use the idempotency key. - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/gift-card-transaction.ts b/packages/medusa/src/models/gift-card-transaction.ts deleted file mode 100644 index a3b33cc71c..0000000000 --- a/packages/medusa/src/models/gift-card-transaction.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { - BeforeInsert, - Column, - CreateDateColumn, - Entity, - Index, - JoinColumn, - ManyToOne, - PrimaryColumn, - Relation, - Unique, -} from "typeorm" - -import { resolveDbType } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" -import { GiftCard } from "./gift-card" -import { Order } from "./order" - -@Unique("gcuniq", ["gift_card_id", "order_id"]) -@Entity() -export class GiftCardTransaction { - @PrimaryColumn() - id: string - - @Column() - gift_card_id: string - - @ManyToOne(() => GiftCard) - @JoinColumn({ name: "gift_card_id" }) - gift_card: Relation - - @Index() - @Column() - order_id: string - - @ManyToOne(() => Order) - @JoinColumn({ name: "order_id" }) - order: Relation - - @Column("int") - amount: number - - @CreateDateColumn({ type: resolveDbType("timestamptz") }) - created_at: Date - - @Column({ nullable: true }) - is_taxable: boolean - - @Column({ type: "real", nullable: true }) - tax_rate: number | null - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "gct") - } -} - -/** - * @schema GiftCardTransaction - * title: "Gift Card Transaction" - * description: "Gift Card Transactions are created once a Customer uses a Gift Card to pay for their Order." - * type: object - * required: - * - amount - * - created_at - * - gift_card_id - * - id - * - is_taxable - * - order_id - * - tax_rate - * properties: - * id: - * description: The gift card transaction's ID - * type: string - * example: gct_01G8X9A7ESKAJXG2H0E6F1MW7A - * gift_card_id: - * description: The ID of the Gift Card that was used in the transaction. - * type: string - * example: gift_01G8XKBPBQY2R7RBET4J7E0XQZ - * gift_card: - * description: The details of the gift card associated used in this transaction. - * x-expandable: "gift_card" - * nullable: true - * $ref: "#/components/schemas/GiftCard" - * order_id: - * description: The ID of the order that the gift card was used for payment. - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * order: - * description: The details of the order that the gift card was used for payment. - * x-expandable: "order" - * nullable: true - * $ref: "#/components/schemas/Order" - * amount: - * description: The amount that was used from the Gift Card. - * type: integer - * example: 10 - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * is_taxable: - * description: Whether the transaction is taxable or not. - * nullable: true - * type: boolean - * example: false - * tax_rate: - * description: The tax rate of the transaction - * nullable: true - * type: number - * example: 0 - */ diff --git a/packages/medusa/src/models/gift-card.ts b/packages/medusa/src/models/gift-card.ts deleted file mode 100644 index f8b6768517..0000000000 --- a/packages/medusa/src/models/gift-card.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - Relation, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" -import { Order } from "./order" -import { Region } from "./region" - -@Entity() -export class GiftCard extends SoftDeletableEntity { - @Index({ unique: true }) - @Column() - code: string - - @Column("int") - value: number - - @Column("int") - balance: number - - @Index() - @Column() - region_id: string - - @ManyToOne(() => Region) - @JoinColumn({ name: "region_id" }) - region: Relation - - @Index() - @Column({ nullable: true }) - order_id: string - - @ManyToOne(() => Order) - @JoinColumn({ name: "order_id" }) - order: Relation - - @Column({ default: false }) - is_disabled: boolean - - @Column({ - type: resolveDbType("timestamptz"), - nullable: true, - }) - ends_at: Date - - @Column({ type: "real", nullable: true }) - tax_rate: number | null - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "gift") - } -} - -/** - * @schema GiftCard - * title: "Gift Card" - * description: "Gift Cards are redeemable and represent a value that can be used towards the payment of an Order." - * type: object - * required: - * - balance - * - code - * - created_at - * - deleted_at - * - ends_at - * - id - * - is_disabled - * - metadata - * - order_id - * - region_id - * - tax_rate - * - updated_at - * - value - * properties: - * id: - * description: The gift card's ID - * type: string - * example: gift_01G8XKBPBQY2R7RBET4J7E0XQZ - * code: - * description: The unique code that identifies the Gift Card. This is used by the Customer to redeem the value of the Gift Card. - * type: string - * example: 3RFT-MH2C-Y4YZ-XMN4 - * value: - * description: The value that the Gift Card represents. - * type: integer - * example: 10 - * balance: - * description: The remaining value on the Gift Card. - * type: integer - * example: 10 - * region_id: - * description: The ID of the region this gift card is available in. - * type: string - * example: reg_01G1G5V26T9H8Y0M4JNE3YGA4G - * region: - * description: The details of the region this gift card is available in. - * x-expandable: "region" - * nullable: true - * $ref: "#/components/schemas/Region" - * order_id: - * description: The ID of the order that the gift card was purchased in. - * nullable: true - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * order: - * description: The details of the order that the gift card was purchased in. - * x-expandable: "region" - * nullable: true - * $ref: "#/components/schemas/Order" - * is_disabled: - * description: Whether the Gift Card has been disabled. Disabled Gift Cards cannot be applied to carts. - * type: boolean - * default: false - * ends_at: - * description: The time at which the Gift Card can no longer be used. - * nullable: true - * type: string - * format: date-time - * tax_rate: - * description: The gift card's tax rate that will be applied on calculating totals - * nullable: true - * type: number - * example: 0 - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/image.ts b/packages/medusa/src/models/image.ts deleted file mode 100644 index 31f13005f4..0000000000 --- a/packages/medusa/src/models/image.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { BeforeInsert, Column, Entity } from "typeorm" - -import { DbAwareColumn } from "../utils/db-aware-column" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class Image extends SoftDeletableEntity { - @Column() - url: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "img") - } -} - -/** - * @schema Image - * title: "Image" - * description: "An Image is used to store details about uploaded images. Images are uploaded by the File Service, and the URL is provided by the File Service." - * type: object - * required: - * - created_at - * - deleted_at - * - id - * - metadata - * - updated_at - * - url - * properties: - * id: - * type: string - * description: The image's ID - * example: img_01G749BFYR6T8JTVW6SGW3K3E6 - * url: - * description: The URL at which the image file can be found. - * type: string - * format: uri - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/index.ts b/packages/medusa/src/models/index.ts index 87bd96d8ef..93db1cf7c0 100644 --- a/packages/medusa/src/models/index.ts +++ b/packages/medusa/src/models/index.ts @@ -1,80 +1,2 @@ -export * from "./address" -export * from "./analytics-config" -export * from "./batch-job" -export * from "./cart" -export * from "./claim-image" -export * from "./claim-item" -export * from "./claim-order" -export * from "./claim-tag" -export * from "./country" -export * from "./currency" -export * from "./custom-shipping-option" -export * from "./customer" -export * from "./customer-group" -export * from "./discount" -export * from "./discount-condition" -export * from "./discount-condition-customer-group" -export * from "./discount-condition-product" -export * from "./discount-condition-product-collection" -export * from "./discount-condition-product-tag" -export * from "./discount-condition-product-type" -export * from "./discount-rule" -export * from "./draft-order" -export * from "./fulfillment" -export * from "./fulfillment-item" -export * from "./fulfillment-provider" -export * from "./gift-card" -export * from "./gift-card-transaction" export * from "./idempotency-key" -export * from "./image" -export * from "./invite" -export * from "./line-item" -export * from "./line-item-adjustment" -export * from "./line-item-tax-line" -export * from "./money-amount" -export * from "./note" -export * from "./notification-provider" -export * from "./notification" -export * from "./oauth" -export * from "./order" -export * from "./order-edit" -export * from "./order-item-change" -export * from "./payment" -export * from "./payment-collection" -export * from "./payment-provider" -export * from "./payment-session" -export * from "./price-list" -export * from "./product" -export * from "./product-category" -export * from "./product-collection" -export * from "./product-option" -export * from "./product-option-value" -export * from "./product-tag" -export * from "./product-tax-rate" -export * from "./product-type" -export * from "./product-type-tax-rate" -export * from "./product-variant" -export * from "./product-variant-inventory-item" -export * from "./product-variant-money-amount" -export * from "./publishable-api-key" -export * from "./publishable-api-key-sales-channel" -export * from "./refund" -export * from "./region" -export * from "./return" -export * from "./return-item" -export * from "./return-reason" -export * from "./sales-channel" -export * from "./sales-channel-location" -export * from "./shipping-method" -export * from "./shipping-method-tax-line" -export * from "./shipping-option" -export * from "./shipping-option-requirement" -export * from "./shipping-profile" -export * from "./shipping-tax-rate" export * from "./staged-job" -export * from "./store" -export * from "./swap" -export * from "./tax-provider" -export * from "./tax-rate" -export * from "./tracking-link" -export * from "./user" diff --git a/packages/medusa/src/models/invite.ts b/packages/medusa/src/models/invite.ts deleted file mode 100644 index 5dcfe49a9a..0000000000 --- a/packages/medusa/src/models/invite.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { BeforeInsert, Column, CreateDateColumn, Entity, Index } from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { UserRoles } from "./user" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class Invite extends SoftDeletableEntity { - @Index({ unique: true, where: "deleted_at IS NULL" }) - @Column() - user_email: string - - @DbAwareColumn({ - type: "enum", - enum: UserRoles, - nullable: true, - default: UserRoles.MEMBER, - }) - role: UserRoles - - @Column({ default: false }) - accepted: boolean - - @Column() - token: string - - @CreateDateColumn({ type: resolveDbType("timestamptz") }) - expires_at: Date - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "invite") - } -} - -/** - * @schema Invite - * title: "Invite" - * description: "An invite is created when an admin user invites a new user to join the store's team. Once the invite is accepted, it's deleted." - * type: object - * required: - * - accepted - * - created_at - * - deleted_at - * - expires_at - * - id - * - metadata - * - role - * - token - * - updated_at - * - user_email - * properties: - * id: - * type: string - * description: The invite's ID - * example: invite_01G8TKE4XYCTHSCK2GDEP47RE1 - * user_email: - * description: The email of the user being invited. - * type: string - * format: email - * role: - * description: The user's role. These roles don't change the privileges of the user. - * nullable: true - * type: string - * enum: - * - admin - * - member - * - developer - * default: member - * accepted: - * description: Whether the invite was accepted or not. - * type: boolean - * default: false - * token: - * description: The token used to accept the invite. - * type: string - * expires_at: - * description: The date the invite expires at. - * type: string - * format: date-time - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/line-item-adjustment.ts b/packages/medusa/src/models/line-item-adjustment.ts deleted file mode 100644 index d253af1c05..0000000000 --- a/packages/medusa/src/models/line-item-adjustment.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - PrimaryColumn, - Relation, -} from "typeorm" - -import { DbAwareColumn, generateEntityId } from "../utils" -import { Discount } from "./discount" -import { LineItem } from "./line-item" - -@Entity() -@Index(["discount_id", "item_id"], { - unique: true, - where: `"discount_id" IS NOT NULL`, -}) -export class LineItemAdjustment { - @PrimaryColumn() - id: string - - @Index() - @Column() - item_id: string - - @ManyToOne(() => LineItem, (li) => li.adjustments, { onDelete: "CASCADE" }) - @JoinColumn({ name: "item_id" }) - item: Relation - - @Column() - description: string - - @ManyToOne(() => Discount) - @JoinColumn({ name: "discount_id" }) - discount: Relation - - @Index() - @Column({ nullable: true }) - discount_id: string - - @Column({ - type: "numeric", - transformer: { to: (value) => value, from: (value) => parseFloat(value) }, - }) - amount: number - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "lia") - } -} - -/** - * @schema LineItemAdjustment - * title: "Line Item Adjustment" - * description: "A Line Item Adjustment includes details on discounts applied on a line item." - * type: object - * required: - * - amount - * - description - * - discount_id - * - id - * - item_id - * - metadata - * properties: - * id: - * description: The Line Item Adjustment's ID - * type: string - * example: lia_01G8TKE4XYCTHSCK2GDEP47RE1 - * item_id: - * description: The ID of the line item - * type: string - * example: item_01G8ZC9GWT6B2GP5FSXRXNFNGN - * item: - * description: The details of the line item. - * x-expandable: "item" - * nullable: true - * $ref: "#/components/schemas/LineItem" - * description: - * description: The line item's adjustment description - * type: string - * example: Adjusted item's price. - * discount_id: - * description: The ID of the discount associated with the adjustment - * nullable: true - * type: string - * example: disc_01F0YESMW10MGHWJKZSDDMN0VN - * discount: - * description: The details of the discount associated with the adjustment. - * x-expandable: "discount" - * nullable: true - * $ref: "#/components/schemas/Discount" - * amount: - * description: The adjustment amount - * type: number - * example: 1000 - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/line-item-tax-line.ts b/packages/medusa/src/models/line-item-tax-line.ts deleted file mode 100644 index 1e1d102dcc..0000000000 --- a/packages/medusa/src/models/line-item-tax-line.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - Relation, - Unique, -} from "typeorm" - -import { generateEntityId } from "../utils/generate-entity-id" -import { LineItem } from "./line-item" -import { TaxLine } from "./tax-line" - -@Entity() -@Unique(["item_id", "code"]) -export class LineItemTaxLine extends TaxLine { - @Index() - @Column() - item_id: string - - @ManyToOne(() => LineItem, (li) => li.tax_lines) - @JoinColumn({ name: "item_id" }) - item: Relation - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "litl") - } -} - -/** - * @schema LineItemTaxLine - * title: "Line Item Tax Line" - * description: "A Line Item Tax Line represents the taxes applied on a line item." - * type: object - * required: - * - code - * - created_at - * - id - * - item_id - * - metadata - * - name - * - rate - * - updated_at - * properties: - * id: - * description: The line item tax line's ID - * type: string - * example: litl_01G1G5V2DRX1SK6NQQ8VVX4HQ8 - * code: - * description: A code to identify the tax type by - * nullable: true - * type: string - * example: tax01 - * name: - * description: A human friendly name for the tax - * type: string - * example: Tax Example - * rate: - * description: The numeric rate to charge tax by - * type: number - * example: 10 - * item_id: - * description: The ID of the line item - * type: string - * example: item_01G8ZC9GWT6B2GP5FSXRXNFNGN - * item: - * description: The details of the line item. - * x-expandable: "item" - * nullable: true - * $ref: "#/components/schemas/LineItem" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/line-item.ts b/packages/medusa/src/models/line-item.ts deleted file mode 100644 index d33f7c58fb..0000000000 --- a/packages/medusa/src/models/line-item.ts +++ /dev/null @@ -1,440 +0,0 @@ -import { - AfterLoad, - AfterUpdate, - BeforeInsert, - BeforeUpdate, - Check, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - OneToMany, - Relation, -} from "typeorm" - -import { MedusaV2Flag } from "@medusajs/utils" -import { BaseEntity } from "../interfaces" -import { featureFlagRouter } from "../loaders/feature-flags" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { DbAwareColumn, generateEntityId } from "../utils" -import { - FeatureFlagColumn, - FeatureFlagDecorators, -} from "../utils/feature-flag-decorators" -import { Cart } from "./cart" -import { ClaimOrder } from "./claim-order" -import { LineItemAdjustment } from "./line-item-adjustment" -import { LineItemTaxLine } from "./line-item-tax-line" -import { Order } from "./order" -import { OrderEdit } from "./order-edit" -import { ProductVariant } from "./product-variant" -import { Swap } from "./swap" - -@Check(`"fulfilled_quantity" <= "quantity"`) -@Check(`"shipped_quantity" <= "fulfilled_quantity"`) -@Check(`"returned_quantity" <= "quantity"`) -@Check(`"quantity" > 0`) -@Index( - "unique_li_original_item_id_order_edit_id", - ["order_edit_id", "original_item_id"], - { - unique: true, - where: "original_item_id IS NOT NULL AND order_edit_id IS NOT NULL", - } -) -@Entity() -export class LineItem extends BaseEntity { - @Index() - @Column({ nullable: true }) - cart_id: string - - @ManyToOne(() => Cart, (cart) => cart.items) - @JoinColumn({ name: "cart_id" }) - cart: Relation - - @Index() - @Column({ nullable: true }) - order_id: string | null - - @ManyToOne(() => Order, (order) => order.items) - @JoinColumn({ name: "order_id" }) - order: Relation - - @Index() - @Column({ nullable: true }) - swap_id: string - - @ManyToOne(() => Swap, (swap) => swap.additional_items) - @JoinColumn({ name: "swap_id" }) - swap: Relation - - @Index() - @Column({ nullable: true }) - claim_order_id: string - - @ManyToOne(() => ClaimOrder, (co) => co.additional_items) - @JoinColumn({ name: "claim_order_id" }) - claim_order: Relation - - @OneToMany(() => LineItemTaxLine, (tl) => tl.item, { - cascade: ["insert", "remove"], - }) - tax_lines: Relation[] - - @OneToMany(() => LineItemAdjustment, (lia) => lia.item, { - cascade: ["insert", "remove"], - }) - adjustments: Relation[] - - @Column({ nullable: true, type: "varchar" }) - original_item_id?: string | null - - @Column({ nullable: true, type: "varchar" }) - order_edit_id?: string | null - - @ManyToOne(() => OrderEdit, (orderEdit) => orderEdit.items) - @JoinColumn({ name: "order_edit_id" }) - order_edit?: Relation | null - - @Column() - title: string - - @Column({ nullable: true, type: "text" }) - description: string | null - - @Column({ type: "text", nullable: true }) - thumbnail: string | null - - @Column({ default: false }) - is_return: boolean - - @Column({ default: false }) - is_giftcard: boolean - - @Column({ default: true }) - should_merge: boolean - - @Column({ default: true }) - allow_discounts: boolean - - @Column({ nullable: true, type: "boolean" }) - has_shipping: boolean | null - - @Column({ type: "int" }) - unit_price: number - - @Index() - @Column({ nullable: true, type: "text" }) - variant_id: string | null - - @ManyToOne(() => ProductVariant) - @JoinColumn({ name: "variant_id" }) - variant: Relation - - @FeatureFlagColumn(MedusaV2Flag.key, { nullable: true, type: "text" }) - product_id: string | null - - @Column({ type: "int" }) - quantity: number - - @Column({ nullable: true, type: "int" }) - fulfilled_quantity: number | null - - @Column({ nullable: true, type: "int" }) - returned_quantity: number | null - - @Column({ nullable: true, type: "int" }) - shipped_quantity: number | null - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - @FeatureFlagColumn(TaxInclusivePricingFeatureFlag.key, { default: false }) - includes_tax: boolean - - refundable?: number | null - subtotal?: number | null - tax_total?: number | null - total?: number | null - original_total?: number | null - original_tax_total?: number | null - discount_total?: number | null - raw_discount_total?: number | null - gift_card_total?: number | null - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "item") - - // This is to maintain compatibility while isolating the product domain - if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) { - if ( - this.variant && - Object.keys(this.variant).length === 1 && - this.variant.product_id - ) { - this.variant = undefined as any - } - } - } - - /** - * @apiIgnore - */ - @FeatureFlagDecorators(MedusaV2Flag.key, [BeforeUpdate()]) - beforeUpdate(): void { - if ( - this.variant && - Object.keys(this.variant).length === 1 && - this.variant.product_id - ) { - this.variant = undefined as any - } - } - - /** - * @apiIgnore - */ - @FeatureFlagDecorators(MedusaV2Flag.key, [AfterLoad(), AfterUpdate()]) - afterUpdateOrLoad(): void { - if (this.variant) { - return - } - - if (this.product_id) { - this.variant = { product_id: this.product_id } as any - } - } -} - -/** - * @schema LineItem - * title: "Line Item" - * description: "Line Items are created when a product is added to a Cart. When Line Items are purchased they will get copied to the resulting order, swap, or claim, and can eventually be referenced in Fulfillments and Returns. Line items may also be used for order edits." - * type: object - * required: - * - allow_discounts - * - cart_id - * - claim_order_id - * - created_at - * - description - * - fulfilled_quantity - * - has_shipping - * - id - * - is_giftcard - * - is_return - * - metadata - * - order_edit_id - * - order_id - * - original_item_id - * - quantity - * - returned_quantity - * - shipped_quantity - * - should_merge - * - swap_id - * - thumbnail - * - title - * - unit_price - * - updated_at - * - variant_id - * properties: - * id: - * description: The line item's ID - * type: string - * example: item_01G8ZC9GWT6B2GP5FSXRXNFNGN - * cart_id: - * description: The ID of the cart that the line item may belongs to. - * nullable: true - * type: string - * example: cart_01G8ZH853Y6TFXWPG5EYE81X63 - * cart: - * description: The details of the cart that the line item may belongs to. - * x-expandable: "cart" - * nullable: true - * $ref: "#/components/schemas/Cart" - * order_id: - * description: The ID of the order that the line item may belongs to. - * nullable: true - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * order: - * description: The details of the order that the line item may belongs to. - * x-expandable: "order" - * nullable: true - * $ref: "#/components/schemas/Order" - * swap_id: - * description: The ID of the swap that the line item may belong to. - * nullable: true - * type: string - * example: null - * swap: - * description: The details of the swap that the line item may belong to. - * x-expandable: "swap" - * nullable: true - * $ref: "#/components/schemas/Swap" - * claim_order_id: - * description: The ID of the claim that the line item may belong to. - * nullable: true - * type: string - * example: null - * claim_order: - * description: The details of the claim that the line item may belong to. - * x-expandable: "claim_order" - * nullable: true - * $ref: "#/components/schemas/ClaimOrder" - * tax_lines: - * description: The details of the item's tax lines. - * x-expandable: "tax_lines" - * type: array - * items: - * $ref: "#/components/schemas/LineItemTaxLine" - * adjustments: - * description: The details of the item's adjustments, which are available when a discount is applied on the item. - * x-expandable: "adjustments" - * type: array - * items: - * $ref: "#/components/schemas/LineItemAdjustment" - * original_item_id: - * description: The ID of the original line item. This is useful if the line item belongs to a resource that references an order, such as a return or an order edit. - * nullable: true - * type: string - * order_edit_id: - * description: The ID of the order edit that the item may belong to. - * nullable: true - * type: string - * order_edit: - * description: The details of the order edit. - * x-expandable: "order_edit" - * nullable: true - * $ref: "#/components/schemas/OrderEdit" - * title: - * description: The title of the Line Item. - * type: string - * example: Medusa Coffee Mug - * description: - * description: A more detailed description of the contents of the Line Item. - * nullable: true - * type: string - * example: One Size - * thumbnail: - * description: A URL string to a small image of the contents of the Line Item. - * nullable: true - * type: string - * format: uri - * example: https://medusa-public-images.s3.eu-west-1.amazonaws.com/coffee-mug.png - * is_return: - * description: Is the item being returned - * type: boolean - * default: false - * is_giftcard: - * description: Flag to indicate if the Line Item is a Gift Card. - * type: boolean - * default: false - * should_merge: - * description: Flag to indicate if new Line Items with the same variant should be merged or added as an additional Line Item. - * type: boolean - * default: true - * allow_discounts: - * description: Flag to indicate if the Line Item should be included when doing discount calculations. - * type: boolean - * default: true - * has_shipping: - * description: Flag to indicate if the Line Item has fulfillment associated with it. - * nullable: true - * type: boolean - * example: false - * unit_price: - * description: The price of one unit of the content in the Line Item. This should be in the currency defined by the Cart/Order/Swap/Claim that the Line Item belongs to. - * type: integer - * example: 8000 - * variant_id: - * description: The id of the Product Variant contained in the Line Item. - * nullable: true - * type: string - * example: variant_01G1G5V2MRX2V3PVSR2WXYPFB6 - * variant: - * description: The details of the product variant that this item was created from. - * x-expandable: "variant" - * nullable: true - * $ref: "#/components/schemas/ProductVariant" - * quantity: - * description: The quantity of the content in the Line Item. - * type: integer - * example: 1 - * fulfilled_quantity: - * description: The quantity of the Line Item that has been fulfilled. - * nullable: true - * type: integer - * example: 0 - * returned_quantity: - * description: The quantity of the Line Item that has been returned. - * nullable: true - * type: integer - * example: 0 - * shipped_quantity: - * description: The quantity of the Line Item that has been shipped. - * nullable: true - * type: integer - * example: 0 - * refundable: - * description: The amount that can be refunded from the given Line Item. Takes taxes and discounts into consideration. - * type: integer - * example: 0 - * subtotal: - * description: The subtotal of the line item - * type: integer - * example: 8000 - * tax_total: - * description: The total of tax of the line item - * type: integer - * example: 0 - * total: - * description: The total amount of the line item - * type: integer - * example: 8000 - * original_total: - * description: The original total amount of the line item - * type: integer - * example: 8000 - * original_tax_total: - * description: The original tax total amount of the line item - * 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 - * gift_card_total: - * description: The total of the gift card of the line item - * type: integer - * example: 0 - * includes_tax: - * description: "Indicates if the line item unit_price include tax" - * x-featureFlag: "tax_inclusive_pricing" - * type: boolean - * default: false - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/money-amount.ts b/packages/medusa/src/models/money-amount.ts deleted file mode 100644 index dc5240559e..0000000000 --- a/packages/medusa/src/models/money-amount.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { - AfterLoad, - BeforeInsert, - BeforeUpdate, - Column, - Entity, - Index, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, - Relation, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" -import { Currency } from "./currency" -import { PriceList } from "./price-list" -import { ProductVariant } from "./product-variant" -import { Region } from "./region" - -@Entity() -export class MoneyAmount extends SoftDeletableEntity { - @Index() - @Column() - currency_code: string - - @ManyToOne(() => Currency) - @JoinColumn({ name: "currency_code", referencedColumnName: "code" }) - currency?: Relation - - @Column({ type: "int" }) - amount: number - - @Column({ type: "int", nullable: true }) - min_quantity: number | null - - @Column({ type: "int", nullable: true }) - max_quantity: number | null - - @Column({ nullable: true }) - price_list_id: string | null - - @ManyToOne(() => PriceList, (priceList) => priceList.prices, { - cascade: true, - onDelete: "CASCADE", - }) - @JoinColumn({ name: "price_list_id" }) - price_list: Relation | null - - @ManyToMany(() => ProductVariant, { - onDelete: "CASCADE", - }) - @JoinTable({ - name: "product_variant_money_amount", - joinColumn: { - name: "money_amount_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "variant_id", - referencedColumnName: "id", - }, - }) - variants: Relation[] - - variant: Relation - - variant_id: string - - @Index("idx_money_amount_region_id") - @Column({ nullable: true }) - region_id: string | null - - @ManyToOne(() => Region) - @JoinColumn({ name: "region_id" }) - region?: Relation - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): undefined | void { - this.id = generateEntityId(this.id, "ma") - - if (this.variant || this.variant_id) { - this.variants = [ - { id: this.variant?.id || this.variant_id }, - ] as ProductVariant[] - } - } - - /** - * @apiIgnore - */ - @BeforeUpdate() - private beforeUpdate(): void { - if (this.variant || this.variant_id) { - this.variants = [ - { id: this.variant?.id || this.variant_id }, - ] as ProductVariant[] - } - } - - /** - * @apiIgnore - */ - @AfterLoad() - private afterLoad() { - this.variant = this.variants?.[0] - this.variant_id = this.variant?.id - } -} - -/** - * @schema MoneyAmount - * title: "Money Amount" - * description: "A Money Amount represent a price amount, for example, a product variant's price or a price in a price list. Each Money Amount either has a Currency or Region associated with it to indicate the pricing in a given Currency or, for fully region-based pricing, the given price in a specific Region. If region-based pricing is used, the amount will be in the currency defined for the Region." - * type: object - * required: - * - amount - * - created_at - * - currency_code - * - deleted_at - * - id - * - max_quantity - * - min_quantity - * - price_list_id - * - region_id - * - updated_at - * - variant_id - * properties: - * id: - * description: The money amount's ID - * type: string - * example: ma_01F0YESHRFQNH5S8Q0PK84YYZN - * currency_code: - * description: The 3 character currency code that the money amount may belong to. - * type: string - * example: usd - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * currency: - * description: The details of the currency that the money amount may belong to. - * x-expandable: "currency" - * nullable: true - * $ref: "#/components/schemas/Currency" - * amount: - * description: The amount in the smallest currecny unit (e.g. cents 100 cents to charge $1) that the Product Variant will cost. - * type: integer - * example: 100 - * min_quantity: - * description: The minimum quantity that the Money Amount applies to. If this value is not set, the Money Amount applies to all quantities. - * nullable: true - * type: integer - * example: 1 - * max_quantity: - * description: The maximum quantity that the Money Amount applies to. If this value is not set, the Money Amount applies to all quantities. - * nullable: true - * type: integer - * example: 1 - * price_list_id: - * description: The ID of the price list that the money amount may belong to. - * nullable: true - * type: string - * example: pl_01G8X3CKJXCG5VXVZ87H9KC09W - * price_list: - * description: The details of the price list that the money amount may belong to. - * x-expandable: "price_list" - * nullable: true - * $ref: "#/components/schemas/PriceList" - * variant_id: - * description: The ID of the Product Variant contained in the Line Item. - * nullable: true - * type: string - * example: variant_01G1G5V2MRX2V3PVSR2WXYPFB6 - * variant: - * description: The details of the product variant that the money amount may belong to. - * x-expandable: "variant" - * nullable: true - * $ref: "#/components/schemas/ProductVariant" - * region_id: - * description: The region's ID - * nullable: true - * type: string - * example: reg_01G1G5V26T9H8Y0M4JNE3YGA4G - * region: - * description: The details of the region that the money amount may belong to. - * x-expandable: "region" - * nullable: true - * $ref: "#/components/schemas/Region" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - */ diff --git a/packages/medusa/src/models/note.ts b/packages/medusa/src/models/note.ts deleted file mode 100644 index 42bd7ddcd8..0000000000 --- a/packages/medusa/src/models/note.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, -} from "typeorm" - -import { DbAwareColumn } from "../utils/db-aware-column" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { User } from "./user" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class Note extends SoftDeletableEntity { - @Column() - value: string - - @Index() - @Column() - resource_type: string - - @Index() - @Column() - resource_id: string - - @Column({ nullable: true }) - author_id: string - - @ManyToOne(() => User) - @JoinColumn({ name: "author_id" }) - author: User - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "note") - } -} - -/** - * @schema Note - * title: "Note" - * description: "A Note is an element that can be used in association with different resources to allow admin users to describe additional information. For example, they can be used to add additional information about orders." - * type: object - * required: - * - author_id - * - created_at - * - deleted_at - * - id - * - metadata - * - resource_id - * - resource_type - * - updated_at - * - value - * properties: - * id: - * description: The note's ID - * type: string - * example: note_01G8TM8ENBMC7R90XRR1G6H26Q - * resource_type: - * description: The type of resource that the Note refers to. - * type: string - * example: order - * resource_id: - * description: The ID of the resource that the Note refers to. - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * value: - * description: The contents of the note. - * type: string - * example: This order must be fulfilled on Monday - * author_id: - * description: The ID of the user that created the note. - * nullable: true - * type: string - * example: usr_01G1G5V26F5TB3GPAPNJ8X1S3V - * author: - * description: The details of the user that created the note. - * x-expandable: "author" - * nullable: true - * $ref: "#/components/schemas/User" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - */ diff --git a/packages/medusa/src/models/notification-provider.ts b/packages/medusa/src/models/notification-provider.ts deleted file mode 100644 index 3e06c20f17..0000000000 --- a/packages/medusa/src/models/notification-provider.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Column, Entity, PrimaryColumn } from "typeorm" - -@Entity() -export class NotificationProvider { - @PrimaryColumn() - id: string - - @Column({ default: true }) - is_installed: boolean -} - -/** - * @schema NotificationProvider - * title: "Notification Provider" - * description: "A notification provider represents a notification service installed in the Medusa backend, either through a plugin or backend customizations. - * It holds the notification service's installation status." - * type: object - * required: - * - id - * - is_installed - * properties: - * id: - * description: The ID of the notification provider as given by the notification service. - * type: string - * example: sendgrid - * is_installed: - * description: Whether the notification service is installed in the current version. If a notification service is no longer installed, the `is_installed` attribute is set to `false`. - * type: boolean - * default: true - */ diff --git a/packages/medusa/src/models/notification.ts b/packages/medusa/src/models/notification.ts deleted file mode 100644 index a46c72efdc..0000000000 --- a/packages/medusa/src/models/notification.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - OneToMany, -} from "typeorm" - -import { BaseEntity } from "../interfaces/models/base-entity" -import { Customer } from "./customer" -import { DbAwareColumn } from "../utils/db-aware-column" -import { NotificationProvider } from "./notification-provider" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class Notification extends BaseEntity { - @Column({ nullable: true }) - event_name: string - - @Index() - @Column() - resource_type: string - - @Index() - @Column() - resource_id: string - - @Index() - @Column({ nullable: true }) - customer_id: string | null - - @ManyToOne(() => Customer) - @JoinColumn({ name: "customer_id" }) - customer: Customer - - @Column() - to: string - - @DbAwareColumn({ type: "jsonb" }) - data: Record - - @Column({ nullable: true }) - parent_id: string - - @ManyToOne(() => Notification) - @JoinColumn({ name: "parent_id" }) - parent_notification: Notification - - @OneToMany(() => Notification, (noti) => noti.parent_notification) - resends: Notification[] - - @Column({ nullable: true }) - provider_id: string - - @ManyToOne(() => NotificationProvider) - @JoinColumn({ name: "provider_id" }) - provider: NotificationProvider - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "noti") - } -} - -/** - * @schema Notification - * title: "Notification" - * description: "A notification is an alert sent, typically to customers, using the installed Notification Provider as a reaction to internal events such as `order.placed`. Notifications can be resent." - * type: object - * required: - * - created_at - * - customer_id - * - data - * - event_name - * - id - * - parent_id - * - provider_id - * - resource_type - * - resource_id - * - to - * - updated_at - * properties: - * id: - * description: The notification's ID - * type: string - * example: noti_01G53V9Y6CKMCGBM1P0X7C28RX - * event_name: - * description: The name of the event that the notification was sent for. - * nullable: true - * type: string - * example: order.placed - * resource_type: - * description: The type of resource that the Notification refers to. - * type: string - * example: order - * resource_id: - * description: The ID of the resource that the Notification refers to. - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * customer_id: - * description: The ID of the customer that this notification was sent to. - * nullable: true - * type: string - * example: cus_01G2SG30J8C85S4A5CHM2S1NS2 - * customer: - * description: The details of the customer that this notification was sent to. - * x-expandable: "customer" - * nullable: true - * $ref: "#/components/schemas/Customer" - * to: - * description: The address that the Notification was sent to. This will usually be an email address, but can represent other addresses such as a chat bot user ID. - * type: string - * example: user@example.com - * data: - * description: The data that the Notification was sent with. This contains all the data necessary for the Notification Provider to initiate a resend. - * type: object - * example: {} - * parent_id: - * description: The notification's parent ID - * nullable: true - * type: string - * example: noti_01G53V9Y6CKMCGBM1P0X7C28RX - * parent_notification: - * description: The details of the parent notification. - * x-expandable: "parent_notification" - * nullable: true - * $ref: "#/components/schemas/Notification" - * resends: - * description: The details of all resends of the notification. - * type: array - * x-expandable: "resends" - * items: - * $ref: "#/components/schemas/Notification" - * provider_id: - * description: The ID of the notification provider used to send the notification. - * nullable: true - * type: string - * example: sengrid - * provider: - * description: The notification provider used to send the notification. - * x-expandable: "provider" - * nullable: true - * $ref: "#/components/schemas/NotificationProvider" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - */ diff --git a/packages/medusa/src/models/oauth.ts b/packages/medusa/src/models/oauth.ts deleted file mode 100644 index 2ac0c610ed..0000000000 --- a/packages/medusa/src/models/oauth.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { BeforeInsert, Column, Entity, Index, PrimaryColumn } from "typeorm" - -import { DbAwareColumn } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class Oauth { - @PrimaryColumn() - id: string - - @Column() - display_name: string - - @Index({ unique: true }) - @Column() - application_name: string - - @Column({ nullable: true }) - install_url: string - - @Column({ nullable: true }) - uninstall_url: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - data: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "oauth") - } -} - -/** - * @schema OAuth - * title: "OAuth" - * description: "An Oauth app is typically created by a plugin to handle authentication to third-party services." - * type: object - * required: - * - application_name - * - data - * - display_name - * - id - * - install_url - * - uninstall_url - * properties: - * id: - * description: The app's ID - * type: string - * example: example_app - * display_name: - * description: The app's display name - * type: string - * example: Example app - * application_name: - * description: The app's name - * type: string - * example: example - * install_url: - * description: The URL to install the app - * nullable: true - * type: string - * format: uri - * uninstall_url: - * description: The URL to uninstall the app - * nullable: true - * type: string - * format: uri - * data: - * description: Any data necessary to the app. - * nullable: true - * type: object - * example: {} - */ diff --git a/packages/medusa/src/models/order-edit.ts b/packages/medusa/src/models/order-edit.ts deleted file mode 100644 index e14f0b8e48..0000000000 --- a/packages/medusa/src/models/order-edit.ts +++ /dev/null @@ -1,306 +0,0 @@ -import { - AfterLoad, - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - OneToMany, - OneToOne, - Relation, -} from "typeorm" - -import { BaseEntity } from "../interfaces" -import { generateEntityId } from "../utils" -import { resolveDbType } from "../utils/db-aware-column" - -import { LineItem, Order, OrderItemChange, PaymentCollection } from "." - -/** - * @enum - * - * The order edit's status. - */ -export enum OrderEditStatus { - /** - * The order edit is confirmed. - */ - CONFIRMED = "confirmed", - /** - * The order edit is declined. - */ - DECLINED = "declined", - /** - * The order edit is requested. - */ - REQUESTED = "requested", - /** - * The order edit is created. - */ - CREATED = "created", - /** - * The order edit is canceled. - */ - CANCELED = "canceled", -} - -@Entity() -export class OrderEdit extends BaseEntity { - @Index() - @Column() - order_id: string - - @ManyToOne(() => Order, (o) => o.edits) - @JoinColumn({ name: "order_id" }) - order: Relation - - @OneToMany(() => OrderItemChange, (oic) => oic.order_edit, { - cascade: true, - }) - changes: Relation[] - - @Column({ nullable: true }) - internal_note?: string - - @Column() - created_by: string // customer, user, third party, etc. - - @Column({ nullable: true }) - requested_by?: string // customer or user ID - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - requested_at?: Date - - @Column({ nullable: true }) - confirmed_by?: string // customer or user ID - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - confirmed_at?: Date - - @Column({ nullable: true }) - declined_by?: string // customer or user ID - - @Column({ nullable: true }) - declined_reason?: string - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - declined_at?: Date - - @Column({ nullable: true }) - canceled_by?: string - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - canceled_at?: Date - - @OneToMany(() => LineItem, (lineItem) => lineItem.order_edit) - items: Relation[] - - @Index() - @Column({ nullable: true }) - payment_collection_id: string - - @OneToOne(() => PaymentCollection) - @JoinColumn({ name: "payment_collection_id" }) - payment_collection: PaymentCollection - - // Computed - shipping_total: number - discount_total: number - tax_total: number | null - total: number - subtotal: number - gift_card_total: number - gift_card_tax_total: number - - difference_due: number - - status: OrderEditStatus - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "oe") - } - - /** - * @apiIgnore - */ - @AfterLoad() - loadStatus(): void { - if (this.requested_at) { - this.status = OrderEditStatus.REQUESTED - } - if (this.declined_at) { - this.status = OrderEditStatus.DECLINED - } - if (this.confirmed_at) { - this.status = OrderEditStatus.CONFIRMED - } - if (this.canceled_at) { - this.status = OrderEditStatus.CANCELED - } - - this.status = this.status ?? OrderEditStatus.CREATED - } -} - -/** - * @schema OrderEdit - * title: "Order Edit" - * description: "Order edit allows modifying items in an order, such as adding, updating, or deleting items from the original order. Once the order edit is confirmed, the changes are reflected on the original order." - * type: object - * required: - * - canceled_at - * - canceled_by - * - confirmed_by - * - confirmed_at - * - created_at - * - created_by - * - declined_at - * - declined_by - * - declined_reason - * - id - * - internal_note - * - order_id - * - payment_collection_id - * - requested_at - * - requested_by - * - status - * - updated_at - * properties: - * id: - * description: The order edit's ID - * type: string - * example: oe_01G8TJSYT9M6AVS5N4EMNFS1EK - * order_id: - * description: The ID of the order that is edited - * type: string - * example: order_01G2SG30J8C85S4A5CHM2S1NS2 - * order: - * description: The details of the order that this order edit was created for. - * x-expandable: "order" - * nullable: true - * $ref: "#/components/schemas/Order" - * changes: - * description: The details of all the changes on the original order's line items. - * x-expandable: "changes" - * type: array - * items: - * $ref: "#/components/schemas/OrderItemChange" - * internal_note: - * description: An optional note with additional details about the order edit. - * nullable: true - * type: string - * example: Included two more items B to the order. - * created_by: - * description: The unique identifier of the user or customer who created the order edit. - * type: string - * requested_by: - * description: The unique identifier of the user or customer who requested the order edit. - * nullable: true - * type: string - * requested_at: - * description: The date with timezone at which the edit was requested. - * nullable: true - * type: string - * format: date-time - * confirmed_by: - * description: The unique identifier of the user or customer who confirmed the order edit. - * nullable: true - * type: string - * confirmed_at: - * description: The date with timezone at which the edit was confirmed. - * nullable: true - * type: string - * format: date-time - * declined_by: - * description: The unique identifier of the user or customer who declined the order edit. - * nullable: true - * type: string - * declined_at: - * description: The date with timezone at which the edit was declined. - * nullable: true - * type: string - * format: date-time - * declined_reason: - * description: An optional note why the order edit is declined. - * nullable: true - * type: string - * canceled_by: - * description: The unique identifier of the user or customer who cancelled the order edit. - * nullable: true - * type: string - * canceled_at: - * description: The date with timezone at which the edit was cancelled. - * nullable: true - * type: string - * format: date-time - * subtotal: - * description: The total of subtotal - * type: integer - * example: 8000 - * discount_total: - * description: The total of discount - * type: integer - * example: 800 - * shipping_total: - * description: The total of the shipping amount - * type: integer - * example: 800 - * gift_card_total: - * description: The total of the gift card amount - * type: integer - * example: 800 - * gift_card_tax_total: - * description: The total of the gift card tax amount - * type: integer - * example: 800 - * tax_total: - * description: The total of tax - * type: integer - * example: 0 - * total: - * description: The total amount of the edited order. - * type: integer - * example: 8200 - * difference_due: - * description: The difference between the total amount of the order and total amount of edited order. - * type: integer - * example: 8200 - * status: - * description: The status of the order edit. - * type: string - * enum: - * - confirmed - * - declined - * - requested - * - created - * - canceled - * items: - * description: The details of the cloned items from the original order with the new changes. Once the order edit is confirmed, these line items are associated with the original order. - * type: array - * x-expandable: "items" - * items: - * $ref: "#/components/schemas/LineItem" - * payment_collection_id: - * description: The ID of the payment collection - * nullable: true - * type: string - * example: paycol_01G8TJSYT9M6AVS5N4EMNFS1EK - * payment_collection: - * description: The details of the payment collection used to authorize additional payment if necessary. - * x-expandable: "payment_collection" - * nullable: true - * $ref: "#/components/schemas/PaymentCollection" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - */ diff --git a/packages/medusa/src/models/order-item-change.ts b/packages/medusa/src/models/order-item-change.ts deleted file mode 100644 index 1dcaabf775..0000000000 --- a/packages/medusa/src/models/order-item-change.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - JoinColumn, - ManyToOne, - OneToOne, - Unique, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces" -import { generateEntityId } from "../utils" -import { DbAwareColumn } from "../utils/db-aware-column" -import { LineItem } from "./line-item" -import { OrderEdit } from "./order-edit" - -/** - * @enum - * - * The type of the order edit item change. - */ -export enum OrderEditItemChangeType { - /** - * A new item to be added to the original order. - */ - ITEM_ADD = "item_add", - /** - * An existing item to be removed from the original order. - */ - ITEM_REMOVE = "item_remove", - /** - * An existing item to be updated in the original order. - */ - ITEM_UPDATE = "item_update", -} - -@Unique(["order_edit_id", "original_line_item_id"]) -@Unique(["order_edit_id", "line_item_id"]) -@Entity() -export class OrderItemChange extends SoftDeletableEntity { - @DbAwareColumn({ - type: "enum", - enum: OrderEditItemChangeType, - }) - type: OrderEditItemChangeType - - @Column() - order_edit_id: string - - @ManyToOne(() => OrderEdit, (oe) => oe.changes) - @JoinColumn({ name: "order_edit_id" }) - order_edit: OrderEdit - - @Column({ nullable: true }) - original_line_item_id?: string - - @ManyToOne(() => LineItem, { nullable: true }) - @JoinColumn({ name: "original_line_item_id" }) - original_line_item?: LineItem - - @Column({ nullable: true }) - line_item_id?: string - - @OneToOne(() => LineItem, { nullable: true }) - @JoinColumn({ name: "line_item_id" }) - line_item?: LineItem - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "oic") - } -} - -/** - * @schema OrderItemChange - * title: "Order Item Change" - * description: "An order item change is a change made within an order edit to an order's items. These changes are not reflected on the original order until the order edit is confirmed." - * type: object - * required: - * - created_at - * - deleted_at - * - id - * - line_item_id - * - order_edit_id - * - original_line_item_id - * - type - * - updated_at - * properties: - * id: - * description: The order item change's ID - * type: string - * example: oic_01G8TJSYT9M6AVS5N4EMNFS1EK - * type: - * description: The order item change's status - * type: string - * enum: - * - item_add - * - item_remove - * - item_update - * order_edit_id: - * description: The ID of the order edit - * type: string - * example: oe_01G2SG30J8C85S4A5CHM2S1NS2 - * order_edit: - * description: The details of the order edit the item change is associated with. - * x-expandable: "order_edit" - * nullable: true - * $ref: "#/components/schemas/OrderEdit" - * original_line_item_id: - * description: The ID of the original line item in the order - * nullable: true - * type: string - * example: item_01G8ZC9GWT6B2GP5FSXRXNFNGN - * original_line_item: - * description: The details of the original line item this item change references. This is used if the item change updates or deletes the original item. - * x-expandable: "original_line_item" - * nullable: true - * $ref: "#/components/schemas/LineItem" - * line_item_id: - * description: The ID of the cloned line item. - * nullable: true - * type: string - * example: item_01G8ZC9GWT6B2GP5FSXRXNFNGN - * line_item: - * description: The details of the resulting line item after the item change. This line item is then used in the original order once the order edit is confirmed. - * x-expandable: "line_item" - * nullable: true - * $ref: "#/components/schemas/LineItem" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - */ diff --git a/packages/medusa/src/models/order-sales-channel.ts b/packages/medusa/src/models/order-sales-channel.ts deleted file mode 100644 index 497f464169..0000000000 --- a/packages/medusa/src/models/order-sales-channel.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { BeforeInsert, Column, Index, PrimaryColumn } from "typeorm" -import { MedusaV2Flag, SalesChannelFeatureFlag } from "@medusajs/utils" - -import { generateEntityId } from "../utils" -import { SoftDeletableEntity } from "../interfaces" -import { FeatureFlagEntity } from "../utils/feature-flag-decorators" - -@FeatureFlagEntity([MedusaV2Flag.key, SalesChannelFeatureFlag.key]) -export class OrderSalesChannel extends SoftDeletableEntity { - @Column() - id: string - - @Index("order_sales_channel_order_id_unique", { - unique: true, - }) - @PrimaryColumn() - order_id: string - - @PrimaryColumn() - sales_channel_id: string - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "ordersc") - } -} diff --git a/packages/medusa/src/models/order.ts b/packages/medusa/src/models/order.ts deleted file mode 100644 index b60d12fe61..0000000000 --- a/packages/medusa/src/models/order.ts +++ /dev/null @@ -1,754 +0,0 @@ -import { - AfterLoad, - BeforeInsert, - BeforeUpdate, - Column, - Entity, - Generated, - Index, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, - OneToMany, - OneToOne, - Relation, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" -import { - FeatureFlagColumn, - FeatureFlagDecorators, -} from "../utils/feature-flag-decorators" - -import { MedusaV2Flag } from "@medusajs/utils" -import { BaseEntity } from "../interfaces/models/base-entity" -import { generateEntityId } from "../utils/generate-entity-id" -import { manualAutoIncrement } from "../utils/manual-auto-increment" -import { Address } from "./address" -import { Cart } from "./cart" -import { ClaimOrder } from "./claim-order" -import { Currency } from "./currency" -import { Customer } from "./customer" -import { Discount } from "./discount" -import { DraftOrder } from "./draft-order" -import { Fulfillment } from "./fulfillment" -import { GiftCard } from "./gift-card" -import { GiftCardTransaction } from "./gift-card-transaction" -import { LineItem } from "./line-item" -import { OrderEdit } from "./order-edit" -import { Payment } from "./payment" -import { Refund } from "./refund" -import { Region } from "./region" -import { Return } from "./return" -import { SalesChannel } from "./sales-channel" -import { ShippingMethod } from "./shipping-method" -import { Swap } from "./swap" - -/** - * @enum - * - * The order's status. - */ -export enum OrderStatus { - /** - * The order is pending. - */ - PENDING = "pending", - /** - * The order is completed, meaning that - * the items have been fulfilled and the payment - * has been captured. - */ - COMPLETED = "completed", - /** - * The order is archived. - */ - ARCHIVED = "archived", - /** - * The order is canceled. - */ - CANCELED = "canceled", - /** - * The order requires action. - */ - REQUIRES_ACTION = "requires_action", -} - -/** - * @enum - * - * The order's fulfillment status. - */ -export enum FulfillmentStatus { - /** - * The order's items are not fulfilled. - */ - NOT_FULFILLED = "not_fulfilled", - /** - * Some of the order's items, but not all, are fulfilled. - */ - PARTIALLY_FULFILLED = "partially_fulfilled", - /** - * The order's items are fulfilled. - */ - FULFILLED = "fulfilled", - /** - * Some of the order's items, but not all, are shipped. - */ - PARTIALLY_SHIPPED = "partially_shipped", - /** - * The order's items are shipped. - */ - SHIPPED = "shipped", - /** - * Some of the order's items, but not all, are returned. - */ - PARTIALLY_RETURNED = "partially_returned", - /** - * The order's items are returned. - */ - RETURNED = "returned", - /** - * The order's fulfillments are canceled. - */ - CANCELED = "canceled", - /** - * The order's fulfillment requires action. - */ - REQUIRES_ACTION = "requires_action", -} - -/** - * @enum - * - * The order's payment status. - */ -export enum PaymentStatus { - /** - * The order's payment is not paid. - */ - NOT_PAID = "not_paid", - /** - * The order's payment is awaiting capturing. - */ - AWAITING = "awaiting", - /** - * The order's payment is captured. - */ - CAPTURED = "captured", - /** - * Some of the order's payment amount is refunded. - */ - PARTIALLY_REFUNDED = "partially_refunded", - /** - * The order's payment amount is refunded. - */ - REFUNDED = "refunded", - /** - * The order's payment is canceled. - */ - CANCELED = "canceled", - /** - * The order's payment requires action. - */ - REQUIRES_ACTION = "requires_action", -} - -@Entity() -export class Order extends BaseEntity { - /** - * @apiIgnore - */ - readonly object = "order" - - @DbAwareColumn({ type: "enum", enum: OrderStatus, default: "pending" }) - status: OrderStatus - - @DbAwareColumn({ - type: "enum", - enum: FulfillmentStatus, - default: "not_fulfilled", - }) - fulfillment_status: FulfillmentStatus - - @DbAwareColumn({ type: "enum", enum: PaymentStatus, default: "not_paid" }) - payment_status: PaymentStatus - - @Index() - @Column() - @Generated("increment") - display_id: number - - @Index() - @Column({ nullable: true }) - cart_id: string - - @OneToOne(() => Cart) - @JoinColumn({ name: "cart_id" }) - cart: Relation - - @Index() - @Column() - customer_id: string - - @ManyToOne(() => Customer, { cascade: ["insert"] }) - @JoinColumn({ name: "customer_id" }) - customer: Relation - - @Column() - email: string - - @Index() - @Column({ nullable: true }) - billing_address_id: string - - @ManyToOne(() => Address, { cascade: ["insert"] }) - @JoinColumn({ name: "billing_address_id" }) - billing_address: Relation
- - @Index() - @Column({ nullable: true }) - shipping_address_id: string - - @ManyToOne(() => Address, { cascade: ["insert"] }) - @JoinColumn({ name: "shipping_address_id" }) - shipping_address: Relation
- - @Index() - @Column() - region_id: string - - @ManyToOne(() => Region) - @JoinColumn({ name: "region_id" }) - region: Relation - - @Index() - @Column() - currency_code: string - - @ManyToOne(() => Currency) - @JoinColumn({ name: "currency_code", referencedColumnName: "code" }) - currency: Relation - - @Column({ type: "real", nullable: true }) - tax_rate: number | null - - @ManyToMany(() => Discount, { cascade: ["insert"] }) - @JoinTable({ - name: "order_discounts", - joinColumn: { - name: "order_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "discount_id", - referencedColumnName: "id", - }, - }) - discounts: Relation[] - - @ManyToMany(() => GiftCard, { cascade: ["insert"] }) - @JoinTable({ - name: "order_gift_cards", - joinColumn: { - name: "order_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "gift_card_id", - referencedColumnName: "id", - }, - }) - gift_cards: Relation[] - - @OneToMany(() => ShippingMethod, (method) => method.order, { - cascade: ["insert"], - }) - shipping_methods: Relation[] - - @OneToMany(() => Payment, (payment) => payment.order, { cascade: ["insert"] }) - payments: Relation[] - - @OneToMany(() => Fulfillment, (fulfillment) => fulfillment.order, { - cascade: ["insert"], - }) - fulfillments: Relation[] - - @OneToMany(() => Return, (ret) => ret.order, { cascade: ["insert"] }) - returns: Relation[] - - @OneToMany(() => ClaimOrder, (co) => co.order, { cascade: ["insert"] }) - claims: Relation[] - - @OneToMany(() => Refund, (ref) => ref.order, { cascade: ["insert"] }) - refunds: Relation[] - - @OneToMany(() => Swap, (swap) => swap.order, { cascade: ["insert"] }) - swaps: Relation[] - - @Column({ nullable: true }) - draft_order_id: string - - @OneToOne(() => DraftOrder) - @JoinColumn({ name: "draft_order_id" }) - draft_order: Relation - - @OneToMany(() => OrderEdit, (oe) => oe.order) - edits: Relation[] - - @OneToMany(() => LineItem, (lineItem) => lineItem.order, { - cascade: ["insert"], - }) - items: Relation[] - - @OneToMany(() => GiftCardTransaction, (gc) => gc.order) - gift_card_transactions: Relation[] - - @Column({ nullable: true, type: resolveDbType("timestamptz") }) - canceled_at: Date - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - @Column({ type: "boolean", nullable: true }) - no_notification: boolean - - @Column({ nullable: true }) - idempotency_key: string - - @Column({ type: "varchar", nullable: true }) - external_id: string | null - - @FeatureFlagColumn("sales_channels", { type: "varchar", nullable: true }) - sales_channel_id: string | null - - @FeatureFlagDecorators("sales_channels", [ - ManyToOne(() => SalesChannel), - JoinColumn({ name: "sales_channel_id" }), - ]) - sales_channel: Relation - - @FeatureFlagDecorators( - [MedusaV2Flag.key, "sales_channels"], - [ - ManyToMany(() => SalesChannel, { cascade: ["remove", "soft-remove"] }), - JoinTable({ - name: "order_sales_channel", - joinColumn: { - name: "cart_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "sales_channel_id", - referencedColumnName: "id", - }, - }), - ] - ) - sales_channels?: Relation[] - - // Total fields - shipping_total: number - shipping_tax_total: number | null - discount_total: number - raw_discount_total: number - item_tax_total: number | null - tax_total: number | null - refunded_total: number - total: number - subtotal: number - paid_total: number - refundable_amount: number - gift_card_total: number - gift_card_tax_total: number - - returnable_items?: Relation[] - - /** - * @apiIgnore - */ - @BeforeInsert() - private async beforeInsert(): Promise { - this.id = generateEntityId(this.id, "order") - - if (this.sales_channel_id || this.sales_channel) { - this.sales_channels = [ - { id: this.sales_channel_id || this.sales_channel?.id }, - ] as SalesChannel[] - } - - if (process.env.NODE_ENV === "development" && !this.display_id) { - const disId = await manualAutoIncrement("order") - - if (disId) { - this.display_id = disId - } - } - } - - /** - * @apiIgnore - */ - @BeforeUpdate() - private beforeUpdate(): void { - if (this.sales_channel_id || this.sales_channel) { - this.sales_channels = [ - { id: this.sales_channel_id || this.sales_channel?.id }, - ] as SalesChannel[] - } - } - - /** - * @apiIgnore - */ - @AfterLoad() - private afterLoad(): void { - if (this.sales_channels) { - this.sales_channel = this.sales_channels?.[0] - this.sales_channel_id = this.sales_channel?.id - delete this.sales_channels - } - } -} - -/** - * @schema Order - * title: "Order" - * description: "An order is a purchase made by a customer. It holds details about payment and fulfillment of the order. An order may also be created from a draft order, which is created by an admin user." - * type: object - * required: - * - billing_address_id - * - canceled_at - * - cart_id - * - created_at - * - currency_code - * - customer_id - * - draft_order_id - * - display_id - * - email - * - external_id - * - fulfillment_status - * - id - * - idempotency_key - * - metadata - * - no_notification - * - object - * - payment_status - * - region_id - * - shipping_address_id - * - status - * - tax_rate - * - updated_at - * properties: - * id: - * description: The order's ID - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * status: - * description: The order's status - * type: string - * enum: - * - pending - * - completed - * - archived - * - canceled - * - requires_action - * default: pending - * fulfillment_status: - * description: The order's fulfillment status - * type: string - * enum: - * - not_fulfilled - * - partially_fulfilled - * - fulfilled - * - partially_shipped - * - shipped - * - partially_returned - * - returned - * - canceled - * - requires_action - * default: not_fulfilled - * payment_status: - * description: The order's payment status - * type: string - * enum: - * - not_paid - * - awaiting - * - captured - * - partially_refunded - * - refunded - * - canceled - * - requires_action - * default: not_paid - * display_id: - * description: The order's display ID - * type: integer - * example: 2 - * cart_id: - * description: The ID of the cart associated with the order - * nullable: true - * type: string - * example: cart_01G8ZH853Y6TFXWPG5EYE81X63 - * cart: - * description: The details of the cart associated with the order. - * x-expandable: "cart" - * nullable: true - * $ref: "#/components/schemas/Cart" - * customer_id: - * description: The ID of the customer associated with the order - * type: string - * example: cus_01G2SG30J8C85S4A5CHM2S1NS2 - * customer: - * description: The details of the customer associated with the order. - * x-expandable: "customer" - * nullable: true - * $ref: "#/components/schemas/Customer" - * email: - * description: The email associated with the order - * type: string - * format: email - * billing_address_id: - * description: The ID of the billing address associated with the order - * nullable: true - * type: string - * example: addr_01G8ZH853YPY9B94857DY91YGW - * billing_address: - * description: The details of the billing address associated with the order. - * x-expandable: "billing_address" - * nullable: true - * $ref: "#/components/schemas/Address" - * shipping_address_id: - * description: The ID of the shipping address associated with the order - * nullable: true - * type: string - * example: addr_01G8ZH853YPY9B94857DY91YGW - * shipping_address: - * description: The details of the shipping address associated with the order. - * x-expandable: "shipping_address" - * nullable: true - * $ref: "#/components/schemas/Address" - * region_id: - * description: The ID of the region this order was created in. - * type: string - * example: reg_01G1G5V26T9H8Y0M4JNE3YGA4G - * region: - * description: The details of the region this order was created in. - * x-expandable: "region" - * nullable: true - * $ref: "#/components/schemas/Region" - * currency_code: - * description: The 3 character currency code that is used in the order - * type: string - * example: usd - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * currency: - * description: The details of the currency used in the order. - * x-expandable: "currency" - * nullable: true - * $ref: "#/components/schemas/Currency" - * tax_rate: - * description: The order's tax rate - * nullable: true - * type: number - * example: 0 - * discounts: - * description: The details of the discounts applied on the order. - * type: array - * x-expandable: "discounts" - * items: - * $ref: "#/components/schemas/Discount" - * gift_cards: - * description: The details of the gift card used in the order. - * type: array - * x-expandable: "gift_cards" - * items: - * $ref: "#/components/schemas/GiftCard" - * shipping_methods: - * description: The details of the shipping methods used in the order. - * type: array - * x-expandable: "shipping_methods" - * items: - * $ref: "#/components/schemas/ShippingMethod" - * payments: - * description: The details of the payments used in the order. - * type: array - * x-expandable: "payments" - * items: - * $ref: "#/components/schemas/Payment" - * fulfillments: - * description: The details of the fulfillments created for the order. - * type: array - * x-expandable: "fulfillments" - * items: - * $ref: "#/components/schemas/Fulfillment" - * returns: - * description: The details of the returns created for the order. - * type: array - * x-expandable: "returns" - * items: - * $ref: "#/components/schemas/Return" - * claims: - * description: The details of the claims created for the order. - * type: array - * x-expandable: "claims" - * items: - * $ref: "#/components/schemas/ClaimOrder" - * refunds: - * description: The details of the refunds created for the order. - * type: array - * x-expandable: "refunds" - * items: - * $ref: "#/components/schemas/Refund" - * swaps: - * description: The details of the swaps created for the order. - * type: array - * x-expandable: "swaps" - * items: - * $ref: "#/components/schemas/Swap" - * draft_order_id: - * description: The ID of the draft order this order was created from. - * nullable: true - * type: string - * example: null - * draft_order: - * description: The details of the draft order this order was created from. - * x-expandable: "draft_order" - * nullable: true - * $ref: "#/components/schemas/DraftOrder" - * items: - * description: The details of the line items that belong to the order. - * x-expandable: "items" - * type: array - * items: - * $ref: "#/components/schemas/LineItem" - * edits: - * description: The details of the order edits done on the order. - * type: array - * x-expandable: "edits" - * items: - * $ref: "#/components/schemas/OrderEdit" - * gift_card_transactions: - * description: The gift card transactions made in the order. - * type: array - * x-expandable: "gift_card_transactions" - * items: - * $ref: "#/components/schemas/GiftCardTransaction" - * canceled_at: - * description: The date the order was canceled on. - * nullable: true - * type: string - * format: date-time - * no_notification: - * description: Flag for describing whether or not notifications related to this should be send. - * nullable: true - * type: boolean - * example: false - * idempotency_key: - * description: Randomly generated key used to continue the processing of the order in case of failure. - * nullable: true - * type: string - * externalDocs: - * url: https://docs.medusajs.com/development/idempotency-key/overview.md - * description: Learn more how to use the idempotency key. - * external_id: - * description: The ID of an external order. - * nullable: true - * type: string - * example: null - * sales_channel_id: - * description: The ID of the sales channel this order belongs to. - * nullable: true - * type: string - * example: null - * sales_channel: - * description: The details of the sales channel this order belongs to. - * x-expandable: "sales_channel" - * nullable: true - * $ref: "#/components/schemas/SalesChannel" - * shipping_total: - * type: integer - * description: The total of shipping - * example: 1000 - * nullable: true - * shipping_tax_total: - * type: integer - * description: The tax total applied on shipping - * example: 1000 - * 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 - * example: 0 - * item_tax_total: - * description: The tax total applied on items - * type: integer - * example: 0 - * nullable: true - * refunded_total: - * description: The total amount refunded if the order is returned. - * type: integer - * example: 0 - * total: - * description: The total amount of the order - * type: integer - * example: 8200 - * subtotal: - * description: The subtotal of the order - * type: integer - * example: 8000 - * paid_total: - * description: The total amount paid - * type: integer - * example: 8000 - * refundable_amount: - * description: The amount that can be refunded - * type: integer - * example: 8200 - * gift_card_total: - * description: The total of gift cards - * type: integer - * example: 0 - * gift_card_tax_total: - * description: The total of gift cards with taxes - * type: integer - * example: 0 - * returnable_items: - * description: The details of the line items that are returnable as part of the order, swaps, or claims - * type: array - * x-expandable: "returnable_items" - * items: - * $ref: "#/components/schemas/LineItem" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * sales_channels: - * description: The associated sales channels. - * type: array - * nullable: true - * x-expandable: "sales_channels" - * x-featureFlag: "medusa_v2" - * items: - * $ref: "#/components/schemas/SalesChannel" - */ diff --git a/packages/medusa/src/models/payment-collection.ts b/packages/medusa/src/models/payment-collection.ts deleted file mode 100644 index 02d7065266..0000000000 --- a/packages/medusa/src/models/payment-collection.ts +++ /dev/null @@ -1,239 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, -} from "typeorm" - -import { Currency, Payment, PaymentSession, Region } from "." -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils" -import { DbAwareColumn } from "../utils/db-aware-column" - -/** - * @enum - * - * The payment collection's status. - */ -export enum PaymentCollectionStatus { - /** - * The payment collection isn't paid. - */ - NOT_PAID = "not_paid", - /** - * The payment collection is awaiting payment. - */ - AWAITING = "awaiting", - /** - * The payment colleciton is authorized. - */ - AUTHORIZED = "authorized", - /** - * Some of the payments in the payment collection are authorized. - */ - PARTIALLY_AUTHORIZED = "partially_authorized", - /** - * The payment collection is canceled. - */ - CANCELED = "canceled", -} - -/** - * @enum - * - * The payment collection's type. - */ -export enum PaymentCollectionType { - /** - * The payment collection is used for an order edit. - */ - ORDER_EDIT = "order_edit", -} - -@Entity() -export class PaymentCollection extends SoftDeletableEntity { - @DbAwareColumn({ type: "enum", enum: PaymentCollectionType }) - type: PaymentCollectionType - - @DbAwareColumn({ type: "enum", enum: PaymentCollectionStatus }) - status: PaymentCollectionStatus - - @Column({ type: "varchar", nullable: true }) - description: string | null - - @Column({ type: "int" }) - amount: number - - @Column({ type: "int", nullable: true }) - authorized_amount: number | null - - @Index() - @Column() - region_id: string - - @ManyToOne(() => Region) - @JoinColumn({ name: "region_id" }) - region: Region - - @Index() - @Column() - currency_code: string - - @ManyToOne(() => Currency) - @JoinColumn({ name: "currency_code", referencedColumnName: "code" }) - currency: Currency - - @ManyToMany(() => PaymentSession) - @JoinTable({ - name: "payment_collection_sessions", - joinColumn: { - name: "payment_collection_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "payment_session_id", - referencedColumnName: "id", - }, - }) - payment_sessions: PaymentSession[] - - @ManyToMany(() => Payment) - @JoinTable({ - name: "payment_collection_payments", - joinColumn: { - name: "payment_collection_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "payment_id", - referencedColumnName: "id", - }, - }) - payments: Payment[] - - @DbAwareColumn({ type: "jsonb" }) - metadata: Record - - @Column() - created_by: string - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "paycol") - } -} - -/** - * @schema PaymentCollection - * title: "Payment Collection" - * description: "A payment collection allows grouping and managing a list of payments at one. This can be helpful when making additional payment for order edits or integrating installment payments." - * type: object - * required: - * - amount - * - authorized_amount - * - created_at - * - created_by - * - currency_code - * - deleted_at - * - description - * - id - * - metadata - * - region_id - * - status - * - type - * - updated_at - * properties: - * id: - * description: The payment collection's ID - * type: string - * example: paycol_01G8TJSYT9M6AVS5N4EMNFS1EK - * type: - * description: The type of the payment collection - * type: string - * enum: - * - order_edit - * status: - * description: The type of the payment collection - * type: string - * enum: - * - not_paid - * - awaiting - * - authorized - * - partially_authorized - * - canceled - * description: - * description: Description of the payment collection - * nullable: true - * type: string - * amount: - * description: Amount of the payment collection. - * type: integer - * authorized_amount: - * description: Authorized amount of the payment collection. - * nullable: true - * type: integer - * region_id: - * description: The ID of the region this payment collection is associated with. - * type: string - * example: reg_01G1G5V26T9H8Y0M4JNE3YGA4G - * region: - * description: The details of the region this payment collection is associated with. - * x-expandable: "region" - * nullable: true - * $ref: "#/components/schemas/Region" - * currency_code: - * description: The three character ISO code for the currency this payment collection is associated with. - * type: string - * example: usd - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * currency: - * description: The details of the currency this payment collection is associated with. - * x-expandable: "currency" - * nullable: true - * $ref: "#/components/schemas/Currency" - * payment_sessions: - * description: The details of the payment sessions created as part of the payment collection. - * type: array - * x-expandable: "payment_sessions" - * items: - * $ref: "#/components/schemas/PaymentSession" - * payments: - * description: The details of the payments created as part of the payment collection. - * type: array - * x-expandable: "payments" - * items: - * $ref: "#/components/schemas/Payment" - * created_by: - * description: The ID of the user that created the payment collection. - * type: string - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/payment-provider.ts b/packages/medusa/src/models/payment-provider.ts deleted file mode 100644 index 6736c88440..0000000000 --- a/packages/medusa/src/models/payment-provider.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Column, Entity, PrimaryColumn } from "typeorm" - -@Entity() -export class PaymentProvider { - @PrimaryColumn() - id: string - - @Column({ default: true }) - is_installed: boolean -} - -/** - * @schema PaymentProvider - * title: "Payment Provider" - * description: "A payment provider represents a payment service installed in the Medusa backend, either through a plugin or backend customizations. - * It holds the payment service's installation status." - * type: object - * required: - * - id - * - is_installed - * properties: - * id: - * description: The ID of the payment provider as given by the payment service. - * type: string - * example: manual - * is_installed: - * description: Whether the payment service is installed in the current version. If a payment service is no longer installed, the `is_installed` attribute is set to `false`. - * type: boolean - * default: true - */ diff --git a/packages/medusa/src/models/payment-session.ts b/packages/medusa/src/models/payment-session.ts deleted file mode 100644 index daff4df754..0000000000 --- a/packages/medusa/src/models/payment-session.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - Relation, - Unique, -} from "typeorm" - -import { BaseEntity } from "../interfaces" -import { generateEntityId } from "../utils" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" -import { Cart } from "./cart" - -/** - * @enum - * - * The status of a payment session. - */ -export enum PaymentSessionStatus { - /** - * The payment is authorized. - */ - AUTHORIZED = "authorized", - /** - * The payment is pending. - */ - PENDING = "pending", - /** - * The payment requires an action. - */ - REQUIRES_MORE = "requires_more", - /** - * An error occurred while processing the payment. - */ - ERROR = "error", - /** - * The payment is canceled. - */ - CANCELED = "canceled", -} - -@Unique("OneSelected", ["cart_id", "is_selected"]) -@Index("UniqPaymentSessionCartIdProviderId", ["cart_id", "provider_id"], { - unique: true, - where: "cart_id IS NOT NULL", -}) -@Entity() -export class PaymentSession extends BaseEntity { - @Index() - @Column({ nullable: true }) - cart_id: string | null - - @ManyToOne(() => Cart, (cart) => cart.payment_sessions) - @JoinColumn({ name: "cart_id" }) - cart: Relation - - @Index() - @Column() - provider_id: string - - @Column({ type: "boolean", nullable: true }) - is_selected: boolean | null - - @Column({ type: "boolean", default: false }) - is_initiated: boolean - - @DbAwareColumn({ type: "enum", enum: PaymentSessionStatus }) - status: string - - @DbAwareColumn({ type: "jsonb" }) - data: Record - - @Column({ nullable: true }) - idempotency_key: string - - @Column({ type: "integer", nullable: true }) - amount: number - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - payment_authorized_at: Date - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "ps") - } -} - -/** - * @schema PaymentSession - * title: "Payment Session" - * description: "A Payment Session is created when a Customer initilizes the checkout flow, and can be used to hold the state of a payment flow. Each Payment Session is controlled by a Payment Provider, which is responsible for the communication with external payment services. Authorized Payment Sessions will eventually get promoted to Payments to indicate that they are authorized for payment processing such as capture or refund. Payment sessions can also be used as part of payment collections." - * type: object - * required: - * - amount - * - cart_id - * - created_at - * - data - * - id - * - is_initiated - * - is_selected - * - idempotency_key - * - payment_authorized_at - * - provider_id - * - status - * - updated_at - * properties: - * id: - * description: The payment session's ID - * type: string - * example: ps_01G901XNSRM2YS3ASN9H5KG3FZ - * cart_id: - * description: The ID of the cart that the payment session was created for. - * nullable: true - * type: string - * example: cart_01G8ZH853Y6TFXWPG5EYE81X63 - * cart: - * description: The details of the cart that the payment session was created for. - * x-expandable: "cart" - * nullable: true - * $ref: "#/components/schemas/Cart" - * provider_id: - * description: The ID of the Payment Provider that is responsible for the Payment Session - * type: string - * example: manual - * is_selected: - * description: A flag to indicate if the Payment Session has been selected as the method that will be used to complete the purchase. - * nullable: true - * type: boolean - * example: true - * is_initiated: - * description: A flag to indicate if a communication with the third party provider has been initiated. - * type: boolean - * default: false - * example: true - * status: - * description: Indicates the status of the Payment Session. Will default to `pending`, and will eventually become `authorized`. Payment Sessions may have the status of `requires_more` to indicate that further actions are to be completed by the Customer. - * type: string - * enum: - * - authorized - * - pending - * - requires_more - * - error - * - canceled - * example: pending - * data: - * description: The data required for the Payment Provider to identify, modify and process the Payment Session. Typically this will be an object that holds an id to the external payment session, but can be an empty object if the Payment Provider doesn't hold any state. - * type: object - * example: {} - * idempotency_key: - * description: Randomly generated key used to continue the completion of a cart in case of failure. - * nullable: true - * type: string - * externalDocs: - * url: https://docs.medusajs.com/development/idempotency-key/overview.md - * description: Learn more how to use the idempotency key. - * amount: - * description: The amount that the Payment Session has been authorized for. - * nullable: true - * type: integer - * example: 100 - * payment_authorized_at: - * description: The date with timezone at which the Payment Session was authorized. - * nullable: true - * type: string - * format: date-time - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - */ diff --git a/packages/medusa/src/models/payment.ts b/packages/medusa/src/models/payment.ts deleted file mode 100644 index ddb9af2d6d..0000000000 --- a/packages/medusa/src/models/payment.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - OneToOne, - Relation, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { BaseEntity } from "../interfaces/models/base-entity" -import { generateEntityId } from "../utils/generate-entity-id" -import { Cart } from "./cart" -import { Currency } from "./currency" -import { Order } from "./order" -import { Swap } from "./swap" - -@Index(["cart_id"], { where: "canceled_at IS NOT NULL" }) -@Index("UniquePaymentActive", ["cart_id"], { - where: "canceled_at IS NULL", - unique: true, -}) -@Entity() -export class Payment extends BaseEntity { - @Index() - @Column({ nullable: true }) - swap_id: string - - @OneToOne(() => Swap) - @JoinColumn({ name: "swap_id" }) - swap: Relation - - @Index() - @Column({ nullable: true }) - cart_id: string - - @ManyToOne(() => Cart) - @JoinColumn({ name: "cart_id" }) - cart: Relation - - @Index() - @Column({ nullable: true }) - order_id: string - - @ManyToOne(() => Order, (order) => order.payments) - @JoinColumn({ name: "order_id" }) - order: Relation - - @Column({ type: "int" }) - amount: number - - @Index() - @Column() - currency_code: string - - @ManyToOne(() => Currency) - @JoinColumn({ name: "currency_code", referencedColumnName: "code" }) - currency: Relation - - @Column({ type: "int", default: 0 }) - amount_refunded: number - - @Index() - @Column() - provider_id: string - - @DbAwareColumn({ type: "jsonb" }) - data: Record - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - captured_at: Date | string - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - canceled_at: Date | string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - @Column({ nullable: true }) - idempotency_key: string - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "pay") - } -} - -/** - * @schema Payment - * title: "Payment" - * description: "A payment is originally created from a payment session. Once a payment session is authorized, the payment is created to represent the authorized amount with a given payment method. Payments can be captured, canceled or refunded. Payments can be made towards orders, swaps, order edits, or other resources." - * type: object - * required: - * - amount - * - amount_refunded - * - canceled_at - * - captured_at - * - cart_id - * - created_at - * - currency_code - * - data - * - id - * - idempotency_key - * - metadata - * - order_id - * - provider_id - * - swap_id - * - updated_at - * properties: - * id: - * description: The payment's ID - * type: string - * example: pay_01G2SJNT6DEEWDFNAJ4XWDTHKE - * swap_id: - * description: The ID of the swap that this payment was potentially created for. - * nullable: true - * type: string - * example: null - * swap: - * description: The details of the swap that this payment was potentially created for. - * x-expandable: "swap" - * nullable: true - * $ref: "#/components/schemas/Swap" - * cart_id: - * description: The ID of the cart that the payment session was potentially created for. - * nullable: true - * type: string - * cart: - * description: The details of the cart that the payment session was potentially created for. - * x-expandable: "cart" - * nullable: true - * $ref: "#/components/schemas/Cart" - * order_id: - * description: The ID of the order that the payment session was potentially created for. - * nullable: true - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * order: - * description: The details of the order that the payment session was potentially created for. - * x-expandable: "order" - * nullable: true - * $ref: "#/components/schemas/Order" - * amount: - * description: The amount that the Payment has been authorized for. - * type: integer - * example: 100 - * currency_code: - * description: The 3 character ISO currency code of the payment. - * type: string - * example: usd - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * currency: - * description: The details of the currency of the payment. - * x-expandable: "currency" - * nullable: true - * $ref: "#/components/schemas/Currency" - * amount_refunded: - * description: The amount of the original Payment amount that has been refunded back to the Customer. - * type: integer - * default: 0 - * example: 0 - * provider_id: - * description: The id of the Payment Provider that is responsible for the Payment - * type: string - * example: manual - * data: - * description: The data required for the Payment Provider to identify, modify and process the Payment. Typically this will be an object that holds an id to the external payment session, but can be an empty object if the Payment Provider doesn't hold any state. - * type: object - * example: {} - * captured_at: - * description: The date with timezone at which the Payment was captured. - * nullable: true - * type: string - * format: date-time - * canceled_at: - * description: The date with timezone at which the Payment was canceled. - * nullable: true - * type: string - * format: date-time - * idempotency_key: - * description: Randomly generated key used to continue the completion of a payment in case of failure. - * nullable: true - * type: string - * externalDocs: - * url: https://docs.medusajs.com/development/idempotency-key/overview.md - * description: Learn more how to use the idempotency key. - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/price-list.ts b/packages/medusa/src/models/price-list.ts deleted file mode 100644 index 9a62b763e4..0000000000 --- a/packages/medusa/src/models/price-list.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { PriceListStatus, PriceListType } from "@medusajs/utils" -import { - BeforeInsert, - Column, - Entity, - JoinTable, - ManyToMany, - OneToMany, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { FeatureFlagColumn } from "../utils/feature-flag-decorators" -import { generateEntityId } from "../utils/generate-entity-id" -import { CustomerGroup } from "./customer-group" -import { MoneyAmount } from "./money-amount" - -@Entity() -export class PriceList extends SoftDeletableEntity { - @Column() - name: string - - @Column() - description: string - - @DbAwareColumn({ type: "enum", enum: PriceListType, default: "sale" }) - type: PriceListType - - @DbAwareColumn({ type: "enum", enum: PriceListStatus, default: "draft" }) - status: PriceListStatus - - @Column({ - type: resolveDbType("timestamptz"), - nullable: true, - }) - starts_at: Date | null - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - ends_at: Date | null - - @JoinTable({ - name: "price_list_customer_groups", - joinColumn: { - name: "price_list_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "customer_group_id", - referencedColumnName: "id", - }, - }) - @ManyToMany(() => CustomerGroup, (cg) => cg.price_lists, { - onDelete: "CASCADE", - }) - customer_groups: CustomerGroup[] - - @OneToMany(() => MoneyAmount, (moneyAmount) => moneyAmount.price_list, { - onDelete: "CASCADE", - }) - prices: MoneyAmount[] - - @FeatureFlagColumn(TaxInclusivePricingFeatureFlag.key, { default: false }) - includes_tax: boolean - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): undefined | void { - this.id = generateEntityId(this.id, "pl") - } -} - -/** - * @schema PriceList - * title: "Price List" - * description: "A Price List represents a set of prices that override the default price for one or more product variants." - * type: object - * required: - * - created_at - * - deleted_at - * - description - * - ends_at - * - id - * - name - * - starts_at - * - status - * - type - * - updated_at - * properties: - * id: - * description: The price list's ID - * type: string - * example: pl_01G8X3CKJXCG5VXVZ87H9KC09W - * name: - * description: The price list's name - * type: string - * example: VIP Prices - * description: - * description: The price list's description - * type: string - * example: Prices for VIP customers - * type: - * description: The type of Price List. This can be one of either `sale` or `override`. - * type: string - * enum: - * - sale - * - override - * default: sale - * status: - * description: The status of the Price List - * type: string - * enum: - * - active - * - draft - * default: draft - * starts_at: - * description: The date with timezone that the Price List starts being valid. - * nullable: true - * type: string - * format: date-time - * ends_at: - * description: The date with timezone that the Price List stops being valid. - * nullable: true - * type: string - * format: date-time - * customer_groups: - * description: The details of the customer groups that the Price List can apply to. - * type: array - * x-expandable: "customer_groups" - * items: - * $ref: "#/components/schemas/CustomerGroup" - * prices: - * description: The prices that belong to the price list, represented as a Money Amount. - * type: array - * x-expandable: "prices" - * items: - * $ref: "#/components/schemas/MoneyAmount" - * includes_tax: - * description: "Whether the price list prices include tax" - * type: boolean - * x-featureFlag: "tax_inclusive_pricing" - * default: false - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - */ diff --git a/packages/medusa/src/models/product-category.ts b/packages/medusa/src/models/product-category.ts deleted file mode 100644 index 633c84576c..0000000000 --- a/packages/medusa/src/models/product-category.ts +++ /dev/null @@ -1,190 +0,0 @@ -import { kebabCase } from "lodash" -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - JoinTable, - ManyToMany, - Relation, - Tree, - TreeChildren, - TreeParent, -} from "typeorm" -import { Product } from "." -import { BaseEntity } from "../interfaces/models/base-entity" -import { DbAwareColumn } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -@Tree("materialized-path") -@Index(["parent_category_id", "rank"], { unique: true }) -export class ProductCategory extends BaseEntity { - /** - * @apiIgnore - */ - static productCategoryProductJoinTable = "product_category_product" - /** - * @apiIgnore - */ - static treeRelations = ["parent_category", "category_children"] - - @Column() - name: string - - @Column({ nullable: false, default: "" }) - description: string - - @Index({ unique: true }) - @Column({ nullable: false }) - handle: string - - @Column() - is_active: Boolean - - @Column() - is_internal: Boolean - - // The materialized path column is added dynamically by typeorm. Commenting this here for it - // to not be a mystery - // https://github.com/typeorm/typeorm/blob/62518ae1226f22b2f230afa615532c92f1544f01/src/metadata-builder/EntityMetadataBuilder.ts#L615 - // @Column({ nullable: true, default: '' }) - // mpath: String - - @TreeParent() - @JoinColumn({ name: "parent_category_id" }) - parent_category: Relation | null - - // Typeorm also keeps track of the category's parent at all times. - @Column() - parent_category_id: string | null - - @TreeChildren({ cascade: true }) - category_children: Relation[] - - @Column({ nullable: false, default: 0 }) - rank: number - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - @ManyToMany(() => Product, { cascade: ["remove", "soft-remove"] }) - @JoinTable({ - name: ProductCategory.productCategoryProductJoinTable, - joinColumn: { - name: "product_category_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "product_id", - referencedColumnName: "id", - }, - }) - products: Relation[] - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "pcat") - - if (!this.handle) { - this.handle = kebabCase(this.name) - } - } -} - -/** - * @schema ProductCategory - * title: "Product Category" - * description: "A product category can be used to categorize products into a hierarchy of categories." - * x-resourceId: ProductCategory - * x-featureFlag: "product_categories" - * type: object - * required: - * - category_children - * - created_at - * - handle - * - id - * - is_active - * - is_internal - * - metadata - * - mpath - * - name - * - parent_category_id - * - updated_at - * properties: - * id: - * description: The product category's ID - * type: string - * example: pcat_01G2SG30J8C85S4A5CHM2S1NS2 - * name: - * description: The product category's name - * type: string - * example: Regular Fit - * description: - * description: The product category's description. - * type: string - * default: "" - * handle: - * description: A unique string that identifies the Product Category - can for example be used in slug structures. - * type: string - * example: regular-fit - * mpath: - * description: A string for Materialized Paths - used for finding ancestors and descendents - * nullable: true - * type: string - * example: pcat_id1.pcat_id2.pcat_id3 - * is_internal: - * type: boolean - * description: A flag to make product category an internal category for admins - * default: false - * is_active: - * type: boolean - * description: A flag to make product category visible/hidden in the store front - * default: false - * rank: - * type: integer - * description: An integer that depicts the rank of category in a tree node - * default: 0 - * category_children: - * description: The details of the category's children. - * type: array - * x-expandable: "category_children" - * items: - * $ref: "#/components/schemas/ProductCategory" - * parent_category_id: - * description: The ID of the parent category. - * nullable: true - * type: string - * default: null - * parent_category: - * description: The details of the parent of this category. - * x-expandable: "parent_category" - * nullable: true - * $ref: "#/components/schemas/ProductCategory" - * products: - * description: The details of the products that belong to this category. - * type: array - * x-expandable: "products" - * items: - * $ref: "#/components/schemas/Product" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/product-collection.ts b/packages/medusa/src/models/product-collection.ts deleted file mode 100644 index b4c8c090ff..0000000000 --- a/packages/medusa/src/models/product-collection.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - OneToMany, - Relation, -} from "typeorm" - -import _ from "lodash" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { DbAwareColumn } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" -import { Product } from "./product" - -@Entity() -export class ProductCollection extends SoftDeletableEntity { - @Column() - title: string - - @Index({ unique: true, where: "deleted_at IS NULL" }) - @Column({ nullable: true }) - handle: string - - @OneToMany(() => Product, (product) => product.collection) - products: Relation[] - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private createHandleIfNotProvided(): void { - if (this.id) return - - this.id = generateEntityId(this.id, "pcol") - if (!this.handle) { - this.handle = _.kebabCase(this.title) - } - } -} - -/** - * @schema ProductCollection - * title: "Product Collection" - * description: "A Product Collection allows grouping together products for promotional purposes. For example, an admin can create a Summer collection, add products to it, and showcase it on the storefront." - * type: object - * required: - * - created_at - * - deleted_at - * - handle - * - id - * - metadata - * - title - * - updated_at - * properties: - * id: - * description: The product collection's ID - * type: string - * example: pcol_01F0YESBFAZ0DV6V831JXWH0BG - * title: - * description: The title that the Product Collection is identified by. - * type: string - * example: Summer Collection - * handle: - * description: A unique string that identifies the Product Collection - can for example be used in slug structures. - * nullable: true - * type: string - * example: summer-collection - * products: - * description: The details of the products that belong to this product collection. - * type: array - * x-expandable: "products" - * items: - * $ref: "#/components/schemas/Product" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/product-option-value.ts b/packages/medusa/src/models/product-option-value.ts deleted file mode 100644 index 5acc25d411..0000000000 --- a/packages/medusa/src/models/product-option-value.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - Relation, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { DbAwareColumn } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" -import { ProductOption } from "./product-option" -import { ProductVariant } from "./product-variant" - -@Entity() -export class ProductOptionValue extends SoftDeletableEntity { - @Column() - value: string - - @Index("idx_product_option_value_option_id") - @Column() - option_id: string - - @ManyToOne(() => ProductOption, (option) => option.values) - @JoinColumn({ name: "option_id" }) - option: Relation - - @Index("idx_product_option_value_variant_id") - @Column() - variant_id: string - - @ManyToOne(() => ProductVariant, (variant) => variant.options, { - onDelete: "CASCADE", - }) - @JoinColumn({ name: "variant_id" }) - variant: Relation - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "optval") - } -} - -/** - * @schema ProductOptionValue - * title: "Product Option Value" - * description: "An option value is one of the possible values of a Product Option. Product Variants specify a unique combination of product option values." - * type: object - * required: - * - created_at - * - deleted_at - * - id - * - metadata - * - option_id - * - updated_at - * - value - * - variant_id - * properties: - * id: - * description: The product option value's ID - * type: string - * example: optval_01F0YESHR7S6ECD03RF6W12DSJ - * value: - * description: The value that the Product Variant has defined for the specific Product Option (e.g. if the Product Option is "Size" this value could be `Small`, `Medium` or `Large`). - * type: string - * example: large - * option_id: - * description: The ID of the Product Option that the Product Option Value belongs to. - * type: string - * example: opt_01F0YESHQBZVKCEXJ24BS6PCX3 - * option: - * description: The details of the product option that the Product Option Value belongs to. - * x-expandable: "option" - * nullable: true - * $ref: "#/components/schemas/ProductOption" - * variant_id: - * description: The ID of the product variant that uses this product option value. - * type: string - * example: variant_01G1G5V2MRX2V3PVSR2WXYPFB6 - * variant: - * description: The details of the product variant that uses this product option value. - * x-expandable: "variant" - * nullable: true - * $ref: "#/components/schemas/ProductVariant" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/product-option.ts b/packages/medusa/src/models/product-option.ts deleted file mode 100644 index d35a4ca477..0000000000 --- a/packages/medusa/src/models/product-option.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - JoinColumn, - ManyToOne, - OneToMany, - Relation, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { DbAwareColumn } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" -import { Product } from "./product" -import { ProductOptionValue } from "./product-option-value" - -@Entity() -export class ProductOption extends SoftDeletableEntity { - @Column() - title: string - - @OneToMany(() => ProductOptionValue, (value) => value.option, { - cascade: ["soft-remove", "remove"], - }) - values: Relation[] - - @Column() - product_id: string - - @ManyToOne(() => Product, (product) => product.options) - @JoinColumn({ name: "product_id" }) - product: Relation - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "opt") - } -} - -/** - * @schema ProductOption - * title: "Product Option" - * description: A Product Option defines properties that may vary between different variants of a Product. Common Product Options are "Size" and "Color". Admins are free to create any product options. - * type: object - * required: - * - created_at - * - deleted_at - * - id - * - metadata - * - product_id - * - title - * - updated_at - * properties: - * id: - * description: The product option's ID - * type: string - * example: opt_01F0YESHQBZVKCEXJ24BS6PCX3 - * title: - * description: The title that the Product Option is defined by (e.g. `Size`). - * type: string - * example: Size - * values: - * description: The details of the values of the product option. - * type: array - * x-expandable: "values" - * items: - * $ref: "#/components/schemas/ProductOptionValue" - * product_id: - * description: The ID of the product that this product option belongs to. - * type: string - * example: prod_01G1G5V2MBA328390B5AXJ610F - * product: - * description: The details of the product that this product option belongs to. - * x-expandable: "product" - * nullable: true - * $ref: "#/components/schemas/Product" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/product-sales-channel.ts b/packages/medusa/src/models/product-sales-channel.ts deleted file mode 100644 index 75792c3cb2..0000000000 --- a/packages/medusa/src/models/product-sales-channel.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { BeforeInsert, Column, Entity } from "typeorm" -import { BaseEntity } from "../interfaces" -import { generateEntityId } from "../utils" - -@Entity("product_sales_channel") -export class ProductSalesChannel extends BaseEntity { - @Column({ type: "text" }) - sales_channel_id: string - - @Column({ type: "text" }) - product_id: string - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "prodsc") - } -} diff --git a/packages/medusa/src/models/product-tag.ts b/packages/medusa/src/models/product-tag.ts deleted file mode 100644 index 90446c9b3d..0000000000 --- a/packages/medusa/src/models/product-tag.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { BeforeInsert, Column, Entity } from "typeorm" - -import { DbAwareColumn } from "../utils/db-aware-column" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class ProductTag extends SoftDeletableEntity { - @Column() - value: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "ptag") - } -} - -/** - * @schema ProductTag - * title: "Product Tag" - * description: "A Product Tag can be added to Products for easy filtering and grouping." - * type: object - * required: - * - created_at - * - deleted_at - * - id - * - metadata - * - updated_at - * - value - * properties: - * id: - * description: The product tag's ID - * type: string - * example: ptag_01G8K2MTMG9168F2B70S1TAVK3 - * value: - * description: The value that the Product Tag represents - * type: string - * example: Pants - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/product-tax-rate.ts b/packages/medusa/src/models/product-tax-rate.ts deleted file mode 100644 index 1e031b00d2..0000000000 --- a/packages/medusa/src/models/product-tax-rate.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - CreateDateColumn, - Entity, - JoinColumn, - ManyToOne, - PrimaryColumn, - UpdateDateColumn, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { Product } from "./product" -import { TaxRate } from "./tax-rate" - -@Entity() -export class ProductTaxRate { - @PrimaryColumn() - product_id: string - - @PrimaryColumn() - rate_id: string - - @ManyToOne(() => Product, { onDelete: "CASCADE" }) - @JoinColumn({ name: "product_id" }) - product?: Product - - // Note the onDelete config here - @ManyToOne(() => TaxRate, { onDelete: "CASCADE" }) - @JoinColumn({ name: "rate_id" }) - tax_rate?: TaxRate - - @CreateDateColumn({ type: resolveDbType("timestamptz") }) - created_at: Date - - @UpdateDateColumn({ type: resolveDbType("timestamptz") }) - updated_at: Date - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record -} - -/** - * @schema ProductTaxRate - * title: "Product Tax Rate" - * description: "This represents the association between a tax rate and a product to indicate that the product is taxed in a way different than the default." - * type: object - * required: - * - created_at - * - metadata - * - product_id - * - rate_id - * - updated_at - * properties: - * product_id: - * description: The ID of the Product - * type: string - * example: prod_01G1G5V2MBA328390B5AXJ610F - * product: - * description: The details of the product. - * x-expandable: "product" - * nullable: true - * $ref: "#/components/schemas/Product" - * rate_id: - * description: The ID of the Tax Rate - * type: string - * example: txr_01G8XDBAWKBHHJRKH0AV02KXBR - * tax_rate: - * description: The details of the tax rate. - * x-expandable: "tax_rate" - * nullable: true - * $ref: "#/components/schemas/TaxRate" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/product-type-tax-rate.ts b/packages/medusa/src/models/product-type-tax-rate.ts deleted file mode 100644 index 528dc5a953..0000000000 --- a/packages/medusa/src/models/product-type-tax-rate.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { - CreateDateColumn, - Entity, - JoinColumn, - ManyToOne, - PrimaryColumn, - UpdateDateColumn, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { ProductType } from "./product-type" -import { TaxRate } from "./tax-rate" - -@Entity() -export class ProductTypeTaxRate { - @PrimaryColumn() - product_type_id: string - - @PrimaryColumn() - rate_id: string - - @ManyToOne(() => ProductType, { onDelete: "CASCADE" }) - @JoinColumn({ name: "product_type_id" }) - product_type?: ProductType - - @ManyToOne(() => TaxRate, { onDelete: "CASCADE" }) - @JoinColumn({ name: "rate_id" }) - tax_rate?: TaxRate - - @CreateDateColumn({ type: resolveDbType("timestamptz") }) - created_at: Date - - @UpdateDateColumn({ type: resolveDbType("timestamptz") }) - updated_at: Date - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record -} - -/** - * @schema ProductTypeTaxRate - * title: "Product Type Tax Rate" - * description: "This represents the association between a tax rate and a product type to indicate that the product type is taxed in a different way than the default." - * type: object - * required: - * - created_at - * - metadata - * - product_type_id - * - rate_id - * - updated_at - * properties: - * product_type_id: - * description: The ID of the Product type - * type: string - * example: ptyp_01G8X9A7ESKAJXG2H0E6F1MW7A - * product_type: - * description: The details of the product type. - * x-expandable: "product_type" - * nullable: true - * $ref: "#/components/schemas/ProductType" - * rate_id: - * description: The id of the Tax Rate - * type: string - * example: txr_01G8XDBAWKBHHJRKH0AV02KXBR - * tax_rate: - * description: The details of the tax rate. - * x-expandable: "tax_rate" - * nullable: true - * $ref: "#/components/schemas/TaxRate" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/product-type.ts b/packages/medusa/src/models/product-type.ts deleted file mode 100644 index 01390d4b36..0000000000 --- a/packages/medusa/src/models/product-type.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { BeforeInsert, Column, Entity } from "typeorm" - -import { DbAwareColumn } from "../utils/db-aware-column" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class ProductType extends SoftDeletableEntity { - @Column() - value: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "ptyp") - } -} - -/** - * @schema ProductType - * title: "Product Type" - * description: "A Product Type can be added to Products for filtering and reporting purposes." - * type: object - * required: - * - created_at - * - deleted_at - * - id - * - metadata - * - updated_at - * - value - * properties: - * id: - * description: The product type's ID - * type: string - * example: ptyp_01G8X9A7ESKAJXG2H0E6F1MW7A - * value: - * description: The value that the Product Type represents. - * type: string - * example: Clothing - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/product-variant-inventory-item.ts b/packages/medusa/src/models/product-variant-inventory-item.ts deleted file mode 100644 index 59266fe230..0000000000 --- a/packages/medusa/src/models/product-variant-inventory-item.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - Relation, -} from "typeorm" -import { SoftDeletableEntity } from "../interfaces" -import { generateEntityId } from "../utils" -import { ProductVariant } from "./product-variant" - -@Entity() -export class ProductVariantInventoryItem extends SoftDeletableEntity { - @Index() - @Column({ type: "text" }) - inventory_item_id: string - - @Index() - @Column({ type: "text" }) - variant_id: string - - @ManyToOne(() => ProductVariant, (variant) => variant.inventory_items) - @JoinColumn({ name: "variant_id" }) - variant: Relation - - @Column({ type: "int", default: 1 }) - required_quantity: number - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "pvitem") - } -} - -/** - * @schema ProductVariantInventoryItem - * title: "Product Variant Inventory Item" - * description: "A Product Variant Inventory Item links variants with inventory items and denotes the required quantity of the variant." - * type: object - * required: - * - created_at - * - deleted_at - * - id - * - inventory_item_id - * - required_quantity - * - updated_at - * - variant_id - * properties: - * id: - * description: The product variant inventory item's ID - * type: string - * example: pvitem_01G8X9A7ESKAJXG2H0E6F1MW7A - * inventory_item_id: - * description: The id of the inventory item - * type: string - * variant_id: - * description: The id of the variant. - * type: string - * variant: - * description: The details of the product variant. - * x-expandable: "variant" - * nullable: true - * $ref: "#/components/schemas/ProductVariant" - * required_quantity: - * description: The quantity of an inventory item required for the variant. - * type: integer - * default: 1 - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - */ diff --git a/packages/medusa/src/models/product-variant-money-amount.ts b/packages/medusa/src/models/product-variant-money-amount.ts deleted file mode 100644 index ccef76427f..0000000000 --- a/packages/medusa/src/models/product-variant-money-amount.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { BeforeInsert, Column, Entity, Index } from "typeorm" -import { generateEntityId } from "../utils" -import { SoftDeletableEntity } from "../interfaces" - -@Entity() -export class ProductVariantMoneyAmount extends SoftDeletableEntity { - @Index("idx_product_variant_money_amount_money_amount_id_unique", { - unique: true, - }) - @Column() - money_amount_id: string - - @Index("idx_product_variant_money_amount_variant_id") - @Column() - variant_id: string - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "pvma_") - } -} diff --git a/packages/medusa/src/models/product-variant.ts b/packages/medusa/src/models/product-variant.ts deleted file mode 100644 index dd2c524bea..0000000000 --- a/packages/medusa/src/models/product-variant.ts +++ /dev/null @@ -1,302 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, - OneToMany, - Relation, -} from "typeorm" -import { DbAwareColumn, generateEntityId } from "../utils" - -import { SoftDeletableEntity } from "../interfaces" -import { MoneyAmount } from "./money-amount" -import { Product } from "./product" -import { ProductOptionValue } from "./product-option-value" -import { ProductVariantInventoryItem } from "./product-variant-inventory-item" - -@Entity() -export class ProductVariant extends SoftDeletableEntity { - @Column() - title: string - - @Index() - @Column() - product_id: string - - @ManyToOne(() => Product, (product) => product.variants) - @JoinColumn({ name: "product_id" }) - product: Relation - - @ManyToMany(() => MoneyAmount, { - cascade: ["remove", "soft-remove", "recover"], - }) - @JoinTable({ - name: "product_variant_money_amount", - joinColumn: { - name: "variant_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "money_amount_id", - referencedColumnName: "id", - }, - }) - prices: Relation[] - - @Column({ nullable: true, type: "text" }) - @Index({ unique: true, where: "deleted_at IS NULL" }) - sku: string | null - - @Column({ nullable: true, type: "text" }) - @Index({ unique: true, where: "deleted_at IS NULL" }) - barcode: string | null - - @Column({ nullable: true, type: "text" }) - @Index({ unique: true, where: "deleted_at IS NULL" }) - ean: string | null - - @Column({ nullable: true, type: "text" }) - @Index({ unique: true, where: "deleted_at IS NULL" }) - upc: string | null - - @Column({ nullable: true, type: "text", default: 0 }) - variant_rank: number | null - - @Column({ type: "int" }) - inventory_quantity: number - - @Column({ default: false }) - allow_backorder: boolean - - @Column({ default: true }) - manage_inventory: boolean - - @Column({ nullable: true, type: "text" }) - hs_code: string | null - - @Column({ nullable: true, type: "text" }) - origin_country: string | null - - @Column({ nullable: true, type: "text" }) - mid_code: string | null - - @Column({ nullable: true, type: "text" }) - material: string | null - - @Column({ type: "int", nullable: true }) - weight: number | null - - @Column({ type: "int", nullable: true }) - length: number | null - - @Column({ type: "int", nullable: true }) - height: number | null - - @Column({ type: "int", nullable: true }) - width: number | null - - @OneToMany(() => ProductOptionValue, (optionValue) => optionValue.variant, { - cascade: true, - }) - options: Relation[] - - @OneToMany( - () => ProductVariantInventoryItem, - (inventoryItem) => inventoryItem.variant, - { - cascade: ["soft-remove", "remove"], - } - ) - inventory_items: Relation[] - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record | null - - purchasable?: boolean - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "variant") - } -} - -/** - * @schema ProductVariant - * title: "Product Variant" - * description: "A Product Variant represents a Product with a specific set of Product Option configurations. The maximum number of Product Variants that a Product can have is given by the number of available Product Option combinations. A product must at least have one product variant." - * type: object - * required: - * - allow_backorder - * - barcode - * - created_at - * - deleted_at - * - ean - * - height - * - hs_code - * - id - * - inventory_quantity - * - length - * - manage_inventory - * - material - * - metadata - * - mid_code - * - origin_country - * - product_id - * - sku - * - title - * - upc - * - updated_at - * - weight - * - width - * properties: - * id: - * description: The product variant's ID - * type: string - * example: variant_01G1G5V2MRX2V3PVSR2WXYPFB6 - * title: - * description: A title that can be displayed for easy identification of the Product Variant. - * type: string - * example: Small - * product_id: - * description: The ID of the product that the product variant belongs to. - * type: string - * example: prod_01G1G5V2MBA328390B5AXJ610F - * product: - * description: The details of the product that the product variant belongs to. - * x-expandable: "product" - * nullable: true - * $ref: "#/components/schemas/Product" - * prices: - * description: The details of the prices of the Product Variant, each represented as a Money Amount. Each Money Amount represents a price in a given currency or a specific Region. - * type: array - * x-expandable: "prices" - * items: - * $ref: "#/components/schemas/MoneyAmount" - * sku: - * description: The unique stock keeping unit used to identify the Product Variant. This will usually be a unique identifer for the item that is to be shipped, and can be referenced across multiple systems. - * nullable: true - * type: string - * example: shirt-123 - * barcode: - * description: A generic field for a GTIN number that can be used to identify the Product Variant. - * nullable: true - * type: string - * example: null - * ean: - * description: An EAN barcode number that can be used to identify the Product Variant. - * nullable: true - * type: string - * example: null - * upc: - * description: A UPC barcode number that can be used to identify the Product Variant. - * nullable: true - * type: string - * example: null - * variant_rank: - * description: The ranking of this variant - * nullable: true - * type: number - * default: 0 - * inventory_quantity: - * description: The current quantity of the item that is stocked. - * type: integer - * example: 100 - * allow_backorder: - * description: Whether the Product Variant should be purchasable when `inventory_quantity` is 0. - * type: boolean - * default: false - * manage_inventory: - * description: Whether Medusa should manage inventory for the Product Variant. - * type: boolean - * default: true - * hs_code: - * description: The Harmonized System code of the Product Variant. May be used by Fulfillment Providers to pass customs information to shipping carriers. - * nullable: true - * type: string - * example: null - * origin_country: - * description: The country in which the Product Variant was produced. May be used by Fulfillment Providers to pass customs information to shipping carriers. - * nullable: true - * type: string - * example: null - * mid_code: - * description: The Manufacturers Identification code that identifies the manufacturer of the Product Variant. May be used by Fulfillment Providers to pass customs information to shipping carriers. - * nullable: true - * type: string - * example: null - * material: - * description: The material and composition that the Product Variant is made of, May be used by Fulfillment Providers to pass customs information to shipping carriers. - * nullable: true - * type: string - * example: null - * weight: - * description: The weight of the Product Variant. May be used in shipping rate calculations. - * nullable: true - * type: number - * example: null - * length: - * description: "The length of the Product Variant. May be used in shipping rate calculations." - * nullable: true - * type: number - * example: null - * height: - * description: The height of the Product Variant. May be used in shipping rate calculations. - * nullable: true - * type: number - * example: null - * width: - * description: The width of the Product Variant. May be used in shipping rate calculations. - * nullable: true - * type: number - * example: null - * options: - * description: The details of the product options that this product variant defines values for. - * type: array - * x-expandable: "options" - * items: - * $ref: "#/components/schemas/ProductOptionValue" - * inventory_items: - * description: The details inventory items of the product variant. - * type: array - * x-expandable: "inventory_items" - * items: - * $ref: "#/components/schemas/ProductVariantInventoryItem" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * purchasable: - * description: | - * Only used with the inventory modules. - * A boolean value indicating whether the Product Variant is purchasable. - * A variant is purchasable if: - * - inventory is not managed - * - it has no inventory items - * - it is in stock - * - it is backorderable. - * type: boolean - */ diff --git a/packages/medusa/src/models/product.ts b/packages/medusa/src/models/product.ts deleted file mode 100644 index da2f4143bd..0000000000 --- a/packages/medusa/src/models/product.ts +++ /dev/null @@ -1,464 +0,0 @@ -import { - AfterLoad, - BeforeInsert, - BeforeUpdate, - Column, - Entity, - Index, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, - OneToMany, - Relation, -} from "typeorm" - -import _ from "lodash" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils" -import { DbAwareColumn } from "../utils/db-aware-column" -import { FeatureFlagDecorators } from "../utils/feature-flag-decorators" -import { Image } from "./image" -import { ProductCategory } from "./product-category" -import { ProductCollection } from "./product-collection" -import { ProductOption } from "./product-option" -import { ProductTag } from "./product-tag" -import { ProductType } from "./product-type" -import { ProductVariant } from "./product-variant" -import { SalesChannel } from "./sales-channel" -import { ShippingProfile } from "./shipping-profile" - -/** - * @enum - * - * The status of a product. - */ -export enum ProductStatus { - /** - * The product is a draft. It's not viewable by customers. - */ - DRAFT = "draft", - /** - * The product is proposed, but not yet published. - */ - PROPOSED = "proposed", - /** - * The product is published. - */ - PUBLISHED = "published", - /** - * The product is rejected. It's not viewable by customers. - */ - REJECTED = "rejected", -} - -@Entity() -export class Product extends SoftDeletableEntity { - @Column() - title: string - - @Column({ type: "text", nullable: true }) - subtitle: string | null - - @Column({ type: "text", nullable: true }) - description: string | null - - @Index({ unique: true, where: "deleted_at IS NULL" }) - @Column({ type: "text", nullable: true }) - handle: string | null - - @Column({ default: false }) - is_giftcard: boolean - - @DbAwareColumn({ type: "enum", enum: ProductStatus, default: "draft" }) - status: ProductStatus - - @ManyToMany(() => Image, { cascade: ["insert"] }) - @JoinTable({ - name: "product_images", - joinColumn: { - name: "product_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "image_id", - referencedColumnName: "id", - }, - }) - images: Relation[] - - @Column({ type: "text", nullable: true }) - thumbnail: string | null - - @OneToMany(() => ProductOption, (productOption) => productOption.product) - options: Relation[] - - @OneToMany(() => ProductVariant, (variant) => variant.product, { - cascade: true, - }) - variants: Relation[] - - @ManyToMany(() => ProductCategory, { cascade: ["remove", "soft-remove"] }) - @JoinTable({ - name: "product_category_product", - joinColumn: { - name: "product_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "product_category_id", - referencedColumnName: "id", - }, - }) - categories: Relation[] - - profile_id: string - - profile: Relation - - @ManyToMany(() => ShippingProfile, { - cascade: ["remove", "soft-remove"], - }) - @JoinTable({ - name: "product_shipping_profile", - joinColumn: { - name: "product_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "profile_id", - referencedColumnName: "id", - }, - }) - profiles: Relation[] - - @Column({ type: "int", nullable: true }) - weight: number | null - - @Column({ type: "int", nullable: true }) - length: number | null - - @Column({ type: "int", nullable: true }) - height: number | null - - @Column({ type: "int", nullable: true }) - width: number | null - - @Column({ type: "text", nullable: true }) - hs_code: string | null - - @Column({ type: "text", nullable: true }) - origin_country: string | null - - @Column({ type: "text", nullable: true }) - mid_code: string | null - - @Column({ type: "text", nullable: true }) - material: string | null - - @Column({ type: "text", nullable: true }) - collection_id: string | null - - @ManyToOne(() => ProductCollection) - @JoinColumn({ name: "collection_id" }) - collection: Relation - - @Column({ type: "text", nullable: true }) - type_id: string | null - - @ManyToOne(() => ProductType) - @JoinColumn({ name: "type_id" }) - type: Relation - - @ManyToMany(() => ProductTag) - @JoinTable({ - name: "product_tags", - joinColumn: { - name: "product_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "product_tag_id", - referencedColumnName: "id", - }, - }) - tags: Relation[] - - @Column({ default: true }) - discountable: boolean - - @Column({ type: "text", nullable: true }) - external_id: string | null - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record | null - - @FeatureFlagDecorators("sales_channels", [ - ManyToMany(() => SalesChannel, { cascade: ["remove", "soft-remove"] }), - JoinTable({ - name: "product_sales_channel", - joinColumn: { - name: "product_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "sales_channel_id", - referencedColumnName: "id", - }, - }), - ]) - sales_channels: Relation[] - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "prod") - - if (!this.handle) { - this.handle = _.kebabCase(this.title) - } - - if (this.profile_id) { - this.profiles = [{ id: this.profile_id }] as ShippingProfile[] - } - } - - /** - * @apiIgnore - */ - @BeforeUpdate() - private beforeUpdate(): void { - if (this.profile_id) { - this.profiles = [{ id: this.profile_id }] as ShippingProfile[] - } - } - - /** - * @apiIgnore - */ - @AfterLoad() - private afterLoad(): void { - if (this.profiles) { - this.profile = this.profiles[this.profiles.length - 1]! - this.profile_id = this.profile?.id - } - } -} - -/** - * @schema Product - * title: "Product" - * description: "A product is a saleable item that holds general information such as name or description. It must include at least one Product Variant, where each product variant defines different options to purchase the product with (for example, different sizes or colors). The prices and inventory of the product are defined on the variant level." - * type: object - * required: - * - collection_id - * - created_at - * - deleted_at - * - description - * - discountable - * - external_id - * - handle - * - height - * - hs_code - * - id - * - is_giftcard - * - length - * - material - * - metadata - * - mid_code - * - origin_country - * - profile_id - * - status - * - subtitle - * - type_id - * - thumbnail - * - title - * - updated_at - * - weight - * - width - * properties: - * id: - * description: The product's ID - * type: string - * example: prod_01G1G5V2MBA328390B5AXJ610F - * title: - * description: A title that can be displayed for easy identification of the Product. - * type: string - * example: Medusa Coffee Mug - * subtitle: - * description: An optional subtitle that can be used to further specify the Product. - * nullable: true - * type: string - * description: - * description: A short description of the Product. - * nullable: true - * type: string - * example: Every programmer's best friend. - * handle: - * description: A unique identifier for the Product (e.g. for slug structure). - * nullable: true - * type: string - * example: coffee-mug - * is_giftcard: - * description: Whether the Product represents a Gift Card. Products that represent Gift Cards will automatically generate a redeemable Gift Card code once they are purchased. - * type: boolean - * default: false - * status: - * description: The status of the product - * type: string - * enum: - * - draft - * - proposed - * - published - * - rejected - * default: draft - * images: - * description: The details of the product's images. - * type: array - * x-expandable: "images" - * items: - * $ref: "#/components/schemas/Image" - * thumbnail: - * description: A URL to an image file that can be used to identify the Product. - * nullable: true - * type: string - * format: uri - * options: - * description: The details of the Product Options that are defined for the Product. The product's variants will have a unique combination of values of the product's options. - * type: array - * x-expandable: "options" - * items: - * $ref: "#/components/schemas/ProductOption" - * variants: - * description: The details of the Product Variants that belong to the Product. Each will have a unique combination of values of the product's options. - * type: array - * x-expandable: "variants" - * items: - * $ref: "#/components/schemas/ProductVariant" - * categories: - * description: The details of the product categories that this product belongs to. - * type: array - * x-expandable: "categories" - * x-featureFlag: "product_categories" - * items: - * $ref: "#/components/schemas/ProductCategory" - * profile_id: - * description: The ID of the shipping profile that the product belongs to. The shipping profile has a set of defined shipping options that can be used to fulfill the product. - * type: string - * example: sp_01G1G5V239ENSZ5MV4JAR737BM - * profile: - * description: The details of the shipping profile that the product belongs to. The shipping profile has a set of defined shipping options that can be used to fulfill the product. - * x-expandable: "profile" - * nullable: true - * $ref: "#/components/schemas/ShippingProfile" - * profiles: - * description: Available if the relation `profiles` is expanded. - * nullable: true - * type: array - * items: - * $ref: "#/components/schemas/ShippingProfile" - * weight: - * description: The weight of the Product Variant. May be used in shipping rate calculations. - * nullable: true - * type: number - * example: null - * length: - * description: The length of the Product Variant. May be used in shipping rate calculations. - * nullable: true - * type: number - * example: null - * height: - * description: The height of the Product Variant. May be used in shipping rate calculations. - * nullable: true - * type: number - * example: null - * width: - * description: The width of the Product Variant. May be used in shipping rate calculations. - * nullable: true - * type: number - * example: null - * hs_code: - * description: The Harmonized System code of the Product Variant. May be used by Fulfillment Providers to pass customs information to shipping carriers. - * nullable: true - * type: string - * example: null - * origin_country: - * description: The country in which the Product Variant was produced. May be used by Fulfillment Providers to pass customs information to shipping carriers. - * nullable: true - * type: string - * example: null - * mid_code: - * description: The Manufacturers Identification code that identifies the manufacturer of the Product Variant. May be used by Fulfillment Providers to pass customs information to shipping carriers. - * nullable: true - * type: string - * example: null - * material: - * description: The material and composition that the Product Variant is made of, May be used by Fulfillment Providers to pass customs information to shipping carriers. - * nullable: true - * type: string - * example: null - * collection_id: - * description: The ID of the product collection that the product belongs to. - * nullable: true - * type: string - * example: pcol_01F0YESBFAZ0DV6V831JXWH0BG - * collection: - * description: The details of the product collection that the product belongs to. - * x-expandable: "collection" - * nullable: true - * $ref: "#/components/schemas/ProductCollection" - * type_id: - * description: The ID of the product type that the product belongs to. - * nullable: true - * type: string - * example: ptyp_01G8X9A7ESKAJXG2H0E6F1MW7A - * type: - * description: The details of the product type that the product belongs to. - * x-expandable: "type" - * nullable: true - * $ref: "#/components/schemas/ProductType" - * tags: - * description: The details of the product tags used in this product. - * type: array - * x-expandable: "type" - * items: - * $ref: "#/components/schemas/ProductTag" - * discountable: - * description: Whether the Product can be discounted. Discounts will not apply to Line Items of this Product when this flag is set to `false`. - * type: boolean - * default: true - * external_id: - * description: The external ID of the product - * nullable: true - * type: string - * example: null - * sales_channels: - * description: The details of the sales channels this product is available in. - * type: array - * x-expandable: "sales_channels" - * items: - * $ref: "#/components/schemas/SalesChannel" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/publishable-api-key-sales-channel.ts b/packages/medusa/src/models/publishable-api-key-sales-channel.ts deleted file mode 100644 index 9addc0c629..0000000000 --- a/packages/medusa/src/models/publishable-api-key-sales-channel.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { BeforeInsert, Column, Entity, PrimaryColumn } from "typeorm" -import { BaseEntity } from "../interfaces" -import { generateEntityId } from "../utils" - -@Entity("publishable_api_key_sales_channel") -export class PublishableApiKeySalesChannel extends BaseEntity { - @Column({ type: "text" }) - id: string - - @PrimaryColumn({ type: "text" }) - sales_channel_id: string - - @PrimaryColumn({ type: "text" }) - publishable_key_id: string - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "pksc") - } -} - -/** - * @schema PublishableApiKeySalesChannel - * title: "Publishable API Key Sales Channel" - * description: "This represents the association between the Publishable API keys and Sales Channels" - * type: object - * required: - * - publishable_key_id - * - sales_channel_id - * - created_at - * - updated_at - * - deleted_at - * properties: - * id: - * description: The relation's ID - * type: string - * example: pksc_01G8X9A7ESKAJXG2H0E6F1MW7A - * sales_channel_id: - * description: The sales channel's ID - * type: string - * example: sc_01G1G5V21KADXNGH29BJMAJ4B4 - * publishable_key_id: - * description: The publishable API key's ID - * type: string - * example: pak_01G1G5V21KADXNGH29BJMAJ4B4 - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - */ diff --git a/packages/medusa/src/models/publishable-api-key.ts b/packages/medusa/src/models/publishable-api-key.ts deleted file mode 100644 index d531fd55cf..0000000000 --- a/packages/medusa/src/models/publishable-api-key.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { BeforeInsert, Column, Entity } from "typeorm" - -import { BaseEntity } from "../interfaces" -import { generateEntityId, resolveDbType } from "../utils" - -@Entity() -export class PublishableApiKey extends BaseEntity { - @Column({ type: "varchar", nullable: true }) - created_by: string | null - - @Column({ type: "varchar", nullable: true }) - revoked_by: string | null - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - revoked_at?: Date - - @Column() - title: string - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "pk") - } -} - -/** - * @schema PublishableApiKey - * title: "Publishable API key" - * description: "A Publishable API key defines scopes that resources are available in. Then, it can be used in request to infer the resources without having to directly pass them. For example, a publishable API key can be associated with one or more sales channels. Then, when the publishable API key is passed in the header of a request, it is inferred what sales channel is being used without having to pass the sales channel as a query or body parameter of the request. Publishable API keys can only be used with sales channels, at the moment." - * type: object - * required: - * - created_at - * - created_by - * - id - * - revoked_by - * - revoked_at - * - title - * - updated_at - * properties: - * id: - * description: The key's ID - * type: string - * example: pk_01G1G5V27GYX4QXNARRQCW1N8T - * created_by: - * description: The unique identifier of the user that created the key. - * nullable: true - * type: string - * example: usr_01G1G5V26F5TB3GPAPNJ8X1S3V - * revoked_by: - * description: The unique identifier of the user that revoked the key. - * nullable: true - * type: string - * example: usr_01G1G5V26F5TB3GPAPNJ8X1S3V - * revoked_at: - * description: The date with timezone at which the key was revoked. - * nullable: true - * type: string - * format: date-time - * title: - * description: The key's title. - * type: string - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - */ diff --git a/packages/medusa/src/models/refund.ts b/packages/medusa/src/models/refund.ts deleted file mode 100644 index 42c063ac30..0000000000 --- a/packages/medusa/src/models/refund.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - OneToOne, - Relation, -} from "typeorm" - -import { BaseEntity } from "../interfaces/models/base-entity" -import { DbAwareColumn } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" -import { Order } from "./order" -import { Payment } from "./payment" - -/** - * @enum - * - * The reason of the refund. - */ -export enum RefundReason { - /** - * The refund is applied as a discount. - */ - DISCOUNT = "discount", - /** - * The refund is applied because of a created return. - */ - RETURN = "return", - /** - * The refund is applied because of a created swap. - */ - SWAP = "swap", - /** - * The refund is applied because of a created claim. - */ - CLAIM = "claim", - /** - * The refund is created for a custom reason. - */ - OTHER = "other", -} - -@Entity() -export class Refund extends BaseEntity { - @Index() - @Column({ nullable: true }) - order_id: string - - @Index() - @Column({ nullable: true }) - payment_id: string - - @ManyToOne(() => Order, (order) => order.payments) - @JoinColumn({ name: "order_id" }) - order: Relation - - @OneToOne(() => Payment, { nullable: true }) - @JoinColumn({ name: "payment_id" }) - payment: Relation - - @Column({ type: "int" }) - amount: number - - @Column({ nullable: true }) - note: string - - @DbAwareColumn({ type: "enum", enum: RefundReason }) - reason: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - @Column({ nullable: true }) - idempotency_key: string - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "ref") - } -} - -/** - * @schema Refund - * title: "Refund" - * description: "A refund represents an amount of money transfered back to the customer for a given reason. Refunds may occur in relation to Returns, Swaps and Claims, but can also be initiated by an admin for an order." - * type: object - * required: - * - amount - * - created_at - * - id - * - idempotency_key - * - metadata - * - note - * - order_id - * - payment_id - * - reason - * - updated_at - * properties: - * id: - * description: The refund's ID - * type: string - * example: ref_01G1G5V27GYX4QXNARRQCW1N8T - * order_id: - * description: The ID of the order this refund was created for. - * nullable: true - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * order: - * description: The details of the order this refund was created for. - * x-expandable: "order" - * nullable: true - * $ref: "#/components/schemas/Order" - * payment_id: - * description: The payment's ID, if available. - * nullable: true - * type: string - * example: pay_01G8ZCC5W42ZNY842124G7P5R9 - * payment: - * description: The details of the payment associated with the refund. - * x-expandable: "payment" - * nullable: true - * $ref: "#/components/schemas/Payment" - * amount: - * description: The amount that has be refunded to the Customer. - * type: integer - * example: 1000 - * note: - * description: An optional note explaining why the amount was refunded. - * nullable: true - * type: string - * example: I didn't like it - * reason: - * description: The reason given for the Refund, will automatically be set when processed as part of a Swap, Claim or Return. - * type: string - * enum: - * - discount - * - return - * - swap - * - claim - * - other - * example: return - * idempotency_key: - * description: Randomly generated key used to continue the completion of the refund in case of failure. - * nullable: true - * type: string - * externalDocs: - * url: https://docs.medusajs.com/development/idempotency-key/overview.md - * description: Learn more how to use the idempotency key. - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/region.ts b/packages/medusa/src/models/region.ts deleted file mode 100644 index 7954ffa698..0000000000 --- a/packages/medusa/src/models/region.ts +++ /dev/null @@ -1,227 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, - OneToMany, - Relation, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { DbAwareColumn } from "../utils/db-aware-column" -import { FeatureFlagColumn } from "../utils/feature-flag-decorators" -import { generateEntityId } from "../utils/generate-entity-id" -import { Country } from "./country" -import { Currency } from "./currency" -import { FulfillmentProvider } from "./fulfillment-provider" -import { PaymentProvider } from "./payment-provider" -import { TaxProvider } from "./tax-provider" -import { TaxRate } from "./tax-rate" - -@Entity() -export class Region extends SoftDeletableEntity { - @Column() - name: string - - @Index() - @Column() - currency_code: string - - @ManyToOne(() => Currency) - @JoinColumn({ name: "currency_code", referencedColumnName: "code" }) - currency: Relation - - @Column({ type: "real" }) - tax_rate: number - - @OneToMany(() => TaxRate, (tr) => tr.region) - tax_rates: Relation[] | null - - @Column({ nullable: true }) - tax_code: string - - @Column({ default: true }) - gift_cards_taxable: boolean - - @Column({ default: true }) - automatic_taxes: boolean - - @OneToMany(() => Country, (c) => c.region) - countries: Relation[] - - @Column({ type: "text", nullable: true }) - tax_provider_id: string | null - - @ManyToOne(() => TaxProvider) - @JoinColumn({ name: "tax_provider_id" }) - tax_provider: Relation - - @ManyToMany(() => PaymentProvider, { - cascade: ["insert", "update"], - }) - @JoinTable({ - name: "region_payment_providers", - joinColumn: { - name: "region_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "provider_id", - referencedColumnName: "id", - }, - }) - payment_providers: Relation[] - - @ManyToMany(() => FulfillmentProvider, { - cascade: ["insert", "update"], - }) - @JoinTable({ - name: "region_fulfillment_providers", - joinColumn: { - name: "region_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "provider_id", - referencedColumnName: "id", - }, - }) - fulfillment_providers: Relation[] - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - @FeatureFlagColumn(TaxInclusivePricingFeatureFlag.key, { default: false }) - includes_tax: boolean - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "reg") - } -} - -/** - * @schema Region - * title: "Region" - * description: "A region holds settings specific to a geographical location, including the currency, tax rates, and fulfillment and payment providers. A Region can consist of multiple countries to accomodate common shopping settings across countries." - * type: object - * required: - * - automatic_taxes - * - created_at - * - currency_code - * - deleted_at - * - gift_cards_taxable - * - id - * - metadata - * - name - * - tax_code - * - tax_provider_id - * - tax_rate - * - updated_at - * properties: - * id: - * description: The region's ID - * type: string - * example: reg_01G1G5V26T9H8Y0M4JNE3YGA4G - * name: - * description: The name of the region as displayed to the customer. If the Region only has one country it is recommended to write the country name. - * type: string - * example: EU - * currency_code: - * description: The three character currency code used in the region. - * type: string - * example: usd - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * currency: - * description: The details of the currency used in the region. - * x-expandable: "currency" - * nullable: true - * $ref: "#/components/schemas/Currency" - * tax_rate: - * description: The tax rate that should be charged on purchases in the Region. - * type: number - * example: 0 - * tax_rates: - * description: The details of the tax rates used in the region, aside from the default rate. - * type: array - * x-expandable: "tax_rates" - * items: - * $ref: "#/components/schemas/TaxRate" - * tax_code: - * description: The tax code used on purchases in the Region. This may be used by other systems for accounting purposes. - * nullable: true - * type: string - * example: null - * gift_cards_taxable: - * description: Whether the gift cards are taxable or not in this region. - * type: boolean - * default: true - * automatic_taxes: - * description: Whether taxes should be automated in this region. - * type: boolean - * default: true - * countries: - * description: The details of the countries included in this region. - * type: array - * x-expandable: "countries" - * items: - * $ref: "#/components/schemas/Country" - * tax_provider_id: - * description: The ID of the tax provider used in this region - * nullable: true - * type: string - * example: null - * tax_provider: - * description: The details of the tax provider used in the region. - * x-expandable: "tax_provider" - * nullable: true - * $ref: "#/components/schemas/TaxProvider" - * payment_providers: - * description: The details of the payment providers that can be used to process payments in the region. - * type: array - * x-expandable: "payment_providers" - * items: - * $ref: "#/components/schemas/PaymentProvider" - * fulfillment_providers: - * description: The details of the fulfillment providers that can be used to fulfill items of orders and similar resources in the region. - * type: array - * x-expandable: "fulfillment_providers" - * items: - * $ref: "#/components/schemas/FulfillmentProvider" - * includes_tax: - * description: "Whether the prices for the region include tax" - * type: boolean - * x-featureFlag: "tax_inclusive_pricing" - * default: false - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/return-item.ts b/packages/medusa/src/models/return-item.ts deleted file mode 100644 index ccbe5b3a8e..0000000000 --- a/packages/medusa/src/models/return-item.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { - Column, - Entity, - JoinColumn, - ManyToOne, - PrimaryColumn, - Relation, -} from "typeorm" - -import { DbAwareColumn } from "../utils/db-aware-column" -import { LineItem } from "./line-item" -import { Return } from "./return" -import { ReturnReason } from "./return-reason" - -@Entity() -export class ReturnItem { - @PrimaryColumn() - return_id: string - - @PrimaryColumn() - item_id: string - - @ManyToOne(() => Return) - @JoinColumn({ name: "return_id" }) - return_order: Relation - - @ManyToOne(() => LineItem) - @JoinColumn({ name: "item_id" }) - item: Relation - - @Column({ type: "int" }) - quantity: number - - @Column({ type: "boolean", default: true }) - is_requested: boolean - - @Column({ type: "int", nullable: true }) - requested_quantity: number - - @Column({ type: "int", nullable: true }) - received_quantity: number - - @Column({ nullable: true }) - reason_id: string - - @ManyToOne(() => ReturnReason) - @JoinColumn({ name: "reason_id" }) - reason: Relation - - @Column({ nullable: true }) - note: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record -} - -/** - * @schema ReturnItem - * title: "Return Item" - * description: "A return item represents a line item in an order that is to be returned. It includes details related to the return and the reason behind it." - * type: object - * required: - * - is_requested - * - item_id - * - metadata - * - note - * - quantity - * - reason_id - * - received_quantity - * - requested_quantity - * - return_id - * properties: - * return_id: - * description: The ID of the Return that the Return Item belongs to. - * type: string - * example: ret_01F0YET7XPCMF8RZ0Y151NZV2V - * item_id: - * description: The ID of the Line Item that the Return Item references. - * type: string - * example: item_01G8ZC9GWT6B2GP5FSXRXNFNGN - * return_order: - * description: Details of the Return that the Return Item belongs to. - * x-expandable: "return_order" - * nullable: true - * $ref: "#/components/schemas/Return" - * item: - * description: The details of the line item in the original order to be returned. - * x-expandable: "item" - * nullable: true - * $ref: "#/components/schemas/LineItem" - * quantity: - * description: The quantity of the Line Item to be returned. - * type: integer - * example: 1 - * is_requested: - * description: Whether the Return Item was requested initially or received unexpectedly in the warehouse. - * type: boolean - * default: true - * requested_quantity: - * description: The quantity that was originally requested to be returned. - * nullable: true - * type: integer - * example: 1 - * received_quantity: - * description: The quantity that was received in the warehouse. - * nullable: true - * type: integer - * example: 1 - * reason_id: - * description: The ID of the reason for returning the item. - * nullable: true - * type: string - * example: rr_01G8X82GCCV2KSQHDBHSSAH5TQ - * reason: - * description: The details of the reason for returning the item. - * x-expandable: "reason" - * nullable: true - * $ref: "#/components/schemas/ReturnReason" - * note: - * description: An optional note with additional details about the Return. - * nullable: true - * type: string - * example: I didn't like it. - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/return-reason.ts b/packages/medusa/src/models/return-reason.ts deleted file mode 100644 index b5cde80c4a..0000000000 --- a/packages/medusa/src/models/return-reason.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - OneToMany, -} from "typeorm" - -import { DbAwareColumn } from "../utils/db-aware-column" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class ReturnReason extends SoftDeletableEntity { - @Index({ unique: true, where: "deleted_at IS NULL" }) - @Column() - value: string - - @Column() - label: string - - @Column({ nullable: true }) - description: string - - @Column({ nullable: true }) - parent_return_reason_id: string | null - - @ManyToOne(() => ReturnReason, { cascade: ["soft-remove"] }) - @JoinColumn({ name: "parent_return_reason_id" }) - parent_return_reason: ReturnReason | null - - @OneToMany( - () => ReturnReason, - (return_reason) => return_reason.parent_return_reason, - { cascade: ["insert", "soft-remove"] } - ) - return_reason_children: ReturnReason[] - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "rr") - } -} - -/** - * @schema ReturnReason - * title: "Return Reason" - * description: "A Return Reason is a value defined by an admin. It can be used on Return Items in order to indicate why a Line Item was returned." - * type: object - * required: - * - created_at - * - deleted_at - * - description - * - id - * - label - * - metadata - * - parent_return_reason_id - * - updated_at - * - value - * properties: - * id: - * description: The return reason's ID - * type: string - * example: rr_01G8X82GCCV2KSQHDBHSSAH5TQ - * value: - * description: The value to identify the reason by. - * type: string - * example: damaged - * label: - * description: A text that can be displayed to the Customer as a reason. - * type: string - * example: Damaged goods - * description: - * description: A description of the Reason. - * nullable: true - * type: string - * example: Items that are damaged - * parent_return_reason_id: - * description: The ID of the parent reason. - * nullable: true - * type: string - * example: null - * parent_return_reason: - * description: The details of the parent reason. - * x-expandable: "parent_return_reason" - * nullable: true - * $ref: "#/components/schemas/ReturnReason" - * return_reason_children: - * description: The details of the child reasons. - * x-expandable: "return_reason_children" - * $ref: "#/components/schemas/ReturnReason" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/return.ts b/packages/medusa/src/models/return.ts deleted file mode 100644 index e7595183e7..0000000000 --- a/packages/medusa/src/models/return.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - OneToMany, - OneToOne, - Relation, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { BaseEntity } from "../interfaces/models/base-entity" -import { generateEntityId } from "../utils/generate-entity-id" -import { ClaimOrder } from "./claim-order" -import { Order } from "./order" -import { ReturnItem } from "./return-item" -import { ShippingMethod } from "./shipping-method" -import { Swap } from "./swap" - -/** - * @enum - * - * The return's status. - */ -export enum ReturnStatus { - /** - * The return is requested. - */ - REQUESTED = "requested", - /** - * The return is received. - */ - RECEIVED = "received", - /** - * The return is awaiting action. - */ - REQUIRES_ACTION = "requires_action", - /** - * The return is canceled. - */ - CANCELED = "canceled", -} - -@Entity() -export class Return extends BaseEntity { - @DbAwareColumn({ - type: "enum", - enum: ReturnStatus, - default: ReturnStatus.REQUESTED, - }) - status: ReturnStatus - - @OneToMany(() => ReturnItem, (item) => item.return_order, { - eager: true, - cascade: ["insert", "update"], - }) - items: Relation[] - - @Index() - @Column({ nullable: true, type: "text" }) - swap_id: string | null - - @OneToOne(() => Swap, (swap) => swap.return_order) - @JoinColumn({ name: "swap_id" }) - swap: Relation - - @Index() - @Column({ nullable: true, type: "text" }) - claim_order_id: string | null - - @OneToOne(() => ClaimOrder, (co) => co.return_order) - @JoinColumn({ name: "claim_order_id" }) - claim_order: Relation - - @Index() - @Column({ nullable: true, type: "text" }) - order_id: string | null - - @ManyToOne(() => Order, (o) => o.returns) - @JoinColumn({ name: "order_id" }) - order: Relation - - @OneToOne(() => ShippingMethod, (method) => method.return_order, { - cascade: true, - }) - shipping_method: Relation - - @Index() - @Column({ nullable: true, type: "text" }) - location_id: string | null - - @DbAwareColumn({ type: "jsonb", nullable: true }) - shipping_data: Record - - @Column({ type: "int" }) - refund_amount: number - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - received_at: Date - - @Column({ type: "boolean", nullable: true }) - no_notification: boolean | null - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record | null - - @Column({ nullable: true, type: "text" }) - idempotency_key: string | null - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "ret") - } -} - -/** - * @schema Return - * title: "Return" - * description: "A Return holds information about Line Items that a Customer wishes to send back, along with how the items will be returned. Returns can also be used as part of a Swap or a Claim." - * type: object - * required: - * - claim_order_id - * - created_at - * - id - * - idempotency_key - * - location_id - * - metadata - * - no_notification - * - order_id - * - received_at - * - refund_amount - * - shipping_data - * - status - * - swap_id - * - updated_at - * properties: - * id: - * description: The return's ID - * type: string - * example: ret_01F0YET7XPCMF8RZ0Y151NZV2V - * status: - * description: Status of the Return. - * type: string - * enum: - * - requested - * - received - * - requires_action - * - canceled - * default: requested - * items: - * description: The details of the items that the customer is returning. - * type: array - * x-expandable: "items" - * items: - * $ref: "#/components/schemas/ReturnItem" - * swap_id: - * description: The ID of the swap that the return may belong to. - * nullable: true - * type: string - * example: null - * swap: - * description: The details of the swap that the return may belong to. - * x-expandable: "swap" - * nullable: true - * $ref: "#/components/schemas/Swap" - * claim_order_id: - * description: The ID of the claim that the return may belong to. - * nullable: true - * type: string - * example: null - * claim_order: - * description: The details of the claim that the return may belong to. - * x-expandable: "claim_order" - * nullable: true - * $ref: "#/components/schemas/ClaimOrder" - * order_id: - * description: The ID of the order that the return was created for. - * nullable: true - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * order: - * description: The details of the order that the return was created for. - * x-expandable: "order" - * nullable: true - * $ref: "#/components/schemas/Order" - * shipping_method: - * description: The details of the Shipping Method that will be used to send the Return back. Can be null if the Customer will handle the return shipment themselves. - * x-expandable: "shipping_method" - * nullable: true - * $ref: "#/components/schemas/ShippingMethod" - * shipping_data: - * description: Data about the return shipment as provided by the Fulfilment Provider that handles the return shipment. - * nullable: true - * type: object - * example: {} - * location_id: - * description: The ID of the stock location the return will be added back. - * nullable: true - * type: string - * example: sloc_01G8TJSYT9M6AVS5N4EMNFS1EK - * refund_amount: - * description: The amount that should be refunded as a result of the return. - * type: integer - * example: 1000 - * no_notification: - * description: When set to true, no notification will be sent related to this return. - * nullable: true - * type: boolean - * example: false - * idempotency_key: - * description: Randomly generated key used to continue the completion of the return in case of failure. - * nullable: true - * type: string - * externalDocs: - * url: https://docs.medusajs.com/development/idempotency-key/overview.md - * description: Learn more how to use the idempotency key. - * received_at: - * description: The date with timezone at which the return was received. - * nullable: true - * type: string - * format: date-time - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/sales-channel-location.ts b/packages/medusa/src/models/sales-channel-location.ts deleted file mode 100644 index b63b9e3a93..0000000000 --- a/packages/medusa/src/models/sales-channel-location.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { - BeforeInsert, - Column, - Index, - JoinColumn, - ManyToOne, - Relation, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces" -import { generateEntityId } from "../utils" -import { FeatureFlagEntity } from "../utils/feature-flag-decorators" -import { SalesChannel } from "./sales-channel" - -@FeatureFlagEntity("sales_channels") -export class SalesChannelLocation extends SoftDeletableEntity { - @Index() - @Column({ type: "text" }) - sales_channel_id: string - - @Index() - @Column({ type: "text" }) - location_id: string - - @ManyToOne(() => SalesChannel, (sc) => sc.locations) - @JoinColumn({ name: "sales_channel_id" }) - sales_channel: Relation - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "scloc") - } -} - -/** - * @schema SalesChannelLocation - * title: "Sales Channel Stock Location" - * description: "This represents the association between a sales channel and a stock locations." - * type: object - * required: - * - created_at - * - deleted_at - * - id - * - location_id - * - sales_channel_id - * - updated_at - * properties: - * id: - * description: The Sales Channel Stock Location's ID - * type: string - * example: scloc_01G8X9A7ESKAJXG2H0E6F1MW7A - * sales_channel_id: - * description: "The ID of the Sales Channel" - * type: string - * example: sc_01G8X9A7ESKAJXG2H0E6F1MW7A - * location_id: - * description: "The ID of the Location Stock." - * type: string - * sales_channel: - * description: The details of the sales channel the location is associated with. - * x-expandable: "sales_channel" - * nullable: true - * $ref: "#/components/schemas/SalesChannel" - * created_at: - * description: "The date with timezone at which the resource was created." - * type: string - * format: date-time - * updated_at: - * description: "The date with timezone at which the resource was updated." - * type: string - * format: date-time - * deleted_at: - * description: "The date with timezone at which the resource was deleted." - * nullable: true - * type: string - * format: date-time - */ diff --git a/packages/medusa/src/models/sales-channel.ts b/packages/medusa/src/models/sales-channel.ts deleted file mode 100644 index 113b1fde3b..0000000000 --- a/packages/medusa/src/models/sales-channel.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { - BeforeInsert, - Column, - JoinTable, - ManyToMany, - OneToMany, - Relation, -} from "typeorm" - -import { MedusaV2Flag } from "@medusajs/utils" -import { SoftDeletableEntity } from "../interfaces" -import { DbAwareColumn, generateEntityId } from "../utils" -import { - FeatureFlagDecorators, - FeatureFlagEntity, -} from "../utils/feature-flag-decorators" -import { Cart } from "./cart" -import { Order } from "./order" -import { Product } from "./product" -import { PublishableApiKey } from "./publishable-api-key" -import { SalesChannelLocation } from "./sales-channel-location" - -@FeatureFlagEntity("sales_channels") -export class SalesChannel extends SoftDeletableEntity { - @Column() - name: string - - @Column({ type: "varchar", nullable: true }) - description: string | null - - @Column({ default: false }) - is_disabled: boolean - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record | null - - @ManyToMany(() => Product) - @JoinTable({ - name: "product_sales_channel", - inverseJoinColumn: { - name: "product_id", - referencedColumnName: "id", - }, - joinColumn: { - name: "sales_channel_id", - referencedColumnName: "id", - }, - }) - products: Relation[] - - @FeatureFlagDecorators(MedusaV2Flag.key, [ - ManyToMany(() => Cart), - JoinTable({ - name: "cart_sales_channel", - joinColumn: { - name: "sales_channel_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "cart_id", - referencedColumnName: "id", - }, - }), - ]) - carts: Relation[] - - @FeatureFlagDecorators(MedusaV2Flag.key, [ - ManyToMany(() => Order), - JoinTable({ - name: "order_sales_channel", - joinColumn: { - name: "sales_channel_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "order_id", - referencedColumnName: "id", - }, - }), - ]) - orders: Relation[] - - @ManyToMany(() => PublishableApiKey) - @JoinTable({ - name: "publishable_api_key_sales_channel", - inverseJoinColumn: { - name: "publishable_key_id", - referencedColumnName: "id", - }, - joinColumn: { - name: "sales_channel_id", - referencedColumnName: "id", - }, - }) - publishableKeys: Relation[] - - @OneToMany( - () => SalesChannelLocation, - (scLocation) => scLocation.sales_channel, - { - cascade: ["soft-remove", "remove"], - } - ) - locations: Relation[] - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "sc") - } -} - -/** - * @schema SalesChannel - * title: "Sales Channel" - * description: "A Sales Channel is a method a business offers its products for purchase for the customers. For example, a Webshop can be a sales channel, and a mobile app can be another." - * type: object - * required: - * - created_at - * - deleted_at - * - description - * - id - * - is_disabled - * - name - * - updated_at - * properties: - * id: - * description: The sales channel's ID - * type: string - * example: sc_01G8X9A7ESKAJXG2H0E6F1MW7A - * name: - * description: The name of the sales channel. - * type: string - * example: Market - * description: - * description: The description of the sales channel. - * nullable: true - * type: string - * example: Multi-vendor market - * is_disabled: - * description: Specify if the sales channel is enabled or disabled. - * type: boolean - * default: false - * locations: - * description: The details of the stock locations related to the sales channel. - * type: array - * x-expandable: "locations" - * items: - * $ref: "#/components/schemas/SalesChannelLocation" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - * carts: - * description: The associated carts. - * type: array - * nullable: true - * x-expandable: "carts" - * x-featureFlag: "medusa_v2" - * items: - * $ref: "#/components/schemas/Cart" - * orders: - * description: The associated orders. - * type: array - * nullable: true - * x-expandable: "orders" - * x-featureFlag: "medusa_v2" - * items: - * $ref: "#/components/schemas/Order" - * publishableKeys: - * description: The associated publishable API keys. - * type: array - * nullable: true - * x-expandable: "publishableKeys" - * items: - * $ref: "#/components/schemas/PublishableApiKey" - */ diff --git a/packages/medusa/src/models/shipping-method-tax-line.ts b/packages/medusa/src/models/shipping-method-tax-line.ts deleted file mode 100644 index a553a0bba6..0000000000 --- a/packages/medusa/src/models/shipping-method-tax-line.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - Relation, - Unique, -} from "typeorm" - -import { generateEntityId } from "../utils/generate-entity-id" -import { ShippingMethod } from "./shipping-method" -import { TaxLine } from "./tax-line" - -@Entity() -@Unique(["shipping_method_id", "code"]) -export class ShippingMethodTaxLine extends TaxLine { - @Index() - @Column() - shipping_method_id: string - - @ManyToOne(() => ShippingMethod, (sm) => sm.tax_lines) - @JoinColumn({ name: "shipping_method_id" }) - shipping_method: Relation - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "smtl") - } -} - -/** - * @schema ShippingMethodTaxLine - * title: "Shipping Method Tax Line" - * description: "A Shipping Method Tax Line represents the taxes applied on a shipping method in a cart." - * type: object - * required: - * - code - * - created_at - * - id - * - shipping_method_id - * - metadata - * - name - * - rate - * - updated_at - * properties: - * id: - * description: The line item tax line's ID - * type: string - * example: smtl_01G1G5V2DRX1SK6NQQ8VVX4HQ8 - * code: - * description: A code to identify the tax type by - * nullable: true - * type: string - * example: tax01 - * name: - * description: A human friendly name for the tax - * type: string - * example: Tax Example - * rate: - * description: "The numeric rate to charge tax by" - * type: number - * example: 10 - * shipping_method_id: - * description: The ID of the line item - * type: string - * example: sm_01F0YET7DR2E7CYVSDHM593QG2 - * shipping_method: - * description: The details of the associated shipping method. - * x-expandable: "shipping_method" - * nullable: true - * $ref: "#/components/schemas/ShippingMethod" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/shipping-method.ts b/packages/medusa/src/models/shipping-method.ts deleted file mode 100644 index 18efd15422..0000000000 --- a/packages/medusa/src/models/shipping-method.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { - BeforeInsert, - Check, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - OneToMany, - OneToOne, - PrimaryColumn, - Relation, -} from "typeorm" - -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { DbAwareColumn } from "../utils/db-aware-column" -import { FeatureFlagColumn } from "../utils/feature-flag-decorators" -import { generateEntityId } from "../utils/generate-entity-id" -import { Cart } from "./cart" -import { ClaimOrder } from "./claim-order" -import { Order } from "./order" -import { Return } from "./return" -import { ShippingMethodTaxLine } from "./shipping-method-tax-line" -import { ShippingOption } from "./shipping-option" -import { Swap } from "./swap" - -@Check( - `"claim_order_id" IS NOT NULL OR "order_id" IS NOT NULL OR "cart_id" IS NOT NULL OR "swap_id" IS NOT NULL OR "return_id" IS NOT NULL` -) -@Check(`"price" >= 0`) -@Entity() -export class ShippingMethod { - @PrimaryColumn() - id: string - - @Index() - @Column() - shipping_option_id: string - - @Index() - @Column({ nullable: true }) - order_id: string - - @ManyToOne(() => Order) - @JoinColumn({ name: "order_id" }) - order: Relation - - @Index() - @Column({ nullable: true }) - claim_order_id: string | null - - @ManyToOne(() => ClaimOrder) - @JoinColumn({ name: "claim_order_id" }) - claim_order: Relation - - @Index() - @Column({ nullable: true }) - cart_id: string - - @ManyToOne(() => Cart, (cart) => cart.shipping_methods) - @JoinColumn({ name: "cart_id" }) - cart: Relation - - @Index() - @Column({ nullable: true }) - swap_id: string - - @ManyToOne(() => Swap) - @JoinColumn({ name: "swap_id" }) - swap: Relation - - @Index() - @Column({ nullable: true }) - return_id: string - - @OneToOne(() => Return, (ret) => ret.shipping_method) - @JoinColumn({ name: "return_id" }) - return_order: Relation - - @ManyToOne(() => ShippingOption) - @JoinColumn({ name: "shipping_option_id" }) - shipping_option: Relation - - @OneToMany(() => ShippingMethodTaxLine, (tl) => tl.shipping_method, { - cascade: ["insert"], - }) - tax_lines: Relation[] - - @Column({ type: "int" }) - price: number - - @DbAwareColumn({ type: "jsonb" }) - data: Record - - @FeatureFlagColumn(TaxInclusivePricingFeatureFlag.key, { default: false }) - includes_tax: boolean - - subtotal?: number - total?: number - tax_total?: number - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "sm") - } -} - -/** - * @schema ShippingMethod - * title: "Shipping Method" - * description: "A Shipping Method represents a way in which an Order or Return can be shipped. Shipping Methods are created from a Shipping Option, but may contain additional details that can be necessary for the Fulfillment Provider to handle the shipment. If the shipping method is created for a return, it may be associated with a claim or a swap that the return is part of." - * type: object - * required: - * - cart_id - * - claim_order_id - * - data - * - id - * - order_id - * - price - * - return_id - * - shipping_option_id - * - swap_id - * properties: - * id: - * description: The shipping method's ID - * type: string - * example: sm_01F0YET7DR2E7CYVSDHM593QG2 - * shipping_option_id: - * description: The ID of the Shipping Option that the Shipping Method is built from. - * type: string - * example: so_01G1G5V27GYX4QXNARRQCW1N8T - * order_id: - * description: The ID of the order that the shipping method is used in. - * nullable: true - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * order: - * description: The details of the order that the shipping method is used in. - * x-expandable: "order" - * nullable: true - * $ref: "#/components/schemas/Order" - * claim_order_id: - * description: The ID of the claim that the shipping method is used in. - * nullable: true - * type: string - * example: null - * claim_order: - * description: The details of the claim that the shipping method is used in. - * x-expandable: "claim_order" - * nullable: true - * $ref: "#/components/schemas/ClaimOrder" - * cart_id: - * description: The ID of the cart that the shipping method is used in. - * nullable: true - * type: string - * example: cart_01G8ZH853Y6TFXWPG5EYE81X63 - * cart: - * description: The details of the cart that the shipping method is used in. - * x-expandable: "cart" - * nullable: true - * $ref: "#/components/schemas/Cart" - * swap_id: - * description: The ID of the swap that the shipping method is used in. - * nullable: true - * type: string - * example: null - * swap: - * description: The details of the swap that the shipping method is used in. - * x-expandable: "swap" - * nullable: true - * $ref: "#/components/schemas/Swap" - * return_id: - * description: The ID of the return that the shipping method is used in. - * nullable: true - * type: string - * example: null - * return_order: - * description: The details of the return that the shipping method is used in. - * x-expandable: "return_order" - * nullable: true - * $ref: "#/components/schemas/Return" - * shipping_option: - * description: The details of the shipping option the method was created from. - * x-expandable: "shipping_option" - * nullable: true - * $ref: "#/components/schemas/ShippingOption" - * tax_lines: - * description: The details of the tax lines applied on the shipping method. - * type: array - * x-expandable: "tax_lines" - * items: - * $ref: "#/components/schemas/ShippingMethodTaxLine" - * price: - * description: The amount to charge for the Shipping Method. The currency of the price is defined by the Region that the Order that the Shipping Method belongs to is a part of. - * type: integer - * example: 200 - * data: - * description: Additional data that the Fulfillment Provider needs to fulfill the shipment. This is used in combination with the Shipping Options data, and may contain information such as a drop point id. - * type: object - * example: {} - * includes_tax: - * description: "Whether the shipping method price include tax" - * type: boolean - * x-featureFlag: "tax_inclusive_pricing" - * default: false - * subtotal: - * description: The subtotal of the shipping - * type: integer - * example: 8000 - * total: - * description: The total amount of the shipping - * type: integer - * example: 8200 - * tax_total: - * description: The total of tax - * type: integer - * example: 0 - */ diff --git a/packages/medusa/src/models/shipping-option-requirement.ts b/packages/medusa/src/models/shipping-option-requirement.ts deleted file mode 100644 index b4603f414b..0000000000 --- a/packages/medusa/src/models/shipping-option-requirement.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { - BeforeInsert, - Column, - DeleteDateColumn, - Entity, - Index, - JoinColumn, - ManyToOne, - PrimaryColumn, - Relation, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { generateEntityId } from "../utils/generate-entity-id" -import { ShippingOption } from "./shipping-option" - -/** - * @enum - * - * The type of shipping option requirement. - */ -export enum RequirementType { - /** - * The shipping option can only be applied if the subtotal is greater than the requirement's amount. - */ - MIN_SUBTOTAL = "min_subtotal", - /** - * The shipping option can only be applied if the subtotal is less than the requirement's amont. - */ - MAX_SUBTOTAL = "max_subtotal", -} - -@Entity() -export class ShippingOptionRequirement { - @PrimaryColumn() - id: string - - @Index() - @Column() - shipping_option_id: string - - @ManyToOne(() => ShippingOption) - @JoinColumn({ name: "shipping_option_id" }) - shipping_option: Relation - - @DbAwareColumn({ type: "enum", enum: RequirementType }) - type: RequirementType - - @Column({ type: "int" }) - amount: number - - @DeleteDateColumn({ type: resolveDbType("timestamptz") }) - deleted_at: Date - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "sor") - } -} - -/** - * @schema ShippingOptionRequirement - * title: "Shipping Option Requirement" - * description: "A shipping option requirement defines conditions that a Cart must satisfy for the Shipping Option to be available for usage in the Cart." - * type: object - * required: - * - amount - * - deleted_at - * - id - * - shipping_option_id - * - type - * properties: - * id: - * description: The shipping option requirement's ID - * type: string - * example: sor_01G1G5V29AB4CTNDRFSRWSRKWD - * shipping_option_id: - * description: The ID of the shipping option that the requirements belong to. - * type: string - * example: so_01G1G5V27GYX4QXNARRQCW1N8T - * shipping_option: - * description: The details of the shipping option that the requirements belong to. - * x-expandable: "shipping_option" - * nullable: true - * $ref: "#/components/schemas/ShippingOption" - * type: - * description: The type of the requirement, this defines how the value will be compared to the Cart's total. `min_subtotal` requirements define the minimum subtotal that is needed for the Shipping Option to be available, while the `max_subtotal` defines the maximum subtotal that the Cart can have for the Shipping Option to be available. - * type: string - * enum: - * - min_subtotal - * - max_subtotal - * example: min_subtotal - * amount: - * description: The amount to compare the Cart subtotal to. - * type: integer - * example: 100 - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - */ diff --git a/packages/medusa/src/models/shipping-option.ts b/packages/medusa/src/models/shipping-option.ts deleted file mode 100644 index 15232cc6bb..0000000000 --- a/packages/medusa/src/models/shipping-option.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { - BeforeInsert, - Check, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - OneToMany, - Relation, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { DbAwareColumn } from "../utils/db-aware-column" -import { FeatureFlagColumn } from "../utils/feature-flag-decorators" -import { generateEntityId } from "../utils/generate-entity-id" -import { FulfillmentProvider } from "./fulfillment-provider" -import { Region } from "./region" -import { ShippingOptionRequirement } from "./shipping-option-requirement" -import { ShippingProfile } from "./shipping-profile" - -/** - * @enum - * - * The type of the shipping option price. - */ -export enum ShippingOptionPriceType { - /** - * The shipping option's price is a flat rate. - */ - FLAT_RATE = "flat_rate", - /** - * The shipping option's price is calculated. In this case, the `amount` field is typically `null`. - */ - CALCULATED = "calculated", -} - -@Check(`"amount" >= 0`) -@Entity() -export class ShippingOption extends SoftDeletableEntity { - @Column() - name: string - - @Index() - @Column() - region_id: string - - @ManyToOne(() => Region) - @JoinColumn({ name: "region_id" }) - region: Relation - - @Index() - @Column() - profile_id: string - - @ManyToOne(() => ShippingProfile) - @JoinColumn({ name: "profile_id" }) - profile: Relation - - @Index() - @Column() - provider_id: string - - @ManyToOne(() => FulfillmentProvider) - @JoinColumn({ name: "provider_id" }) - provider: Relation - - @DbAwareColumn({ type: "enum", enum: ShippingOptionPriceType }) - price_type: ShippingOptionPriceType - - @Column({ type: "int", nullable: true }) - amount: number | null - - @Column({ default: false }) - is_return: boolean - - @Column({ default: false }) - admin_only: boolean - - @OneToMany(() => ShippingOptionRequirement, (req) => req.shipping_option, { - cascade: ["insert"], - }) - requirements: Relation[] - - @DbAwareColumn({ type: "jsonb" }) - data: Record - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - @FeatureFlagColumn(TaxInclusivePricingFeatureFlag.key, { default: false }) - includes_tax: boolean - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "so") - } -} - -/** - * @schema ShippingOption - * title: "Shipping Option" - * description: "A Shipping Option represents a way in which an Order or Return can be shipped. Shipping Options have an associated Fulfillment Provider that will be used when the fulfillment of an Order is initiated. Shipping Options themselves cannot be added to Carts, but serve as a template for Shipping Methods. This distinction makes it possible to customize individual Shipping Methods with additional information." - * type: object - * required: - * - admin_only - * - amount - * - created_at - * - data - * - deleted_at - * - id - * - is_return - * - metadata - * - name - * - price_type - * - profile_id - * - provider_id - * - region_id - * - updated_at - * properties: - * id: - * description: The shipping option's ID - * type: string - * example: so_01G1G5V27GYX4QXNARRQCW1N8T - * name: - * description: The name given to the Shipping Option - this may be displayed to the Customer. - * type: string - * example: PostFake Standard - * region_id: - * description: The ID of the region this shipping option can be used in. - * type: string - * example: reg_01G1G5V26T9H8Y0M4JNE3YGA4G - * region: - * description: The details of the region this shipping option can be used in. - * x-expandable: "region" - * nullable: true - * $ref: "#/components/schemas/Region" - * profile_id: - * description: The ID of the Shipping Profile that the shipping option belongs to. - * type: string - * example: sp_01G1G5V239ENSZ5MV4JAR737BM - * profile: - * description: The details of the shipping profile that the shipping option belongs to. - * x-expandable: "profile" - * nullable: true - * $ref: "#/components/schemas/ShippingProfile" - * provider_id: - * description: The ID of the fulfillment provider that will be used to later to process the shipping method created from this shipping option and its fulfillments. - * type: string - * example: manual - * provider: - * description: The details of the fulfillment provider that will be used to later to process the shipping method created from this shipping option and its fulfillments. - * x-expandable: "provider" - * nullable: true - * $ref: "#/components/schemas/FulfillmentProvider" - * price_type: - * description: The type of pricing calculation that is used when creatin Shipping Methods from the Shipping Option. Can be `flat_rate` for fixed prices or `calculated` if the Fulfillment Provider can provide price calulations. - * type: string - * enum: - * - flat_rate - * - calculated - * example: flat_rate - * amount: - * description: The amount to charge for shipping when the Shipping Option price type is `flat_rate`. - * nullable: true - * type: integer - * example: 200 - * is_return: - * description: Flag to indicate if the Shipping Option can be used for Return shipments. - * type: boolean - * default: false - * admin_only: - * description: Flag to indicate if the Shipping Option usage is restricted to admin users. - * type: boolean - * default: false - * requirements: - * description: The details of the requirements that must be satisfied for the Shipping Option to be available for usage in a Cart. - * type: array - * x-expandable: "requirements" - * items: - * $ref: "#/components/schemas/ShippingOptionRequirement" - * data: - * description: The data needed for the Fulfillment Provider to identify the Shipping Option. - * type: object - * example: {} - * includes_tax: - * description: "Whether the shipping option price include tax" - * type: boolean - * x-featureFlag: "tax_inclusive_pricing" - * default: false - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/shipping-profile.ts b/packages/medusa/src/models/shipping-profile.ts deleted file mode 100644 index f4e20f9361..0000000000 --- a/packages/medusa/src/models/shipping-profile.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - JoinTable, - ManyToMany, - OneToMany, - Relation, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces" -import { DbAwareColumn, generateEntityId } from "../utils" -import { Product } from "./product" -import { ShippingOption } from "./shipping-option" - -/** - * @enum - * - * The shipping profile's type. - */ -export enum ShippingProfileType { - /** - * The default profile used to ship item. - */ - DEFAULT = "default", - /** - * The profile used to ship gift cards. - */ - GIFT_CARD = "gift_card", - /** - * The profile used to ship custom items. - */ - CUSTOM = "custom", -} - -@Entity() -export class ShippingProfile extends SoftDeletableEntity { - @Column() - name: string - - @DbAwareColumn({ type: "enum", enum: ShippingProfileType }) - type: ShippingProfileType - - @ManyToMany(() => Product) - @JoinTable({ - name: "product_shipping_profile", - joinColumn: { - name: "profile_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "product_id", - referencedColumnName: "id", - }, - }) - products: Relation[] - - @OneToMany(() => ShippingOption, (so) => so.profile) - shipping_options: Relation[] - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "sp") - } -} - -/** - * @schema ShippingProfile - * title: "Shipping Profile" - * description: "A Shipping Profile has a set of defined Shipping Options that can be used to fulfill a given set of Products. For example, gift cards are shipped differently than physical products, - * so a shipping profile with the type `gift_card` groups together the shipping options that can only be used for gift cards." - * type: object - * required: - * - created_at - * - deleted_at - * - id - * - metadata - * - name - * - type - * - updated_at - * properties: - * id: - * description: The shipping profile's ID - * type: string - * example: sp_01G1G5V239ENSZ5MV4JAR737BM - * name: - * description: The name given to the Shipping profile - this may be displayed to the Customer. - * type: string - * example: Default Shipping Profile - * type: - * description: The type of the Shipping Profile, may be `default`, `gift_card` or `custom`. - * type: string - * enum: - * - default - * - gift_card - * - custom - * example: default - * products: - * description: The details of the products that the Shipping Profile defines Shipping Options for. Available if the relation `products` is expanded. - * type: array - * x-expandable: "products" - * items: - * $ref: "#/components/schemas/Product" - * shipping_options: - * description: The details of the shipping options that can be used to create shipping methods for the Products in the Shipping Profile. - * type: array - * x-expandable: "shipping_options" - * items: - * $ref: "#/components/schemas/ShippingOption" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/shipping-tax-rate.ts b/packages/medusa/src/models/shipping-tax-rate.ts deleted file mode 100644 index 7601452aa1..0000000000 --- a/packages/medusa/src/models/shipping-tax-rate.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { - CreateDateColumn, - Entity, - JoinColumn, - ManyToOne, - PrimaryColumn, - UpdateDateColumn, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { ShippingOption } from "./shipping-option" -import { TaxRate } from "./tax-rate" - -@Entity() -export class ShippingTaxRate { - @PrimaryColumn() - shipping_option_id: string - - @PrimaryColumn() - rate_id: string - - @ManyToOne(() => ShippingOption, { onDelete: "CASCADE" }) - @JoinColumn({ name: "shipping_option_id" }) - shipping_option?: ShippingOption - - @ManyToOne(() => TaxRate, { onDelete: "CASCADE" }) - @JoinColumn({ name: "rate_id" }) - tax_rate?: TaxRate - - @CreateDateColumn({ type: resolveDbType("timestamptz") }) - created_at: Date - - @UpdateDateColumn({ type: resolveDbType("timestamptz") }) - updated_at: Date - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record -} - -/** - * @schema ShippingTaxRate - * title: "Shipping Tax Rate" - * description: "This represents the tax rates applied on a shipping option." - * type: object - * required: - * - created_at - * - metadata - * - rate_id - * - shipping_option_id - * - updated_at - * properties: - * shipping_option_id: - * description: The ID of the shipping option. - * type: string - * example: so_01G1G5V27GYX4QXNARRQCW1N8T - * shipping_option: - * description: The details of the shipping option. - * x-expandable: "shipping_option" - * nullable: true - * $ref: "#/components/schemas/ShippingOption" - * rate_id: - * description: The ID of the associated tax rate. - * type: string - * example: txr_01G8XDBAWKBHHJRKH0AV02KXBR - * tax_rate: - * description: The details of the associated tax rate. - * x-expandable: "tax_rate" - * nullable: true - * $ref: "#/components/schemas/TaxRate" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/store.ts b/packages/medusa/src/models/store.ts deleted file mode 100644 index dd92e72e28..0000000000 --- a/packages/medusa/src/models/store.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, - OneToOne, -} from "typeorm" -import { - FeatureFlagColumn, - FeatureFlagDecorators, -} from "../utils/feature-flag-decorators" - -import { BaseEntity } from "../interfaces/models/base-entity" -import { Currency } from "./currency" -import { DbAwareColumn } from "../utils/db-aware-column" -import { SalesChannel } from "./sales-channel" -import { generateEntityId } from "../utils/generate-entity-id" - -@Entity() -export class Store extends BaseEntity { - @Column({ default: "Medusa Store" }) - name: string - - @Column({ default: "usd" }) - default_currency_code: string - - @ManyToOne(() => Currency) - @JoinColumn({ name: "default_currency_code", referencedColumnName: "code" }) - default_currency: Currency - - @ManyToMany(() => Currency) - @JoinTable({ - name: "store_currencies", - joinColumn: { - name: "store_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "currency_code", - referencedColumnName: "code", - }, - }) - currencies: Currency[] - - @Column({ nullable: true, type: "text" }) - swap_link_template: string | null - - @Column({ nullable: true, type: "text" }) - payment_link_template: string | null - - @Column({ nullable: true, type: "text" }) - invite_link_template: string | null - - @Column({ nullable: true }) - default_location_id: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record | null - - @FeatureFlagColumn("sales_channels", { nullable: true, type: "text" }) - default_sales_channel_id: string | null - - @FeatureFlagDecorators("sales_channels", [ - OneToOne(() => SalesChannel), - JoinColumn({ name: "default_sales_channel_id" }), - ]) - default_sales_channel: SalesChannel - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "store") - } -} - -/** - * @schema Store - * title: "Store" - * description: "A store holds the main settings of the commerce shop. By default, only one store is created and used within the Medusa backend. It holds settings related to the name of the store, available currencies, and more." - * type: object - * required: - * - created_at - * - default_currency_code - * - default_location_id - * - id - * - invite_link_template - * - metadata - * - name - * - payment_link_template - * - swap_link_template - * - updated_at - * properties: - * id: - * description: The store's ID - * type: string - * example: store_01G1G5V21KADXNGH29BJMAJ4B4 - * name: - * description: The name of the Store - this may be displayed to the Customer. - * type: string - * example: Medusa Store - * default: Medusa Store - * default_currency_code: - * description: The three character currency code that is the default of the store. - * type: string - * example: usd - * externalDocs: - * url: https://en.wikipedia.org/wiki/ISO_4217#Active_codes - * description: See a list of codes. - * default_currency: - * description: The details of the store's default currency. - * x-expandable: "default_currency" - * default: "usd" - * nullable: true - * $ref: "#/components/schemas/Currency" - * currencies: - * description: The details of the enabled currencies in the store. - * type: array - * x-expandable: "currencies" - * items: - * $ref: "#/components/schemas/Currency" - * swap_link_template: - * description: A template to generate Swap links from. Use {{cart_id}} to include the Swap's `cart_id` in the link. - * nullable: true - * type: string - * example: null - * payment_link_template: - * description: A template to generate Payment links from. Use {{cart_id}} to include the payment's `cart_id` in the link. - * nullable: true - * type: string - * example: null - * invite_link_template: - * description: A template to generate Invite links from - * nullable: true - * type: string - * example: null - * default_location_id: - * description: The location ID the store is associated with. - * nullable: true - * type: string - * example: null - * default_sales_channel_id: - * description: The ID of the store's default sales channel. - * nullable: true - * type: string - * example: null - * default_sales_channel: - * description: The details of the store's default sales channel. - * x-expandable: "default_sales_channel" - * nullable: true - * $ref: "#/components/schemas/SalesChannel" - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/swap.ts b/packages/medusa/src/models/swap.ts deleted file mode 100644 index 15e6f15b5b..0000000000 --- a/packages/medusa/src/models/swap.ts +++ /dev/null @@ -1,341 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - Index, - JoinColumn, - ManyToOne, - OneToMany, - OneToOne, - Relation, -} from "typeorm" -import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" -import { Address } from "./address" -import { Cart } from "./cart" -import { Fulfillment } from "./fulfillment" -import { LineItem } from "./line-item" -import { Order } from "./order" -import { Payment } from "./payment" -import { Return } from "./return" -import { ShippingMethod } from "./shipping-method" - -/** - * @enum - * - * The swap's fulfillment status. - */ -export enum SwapFulfillmentStatus { - /** - * The swap's items aren't fulfilled. - */ - NOT_FULFILLED = "not_fulfilled", - /** - * The swap's items are fulfilled. - */ - FULFILLED = "fulfilled", - /** - * The swap's items are shipped. - */ - SHIPPED = "shipped", - /** - * Some of the swap's items are shipped. - */ - PARTIALLY_SHIPPED = "partially_shipped", - /** - * The swap's fulfillments are canceled. - */ - CANCELED = "canceled", - /** - * The swap's fulfillments require an action. - */ - REQUIRES_ACTION = "requires_action", -} - -/** - * @enum - * - * The swap's payment status. - */ -export enum SwapPaymentStatus { - /** - * The swap's additional payment isn't paid. - */ - NOT_PAID = "not_paid", - /** - * The swap is additional awaiting payment. - */ - AWAITING = "awaiting", - /** - * The swap's additional payment is captured. - */ - CAPTURED = "captured", - /** - * The swap's additional payment is confirmed. - */ - CONFIRMED = "confirmed", - /** - * The swap's additional payment is canceled. - */ - CANCELED = "canceled", - /** - * The negative difference amount between the returned item(s) and the new one(s) has been refuneded. - */ - DIFFERENCE_REFUNDED = "difference_refunded", - /** - * Some of the negative difference amount between the returned item(s) and the new one(s) has been refuneded. - */ - PARTIALLY_REFUNDED = "partially_refunded", - /** - * The amount in the associated order has been refunded. - */ - REFUNDED = "refunded", - /** - * The swap's payment requires an action. - */ - REQUIRES_ACTION = "requires_action", -} - -@Entity() -export class Swap extends SoftDeletableEntity { - @DbAwareColumn({ type: "enum", enum: SwapFulfillmentStatus }) - fulfillment_status: SwapFulfillmentStatus - - @DbAwareColumn({ type: "enum", enum: SwapPaymentStatus }) - payment_status: SwapPaymentStatus - - @Index() - @Column({ type: "string" }) - order_id: string - - @ManyToOne(() => Order, (o) => o.swaps) - @JoinColumn({ name: "order_id" }) - order: Relation - - @OneToMany(() => LineItem, (item) => item.swap, { cascade: ["insert"] }) - additional_items: Relation[] - - @OneToOne(() => Return, (ret) => ret.swap, { cascade: ["insert"] }) - return_order: Relation - - @OneToMany(() => Fulfillment, (fulfillment) => fulfillment.swap, { - cascade: ["insert"], - }) - fulfillments: Relation[] - - @OneToOne(() => Payment, (p) => p.swap, { cascade: ["insert"] }) - payment: Relation - - @Column({ type: "int", nullable: true }) - difference_due: number - - @Column({ nullable: true }) - shipping_address_id: string - - @ManyToOne(() => Address, { cascade: ["insert"] }) - @JoinColumn({ name: "shipping_address_id" }) - shipping_address: Relation
- - @OneToMany(() => ShippingMethod, (method) => method.swap, { - cascade: ["insert"], - }) - shipping_methods: Relation[] - - @Column({ nullable: true }) - cart_id: string - - @OneToOne(() => Cart) - @JoinColumn({ name: "cart_id" }) - cart: Relation - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - confirmed_at: Date - - @Column({ type: resolveDbType("timestamptz"), nullable: true }) - canceled_at: Date - - @Column({ type: "boolean", nullable: true }) - no_notification: boolean - - @Column({ type: "boolean", default: false }) - allow_backorder: boolean - - @Column({ nullable: true }) - idempotency_key: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "swap") - } -} - -/** - * @schema Swap - * title: "Swap" - * description: "A swap can be created when a Customer wishes to exchange Products that they have purchased with different Products. It consists of a Return of previously purchased Products and a Fulfillment of new Products. It also includes information on any additional payment or refund required based on the difference between the exchanged products." - * type: object - * required: - * - allow_backorder - * - canceled_at - * - cart_id - * - confirmed_at - * - created_at - * - deleted_at - * - difference_due - * - fulfillment_status - * - id - * - idempotency_key - * - metadata - * - no_notification - * - order_id - * - payment_status - * - shipping_address_id - * - updated_at - * properties: - * id: - * description: The swap's ID - * type: string - * example: swap_01F0YET86Y9G92D3YDR9Y6V676 - * fulfillment_status: - * description: The status of the Fulfillment of the Swap. - * type: string - * enum: - * - not_fulfilled - * - fulfilled - * - shipped - * - partially_shipped - * - canceled - * - requires_action - * example: not_fulfilled - * payment_status: - * description: The status of the Payment of the Swap. The payment may either refer to the refund of an amount or the authorization of a new amount. - * type: string - * enum: - * - not_paid - * - awaiting - * - captured - * - confirmed - * - canceled - * - difference_refunded - * - partially_refunded - * - refunded - * - requires_action - * example: not_paid - * order_id: - * description: The ID of the order that the swap belongs to. - * type: string - * example: order_01G8TJSYT9M6AVS5N4EMNFS1EK - * order: - * description: The details of the order that the swap belongs to. - * x-expandable: "order" - * nullable: true - * $ref: "#/components/schemas/Order" - * additional_items: - * description: The details of the new products to send to the customer, represented as line items. - * type: array - * x-expandable: "additional_items" - * items: - * $ref: "#/components/schemas/LineItem" - * return_order: - * description: The details of the return that belongs to the swap, which holds the details on the items being returned. - * x-expandable: "return_order" - * nullable: true - * $ref: "#/components/schemas/Return" - * fulfillments: - * description: The details of the fulfillments that are used to send the new items to the customer. - * x-expandable: "fulfillments" - * type: array - * items: - * $ref: "#/components/schemas/Fulfillment" - * payment: - * description: The details of the additional payment authorized by the customer when `difference_due` is positive. - * x-expandable: "payment" - * nullable: true - * $ref: "#/components/schemas/Payment" - * difference_due: - * description: The difference amount between the order’s original total and the new total imposed by the swap. If its value is negative, a refund must be issues to the customer. If it's positive, additional payment must be authorized by the customer. Otherwise, no payment processing is required. - * nullable: true - * type: integer - * example: 0 - * shipping_address_id: - * description: The Address to send the new Line Items to - in most cases this will be the same as the shipping address on the Order. - * nullable: true - * type: string - * example: addr_01G8ZH853YPY9B94857DY91YGW - * shipping_address: - * description: The details of the shipping address that the new items should be sent to. - * x-expandable: "shipping_address" - * nullable: true - * $ref: "#/components/schemas/Address" - * shipping_methods: - * description: The details of the shipping methods used to fulfill the additional items purchased. - * type: array - * x-expandable: "shipping_methods" - * items: - * $ref: "#/components/schemas/ShippingMethod" - * cart_id: - * description: The ID of the cart that the customer uses to complete the swap. - * nullable: true - * type: string - * example: cart_01G8ZH853Y6TFXWPG5EYE81X63 - * cart: - * description: The details of the cart that the customer uses to complete the swap. - * x-expandable: "cart" - * nullable: true - * $ref: "#/components/schemas/Cart" - * confirmed_at: - * description: The date with timezone at which the Swap was confirmed by the Customer. - * nullable: true - * type: string - * format: date-time - * canceled_at: - * description: The date with timezone at which the Swap was canceled. - * nullable: true - * type: string - * format: date-time - * no_notification: - * description: If set to true, no notification will be sent related to this swap - * nullable: true - * type: boolean - * example: false - * allow_backorder: - * description: If true, swaps can be completed with items out of stock - * type: boolean - * default: false - * idempotency_key: - * description: Randomly generated key used to continue the completion of the swap in case of failure. - * nullable: true - * type: string - * externalDocs: - * url: https://docs.medusajs.com/development/idempotency-key/overview.md - * description: Learn more how to use the idempotency key. - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/tax-line.ts b/packages/medusa/src/models/tax-line.ts deleted file mode 100644 index e873524a6a..0000000000 --- a/packages/medusa/src/models/tax-line.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { BaseEntity } from "../interfaces/models/base-entity" -import { Column } from "typeorm" -import { DbAwareColumn } from "../utils/db-aware-column" - -export class TaxLine extends BaseEntity { - @Column({ type: "real" }) - rate: number - - @Column() - name: string - - @Column({ type: "varchar", nullable: true }) - code: string | null - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record -} - -/** - * @schema TaxLine - * title: "Tax Line" - * description: "A tax line represents the taxes amount applied to a line item." - * type: object - * required: - * - code - * - created_at - * - id - * - metadata - * - name - * - rate - * - updated_at - * properties: - * id: - * description: The tax line's ID - * type: string - * example: tl_01G1G5V2DRX1SK6NQQ8VVX4HQ8 - * code: - * description: A code to identify the tax type by - * nullable: true - * type: string - * example: tax01 - * name: - * description: A human friendly name for the tax - * type: string - * example: Tax Example - * rate: - * description: The numeric rate to charge tax by - * type: number - * example: 10 - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/tax-provider.ts b/packages/medusa/src/models/tax-provider.ts deleted file mode 100644 index f29149bb7b..0000000000 --- a/packages/medusa/src/models/tax-provider.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Column, Entity, PrimaryColumn } from "typeorm" - -@Entity() -export class TaxProvider { - @PrimaryColumn() - id: string - - @Column({ default: true }) - is_installed: boolean -} - -/** - * @schema TaxProvider - * title: "Tax Provider" - * description: "A tax provider represents a tax service installed in the Medusa backend, either through a plugin or backend customizations. - * It holds the tax service's installation status." - * type: object - * required: - * - id - * - is_installed - * properties: - * id: - * description: The ID of the tax provider as given by the tax service. - * type: string - * example: manual - * is_installed: - * description: Whether the tax service is installed in the current version. If a tax service is no longer installed, the `is_installed` attribute is set to `false`. - * type: boolean - * default: true - */ diff --git a/packages/medusa/src/models/tax-rate.ts b/packages/medusa/src/models/tax-rate.ts deleted file mode 100644 index e80207331e..0000000000 --- a/packages/medusa/src/models/tax-rate.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, - Relation, -} from "typeorm" - -import { BaseEntity } from "../interfaces/models/base-entity" -import { DbAwareColumn } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" -import { Product } from "./product" -import { ProductType } from "./product-type" -import { Region } from "./region" -import { ShippingOption } from "./shipping-option" - -@Entity() -export class TaxRate extends BaseEntity { - @Column({ type: "real", nullable: true }) - rate: number | null - - @Column({ type: "varchar", nullable: true }) - code: string | null - - @Column() - name: string - - @Column() - region_id: string - - @ManyToOne(() => Region, (region) => region.tax_rates) - @JoinColumn({ name: "region_id" }) - region: Relation - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - @ManyToMany(() => Product) - @JoinTable({ - name: "product_tax_rate", - joinColumn: { - name: "rate_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "product_id", - referencedColumnName: "id", - }, - }) - products: Relation[] - - @ManyToMany(() => ProductType) - @JoinTable({ - name: "product_type_tax_rate", - joinColumn: { - name: "rate_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "product_type_id", - referencedColumnName: "id", - }, - }) - product_types: Relation[] - - @ManyToMany(() => ShippingOption) - @JoinTable({ - name: "shipping_tax_rate", - joinColumn: { - name: "rate_id", - referencedColumnName: "id", - }, - inverseJoinColumn: { - name: "shipping_option_id", - referencedColumnName: "id", - }, - }) - shipping_options: Relation[] - - // TODO: consider custom DTO instead - product_count?: number - product_type_count?: number - shipping_option_count?: number - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "txr") - } -} - -/** - * @schema TaxRate - * title: "Tax Rate" - * description: "A Tax Rate can be used to define a custom rate to charge on specified products, product types, and shipping options within a given region." - * type: object - * required: - * - code - * - created_at - * - id - * - metadata - * - name - * - rate - * - region_id - * - updated_at - * properties: - * id: - * description: The tax rate's ID - * type: string - * example: txr_01G8XDBAWKBHHJRKH0AV02KXBR - * rate: - * description: The numeric rate to charge - * nullable: true - * type: number - * example: 10 - * code: - * description: A code to identify the tax type by - * nullable: true - * type: string - * example: tax01 - * name: - * description: A human friendly name for the tax - * type: string - * example: Tax Example - * region_id: - * description: The ID of the region that the rate belongs to. - * type: string - * example: reg_01G1G5V26T9H8Y0M4JNE3YGA4G - * region: - * description: The details of the region that the rate belongs to. - * x-expandable: "region" - * nullable: true - * $ref: "#/components/schemas/Region" - * products: - * description: The details of the products that belong to this tax rate. - * type: array - * x-expandable: "products" - * items: - * $ref: "#/components/schemas/Product" - * product_types: - * description: The details of the product types that belong to this tax rate. - * type: array - * x-expandable: "product_types" - * items: - * $ref: "#/components/schemas/ProductType" - * shipping_options: - * description: The details of the shipping options that belong to this tax rate. - * type: array - * x-expandable: "shipping_options" - * items: - * $ref: "#/components/schemas/ShippingOption" - * product_count: - * description: The count of products - * type: integer - * example: 10 - * product_type_count: - * description: The count of product types - * type: integer - * example: 2 - * shipping_option_count: - * description: The count of shipping options - * type: integer - * example: 1 - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/tracking-link.ts b/packages/medusa/src/models/tracking-link.ts deleted file mode 100644 index e7e1a464bf..0000000000 --- a/packages/medusa/src/models/tracking-link.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { - BeforeInsert, - Column, - Entity, - JoinColumn, - ManyToOne, - Relation, -} from "typeorm" - -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { DbAwareColumn } from "../utils/db-aware-column" -import { generateEntityId } from "../utils/generate-entity-id" -import { Fulfillment } from "./fulfillment" - -@Entity() -export class TrackingLink extends SoftDeletableEntity { - @Column({ nullable: true }) - url: string - - @Column() - tracking_number: string - - @Column() - fulfillment_id: string - - @ManyToOne(() => Fulfillment, (ful) => ful.tracking_links) - @JoinColumn({ name: "fulfillment_id" }) - fulfillment: Relation - - @Column({ nullable: true }) - idempotency_key: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "tlink") - } -} - -/** - * @schema TrackingLink - * title: "Tracking Link" - * description: "A tracking link holds information about tracking numbers for a Fulfillment. Tracking Links can optionally contain a URL that can be visited to see the status of the shipment. Typically, the tracking link is provided from the third-party service integrated through the used fulfillment provider." - * type: object - * required: - * - created_at - * - deleted_at - * - fulfillment_id - * - id - * - idempotency_key - * - metadata - * - tracking_number - * - updated_at - * - url - * properties: - * id: - * description: The tracking link's ID - * type: string - * example: tlink_01G8ZH853Y6TFXWPG5EYE81X63 - * url: - * description: The URL at which the status of the shipment can be tracked. - * nullable: true - * type: string - * format: uri - * tracking_number: - * description: The tracking number given by the shipping carrier. - * type: string - * format: RH370168054CN - * fulfillment_id: - * description: The ID of the fulfillment that the tracking link belongs to. - * type: string - * example: ful_01G8ZRTMQCA76TXNAT81KPJZRF - * fulfillment: - * description: The details of the fulfillment that the tracking link belongs to. - * x-expandable: "fulfillment" - * nullable: true - * $ref: "#/components/schemas/Fulfillment" - * idempotency_key: - * description: Randomly generated key used to continue the completion of a process in case of failure. - * nullable: true - * type: string - * externalDocs: - * url: https://docs.medusajs.com/development/idempotency-key/overview.md - * description: Learn more how to use the idempotency key. - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/models/user.ts b/packages/medusa/src/models/user.ts deleted file mode 100644 index f78508d2c0..0000000000 --- a/packages/medusa/src/models/user.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { BeforeInsert, Column, Entity, Index } from "typeorm" - -import { DbAwareColumn } from "../utils/db-aware-column" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" - -/** - * @enum - * - * The user's role. These roles don't change the user's capabilities or provide access-control features. - */ -export enum UserRoles { - /** - * The user is an admin. - */ - ADMIN = "admin", - /** - * The user is a team member. - */ - MEMBER = "member", - /** - * The user is a developer. - */ - DEVELOPER = "developer", -} - -@Entity() -export class User extends SoftDeletableEntity { - @DbAwareColumn({ - type: "enum", - enum: UserRoles, - nullable: true, - default: UserRoles.MEMBER, - }) - role: UserRoles - - @Index({ unique: true, where: "deleted_at IS NULL" }) - @Column() - email: string - - @Column({ nullable: true }) - first_name: string - - @Column({ nullable: true }) - last_name: string - - /** - * @apiIgnore - */ - @Column({ nullable: true, select: false }) - password_hash: string - - @Column({ nullable: true }) - api_token: string - - @DbAwareColumn({ type: "jsonb", nullable: true }) - metadata: Record - - /** - * @apiIgnore - */ - @BeforeInsert() - private beforeInsert(): void { - this.id = generateEntityId(this.id, "usr") - } -} - -/** - * @schema User - * title: "User" - * description: "A User is an administrator who can manage store settings and data." - * type: object - * required: - * - api_token - * - created_at - * - deleted_at - * - email - * - first_name - * - id - * - last_name - * - metadata - * - role - * - updated_at - * properties: - * id: - * description: The user's ID - * type: string - * example: usr_01G1G5V26F5TB3GPAPNJ8X1S3V - * role: - * description: The user's role. These roles don't provide any different privileges. - * type: string - * enum: - * - admin - * - member - * - developer - * default: member - * email: - * description: The email of the User - * type: string - * format: email - * first_name: - * description: The first name of the User - * nullable: true - * type: string - * example: Levi - * last_name: - * description: The last name of the User - * nullable: true - * type: string - * example: Bogan - * api_token: - * description: An API token associated with the user. - * nullable: true - * type: string - * example: null - * created_at: - * description: The date with timezone at which the resource was created. - * type: string - * format: date-time - * updated_at: - * description: The date with timezone at which the resource was updated. - * type: string - * format: date-time - * deleted_at: - * description: The date with timezone at which the resource was deleted. - * nullable: true - * type: string - * format: date-time - * metadata: - * description: An optional key-value map with additional details - * nullable: true - * type: object - * example: {car: "white"} - * externalDocs: - * description: "Learn about the metadata attribute, and how to delete and update it." - * url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute" - */ diff --git a/packages/medusa/src/repositories/address.ts b/packages/medusa/src/repositories/address.ts deleted file mode 100644 index f9020ea03c..0000000000 --- a/packages/medusa/src/repositories/address.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Address } from "../models" -import { dataSource } from "../loaders/database" - -export const AddressRepository = dataSource.getRepository(Address) -export default AddressRepository diff --git a/packages/medusa/src/repositories/analytics-config.ts b/packages/medusa/src/repositories/analytics-config.ts deleted file mode 100644 index 00e55f1fa3..0000000000 --- a/packages/medusa/src/repositories/analytics-config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { AnalyticsConfig } from "../models/analytics-config" -import { dataSource } from "../loaders/database" - -export const AnalyticsConfigRepository = dataSource.getRepository(AnalyticsConfig) -export default AnalyticsConfigRepository diff --git a/packages/medusa/src/repositories/batch-job.ts b/packages/medusa/src/repositories/batch-job.ts deleted file mode 100644 index 1db24e986b..0000000000 --- a/packages/medusa/src/repositories/batch-job.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { BatchJob } from "../models" -import { dataSource } from "../loaders/database" - -export const BatchJobRepository = dataSource.getRepository(BatchJob) -export default BatchJobRepository diff --git a/packages/medusa/src/repositories/cart.ts b/packages/medusa/src/repositories/cart.ts deleted file mode 100644 index d60c3d0930..0000000000 --- a/packages/medusa/src/repositories/cart.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { objectToStringPath } from "@medusajs/utils" -import { FindManyOptions, FindOptionsRelations } from "typeorm" -import { dataSource } from "../loaders/database" -import { Cart } from "../models" -import { - getGroupedRelations, - mergeEntitiesWithRelations, - queryEntityWithIds, -} from "../utils/repository" - -export const CartRepository = dataSource.getRepository(Cart).extend({ - async findWithRelations( - relations: FindOptionsRelations = {}, - optionsWithoutRelations: Omit, "relations"> = {} - ): Promise { - const entities = await this.find(optionsWithoutRelations) - const entitiesIds = entities.map(({ id }) => id) - - const groupedRelations = getGroupedRelations(objectToStringPath(relations)) - - const entitiesIdsWithRelations = await queryEntityWithIds({ - repository: this, - entityIds: entitiesIds, - groupedRelations, - select: ["id"], - }) - - const entitiesAndRelations = entities.concat(entitiesIdsWithRelations) - return mergeEntitiesWithRelations(entitiesAndRelations) - }, - - async findOneWithRelations( - relations: FindOptionsRelations = {}, - optionsWithoutRelations: Omit, "relations"> = {} - ): Promise { - // Limit 1 - optionsWithoutRelations.take = 1 - - const result = await this.findWithRelations( - relations, - optionsWithoutRelations - ) - return result[0] - }, -}) -export default CartRepository diff --git a/packages/medusa/src/repositories/claim-image.ts b/packages/medusa/src/repositories/claim-image.ts deleted file mode 100644 index ee6a840043..0000000000 --- a/packages/medusa/src/repositories/claim-image.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ClaimImage } from "../models/claim-image" -import { dataSource } from "../loaders/database" - -export const ClaimImageRepository = dataSource.getRepository(ClaimImage) -export default ClaimImageRepository diff --git a/packages/medusa/src/repositories/claim-item.ts b/packages/medusa/src/repositories/claim-item.ts deleted file mode 100644 index b2231d6cef..0000000000 --- a/packages/medusa/src/repositories/claim-item.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ClaimItem } from "../models/claim-item" -import { dataSource } from "../loaders/database" - -export const ClaimItemRepository = dataSource.getRepository(ClaimItem) -export default ClaimItemRepository diff --git a/packages/medusa/src/repositories/claim-tag.ts b/packages/medusa/src/repositories/claim-tag.ts deleted file mode 100644 index ddf29503e7..0000000000 --- a/packages/medusa/src/repositories/claim-tag.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ClaimTag } from "../models/claim-tag" -import { dataSource } from "../loaders/database" - -export const ClaimTagRepository = dataSource.getRepository(ClaimTag) -export default ClaimTagRepository diff --git a/packages/medusa/src/repositories/claim.ts b/packages/medusa/src/repositories/claim.ts deleted file mode 100644 index 669912d905..0000000000 --- a/packages/medusa/src/repositories/claim.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ClaimOrder } from "../models/claim-order" -import { dataSource } from "../loaders/database" - -export const ClaimRepository = dataSource.getRepository(ClaimOrder) -export default ClaimRepository diff --git a/packages/medusa/src/repositories/country.ts b/packages/medusa/src/repositories/country.ts deleted file mode 100644 index 5072ea84c1..0000000000 --- a/packages/medusa/src/repositories/country.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Country } from "../models/country" -import { dataSource } from "../loaders/database" - -export const CountryRepository = dataSource.getRepository(Country) -export default CountryRepository diff --git a/packages/medusa/src/repositories/currency.ts b/packages/medusa/src/repositories/currency.ts deleted file mode 100644 index 744ad6d508..0000000000 --- a/packages/medusa/src/repositories/currency.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Currency } from "../models" -import { dataSource } from "../loaders/database" - -export const CurrencyRepository = dataSource.getRepository(Currency) -export default CurrencyRepository diff --git a/packages/medusa/src/repositories/custom-shipping-option.ts b/packages/medusa/src/repositories/custom-shipping-option.ts deleted file mode 100644 index 15fcca2cf1..0000000000 --- a/packages/medusa/src/repositories/custom-shipping-option.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { CustomShippingOption } from "../models" -import { dataSource } from "../loaders/database" - -export const CustomShippingOptionRepository = - dataSource.getRepository(CustomShippingOption) -export default CustomShippingOptionRepository diff --git a/packages/medusa/src/repositories/customer-group.ts b/packages/medusa/src/repositories/customer-group.ts deleted file mode 100644 index f269037eff..0000000000 --- a/packages/medusa/src/repositories/customer-group.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { DeleteResult, FindOperator, FindOptionsRelations, In } from "typeorm" -import { CustomerGroup } from "../models" -import { ExtendedFindConfig } from "../types/common" -import { - getGroupedRelations, - mergeEntitiesWithRelations, - queryEntityWithIds, - queryEntityWithoutRelations, -} from "../utils/repository" -import { objectToStringPath } from "@medusajs/utils" -import { dataSource } from "../loaders/database" -import { cloneDeep } from "lodash" - -export type DefaultWithoutRelations = Omit< - ExtendedFindConfig, - "relations" -> - -export type FindWithoutRelationsOptions = DefaultWithoutRelations & { - where: DefaultWithoutRelations["where"] & { - discount_condition_id?: string | FindOperator - } -} - -export const CustomerGroupRepository = dataSource - .getRepository(CustomerGroup) - .extend({ - async addCustomers( - groupId: string, - customerIds: string[] - ): Promise { - const customerGroup = await this.findOne({ - where: { - id: groupId, - }, - }) - - await this.createQueryBuilder() - .insert() - .into("customer_group_customers") - .values( - customerIds.map((id) => ({ - customer_id: id, - customer_group_id: groupId, - })) - ) - .orIgnore() - .execute() - - return customerGroup as CustomerGroup - }, - - async removeCustomers( - groupId: string, - customerIds: string[] - ): Promise { - return await this.createQueryBuilder() - .delete() - .from("customer_group_customers") - .where({ - customer_group_id: groupId, - customer_id: In(customerIds), - }) - .execute() - }, - - async findWithRelationsAndCount( - relations: FindOptionsRelations = {}, - idsOrOptionsWithoutRelations: string[] | FindWithoutRelationsOptions = { - where: {}, - } - ): Promise<[CustomerGroup[], number]> { - const withDeleted = Array.isArray(idsOrOptionsWithoutRelations) - ? false - : idsOrOptionsWithoutRelations.withDeleted ?? false - const isOptionsArray = Array.isArray(idsOrOptionsWithoutRelations) - const originalWhere = isOptionsArray - ? undefined - : cloneDeep(idsOrOptionsWithoutRelations.where) - const originalOrder: any = isOptionsArray - ? undefined - : { ...idsOrOptionsWithoutRelations.order } - const originalSelect = isOptionsArray - ? undefined - : (objectToStringPath(idsOrOptionsWithoutRelations.select, { - includeParentPropertyFields: false, - }) as (keyof CustomerGroup)[]) - const clonedOptions = isOptionsArray - ? idsOrOptionsWithoutRelations - : cloneDeep(idsOrOptionsWithoutRelations) - - let count: number - let entities: CustomerGroup[] - if (Array.isArray(idsOrOptionsWithoutRelations)) { - entities = await this.find({ - where: { id: In(idsOrOptionsWithoutRelations) }, - withDeleted, - }) - count = entities.length - } else { - const discountConditionId = ( - clonedOptions as FindWithoutRelationsOptions - )?.where?.discount_condition_id - delete (clonedOptions as FindWithoutRelationsOptions)?.where - ?.discount_condition_id - - const result = await queryEntityWithoutRelations({ - repository: this, - optionsWithoutRelations: clonedOptions as FindWithoutRelationsOptions, - shouldCount: true, - customJoinBuilders: [ - async (qb, alias) => { - if (discountConditionId) { - qb.innerJoin( - "discount_condition_customer_group", - "dc_cg", - `dc_cg.customer_group_id = ${alias}.id AND dc_cg.condition_id = :dcId`, - { dcId: discountConditionId } - ) - - return { - relation: "discount_condition", - preventOrderJoin: true, - } - } - - return - }, - ], - }) - entities = result[0] - count = result[1] - } - const entitiesIds = entities.map(({ id }) => id) - - if (entitiesIds.length === 0) { - // no need to continue - return [[], count] - } - - if (Object.keys(relations).length === 0) { - // Since we are finding by the ids that have been retrieved above and those ids are already - // applying skip/take. Remove those options to avoid getting no results - if (!Array.isArray(clonedOptions)) { - delete clonedOptions.skip - delete clonedOptions.take - } - - const toReturn = await this.find({ - ...(isOptionsArray - ? {} - : (clonedOptions as FindWithoutRelationsOptions)), - where: { - id: In(entitiesIds), - ...(Array.isArray(clonedOptions) ? {} : clonedOptions.where), - }, - }) - return [toReturn, toReturn.length] - } - - const legacyRelations = objectToStringPath(relations) - const groupedRelations = getGroupedRelations(legacyRelations) - - const entitiesIdsWithRelations = await queryEntityWithIds({ - repository: this, - entityIds: entitiesIds, - groupedRelations, - select: originalSelect, - withDeleted, - }) - - const entitiesAndRelations = entities.concat(entitiesIdsWithRelations) - const entitiesToReturn = - mergeEntitiesWithRelations(entitiesAndRelations) - - return [entitiesToReturn, count] - }, - }) - -export default CustomerGroupRepository diff --git a/packages/medusa/src/repositories/customer.ts b/packages/medusa/src/repositories/customer.ts deleted file mode 100644 index 1f6d411678..0000000000 --- a/packages/medusa/src/repositories/customer.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { FindOperator, FindOptionsWhere, ILike, In } from "typeorm" -import { Customer } from "../models" -import { dataSource } from "../loaders/database" -import { ExtendedFindConfig } from "../types/common" -import { promiseAll } from "@medusajs/utils" - -export const CustomerRepository = dataSource.getRepository(Customer).extend({ - async listAndCount( - query: ExtendedFindConfig & { - where: FindOptionsWhere }> - }, - q: string | undefined = undefined - ): Promise<[Customer[], number]> { - const query_ = { ...query } - - if (query_.where.groups) { - query_.relations = query_.relations ?? {} - query_.relations.groups = query_.relations.groups ?? true - - query.where.groups = { - id: In((query_.where.groups as FindOperator).value), - } - } - - if (q) { - query_.where = query_.where as FindOptionsWhere - delete query_.where.email - delete query_.where.first_name - delete query_.where.last_name - - query_.where = [ - { - ...query_.where, - email: ILike(`%${q}%`), - }, - { - ...query_.where, - first_name: ILike(`%${q}%`), - }, - { - ...query_.where, - last_name: ILike(`%${q}%`), - }, - ] - } - - return await promiseAll([this.find(query_), this.count(query_)]) - }, -}) -export default CustomerRepository diff --git a/packages/medusa/src/repositories/discount-condition.ts b/packages/medusa/src/repositories/discount-condition.ts deleted file mode 100644 index 3060db697c..0000000000 --- a/packages/medusa/src/repositories/discount-condition.ts +++ /dev/null @@ -1,383 +0,0 @@ -import { MedusaModule, Modules } from "@medusajs/modules-sdk" -import { MedusaV2Flag } from "@medusajs/utils" -import { DeleteResult, EntityTarget, In, Not } from "typeorm" -import { dataSource } from "../loaders/database" -import { featureFlagRouter } from "../loaders/feature-flags" -import { - Discount, - DiscountCondition, - DiscountConditionCustomerGroup, - DiscountConditionOperator, - DiscountConditionProduct, - DiscountConditionProductCollection, - DiscountConditionProductTag, - DiscountConditionProductType, - DiscountConditionType, -} from "../models" -import { isString } from "../utils" - -export enum DiscountConditionJoinTableForeignKey { - PRODUCT_ID = "product_id", - PRODUCT_TYPE_ID = "product_type_id", - PRODUCT_COLLECTION_ID = "product_collection_id", - PRODUCT_TAG_ID = "product_tag_id", - CUSTOMER_GROUP_ID = "customer_group_id", -} - -type DiscountConditionResourceType = EntityTarget< - | DiscountConditionProduct - | DiscountConditionProductType - | DiscountConditionProductCollection - | DiscountConditionProductTag - | DiscountConditionCustomerGroup -> - -export const DiscountConditionRepository = dataSource - .getRepository(DiscountCondition) - .extend({ - async findOneWithDiscount( - conditionId: string, - discountId: string - ): Promise<(DiscountCondition & { discount: Discount }) | undefined> { - return (await this.createQueryBuilder("condition") - .leftJoinAndMapOne( - "condition.discount", - Discount, - "discount", - `condition.discount_rule_id = discount.rule_id and discount.id = :discId and condition.id = :dcId`, - { discId: discountId, dcId: conditionId } - ) - .getOne()) as (DiscountCondition & { discount: Discount }) | undefined - }, - - getJoinTableResourceIdentifiers(type: string): { - joinTable: string - resourceKey: string - joinTableForeignKey: DiscountConditionJoinTableForeignKey - conditionTable: DiscountConditionResourceType - joinTableKey: string - relatedTable: string - } { - let conditionTable: DiscountConditionResourceType = - DiscountConditionProduct - - let joinTable = "product" - let joinTableForeignKey: DiscountConditionJoinTableForeignKey = - DiscountConditionJoinTableForeignKey.PRODUCT_ID - let joinTableKey = "id" - let relatedTable = "" - - // On the joined table (e.g. `product`), what key should be match on - // (e.g `type_id` for product types and `id` for products) - let resourceKey - - switch (type) { - case DiscountConditionType.PRODUCTS: { - resourceKey = "id" - joinTableForeignKey = DiscountConditionJoinTableForeignKey.PRODUCT_ID - joinTable = "product" - - conditionTable = DiscountConditionProduct - break - } - case DiscountConditionType.PRODUCT_TYPES: { - resourceKey = "type_id" - joinTableForeignKey = - DiscountConditionJoinTableForeignKey.PRODUCT_TYPE_ID - joinTable = "product" - relatedTable = "types" - - conditionTable = DiscountConditionProductType - break - } - case DiscountConditionType.PRODUCT_COLLECTIONS: { - resourceKey = "collection_id" - joinTableForeignKey = - DiscountConditionJoinTableForeignKey.PRODUCT_COLLECTION_ID - joinTable = "product" - relatedTable = "collections" - - conditionTable = DiscountConditionProductCollection - break - } - case DiscountConditionType.PRODUCT_TAGS: { - joinTableKey = "product_id" - resourceKey = "product_tag_id" - joinTableForeignKey = - DiscountConditionJoinTableForeignKey.PRODUCT_TAG_ID - joinTable = "product_tags" - relatedTable = "tags" - - conditionTable = DiscountConditionProductTag - break - } - case DiscountConditionType.CUSTOMER_GROUPS: { - joinTableKey = "customer_id" - resourceKey = "customer_group_id" - joinTable = "customer_group_customers" - joinTableForeignKey = - DiscountConditionJoinTableForeignKey.CUSTOMER_GROUP_ID - - conditionTable = DiscountConditionCustomerGroup - break - } - default: - break - } - - return { - joinTable, - joinTableKey, - resourceKey, - joinTableForeignKey, - conditionTable, - relatedTable, - } - }, - - async removeConditionResources( - id: string, - type: DiscountConditionType, - resourceIds: (string | { id: string })[] - ): Promise { - const { conditionTable, joinTableForeignKey } = - this.getJoinTableResourceIdentifiers(type) - - if (!conditionTable || !joinTableForeignKey) { - return Promise.resolve() - } - - const idsToDelete = resourceIds.map((rId): string => { - return isString(rId) ? rId : rId.id - }) - return await this.createQueryBuilder() - .delete() - .from(conditionTable) - .where({ condition_id: id, [joinTableForeignKey]: In(idsToDelete) }) - .execute() - }, - - async addConditionResources( - conditionId: string, - resourceIds: (string | { id: string })[], - type: DiscountConditionType, - overrideExisting = false - ): Promise< - ( - | DiscountConditionProduct - | DiscountConditionProductType - | DiscountConditionProductCollection - | DiscountConditionProductTag - | DiscountConditionCustomerGroup - )[] - > { - let toInsert: { condition_id: string; [x: string]: string }[] | [] = [] - - const { conditionTable, joinTableForeignKey } = - this.getJoinTableResourceIdentifiers(type) - - if (!conditionTable || !joinTableForeignKey) { - return Promise.resolve([]) - } - - const idsToInsert = resourceIds.map((rId): string => { - return isString(rId) ? rId : rId.id - }) - toInsert = idsToInsert.map((rId) => ({ - condition_id: conditionId, - [joinTableForeignKey]: rId, - })) - - const insertResult = await this.createQueryBuilder() - .insert() - .orIgnore(true) - .into(conditionTable) - .values(toInsert) - .execute() - - if (overrideExisting) { - await this.createQueryBuilder() - .delete() - .from(conditionTable) - .where({ - condition_id: conditionId, - [joinTableForeignKey]: Not(In(idsToInsert)), - }) - .execute() - } - - return await this.manager - .createQueryBuilder(conditionTable, "discon") - .select() - .where(insertResult.identifiers) - .getMany() - }, - - async queryConditionTable({ - type, - conditionId, - resourceId, - }): Promise { - const { - conditionTable, - joinTable, - joinTableForeignKey, - resourceKey, - joinTableKey, - relatedTable, - } = this.getJoinTableResourceIdentifiers(type) - - if ( - type !== DiscountConditionType.CUSTOMER_GROUPS && - featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key) - ) { - const module = MedusaModule.getModuleInstance(Modules.PRODUCT)[ - Modules.PRODUCT - ] - const prop = relatedTable - const resource = await module.retrieve(resourceId, { - select: [`${prop ? prop + "." : ""}id`], - relations: prop ? [prop] : [], - }) - if (!resource) { - return 0 - } - - const relatedResourceIds = prop - ? resource[prop].map((relatedResource) => relatedResource.id) - : [resource.id] - - if (!relatedResourceIds.length) { - return 0 - } - - return await this.manager - .createQueryBuilder(conditionTable, "dc") - .where( - `dc.condition_id = :conditionId AND dc.${joinTableForeignKey} IN (:...relatedResourceIds)`, - { - conditionId, - relatedResourceIds, - } - ) - .getCount() - } - - return await this.manager - .createQueryBuilder(conditionTable, "dc") - .innerJoin( - joinTable, - "resource", - `dc.${joinTableForeignKey} = resource.${resourceKey} and resource.${joinTableKey} = :resourceId `, - { - resourceId, - } - ) - .where(`dc.condition_id = :conditionId`, { - conditionId, - }) - .getCount() - }, - - async isValidForProduct( - discountRuleId: string, - productId: string - ): Promise { - const discountConditions = await this.createQueryBuilder("discon") - .select(["discon.id", "discon.type", "discon.operator"]) - .where("discon.discount_rule_id = :discountRuleId", { - discountRuleId, - }) - .getMany() - - // in case of no discount conditions, we assume that the discount - // is valid for all - if (!discountConditions.length) { - return true - } - - // retrieve all conditions for each type where condition type id is in jointable (products, product_types, product_collections, product_tags) - // "E.g. for a given product condition, give me all products affected by it" - // for each of these types, we check: - // if condition operation is `in` and the query for conditions defined for the given type is empty, the discount is invalid - // if condition operation is `not_in` and the query for conditions defined for the given type is not empty, the discount is invalid - for (const condition of discountConditions) { - if (condition.type === DiscountConditionType.CUSTOMER_GROUPS) { - continue - } - - const numConditions = await this.queryConditionTable({ - type: condition.type, - conditionId: condition.id, - resourceId: productId, - }) - - if ( - condition.operator === DiscountConditionOperator.IN && - numConditions === 0 - ) { - return false - } - - if ( - condition.operator === DiscountConditionOperator.NOT_IN && - numConditions > 0 - ) { - return false - } - } - - return true - }, - - async canApplyForCustomer( - discountRuleId: string, - customerId: string - ): Promise { - const discountConditions = await this.createQueryBuilder("discon") - .select(["discon.id", "discon.type", "discon.operator"]) - .where("discon.discount_rule_id = :discountRuleId", { - discountRuleId, - }) - .andWhere("discon.type = :type", { - type: DiscountConditionType.CUSTOMER_GROUPS, - }) - .getMany() - - // in case of no discount conditions, we assume that the discount - // is valid for all - if (!discountConditions.length) { - return true - } - - // retrieve conditions for customer groups - // for each customer group - // if condition operation is `in` and the query for customer group conditions is empty, the discount is invalid - // if condition operation is `not_in` and the query for customer group conditions is not empty, the discount is invalid - for (const condition of discountConditions) { - const numConditions = await this.queryConditionTable({ - type: "customer_groups", - conditionId: condition.id, - resourceId: customerId, - }) - - if ( - condition.operator === DiscountConditionOperator.IN && - numConditions === 0 - ) { - return false - } - - if ( - condition.operator === DiscountConditionOperator.NOT_IN && - numConditions > 0 - ) { - return false - } - } - - return true - }, - }) - -export default DiscountConditionRepository diff --git a/packages/medusa/src/repositories/discount-rule.ts b/packages/medusa/src/repositories/discount-rule.ts deleted file mode 100644 index c8d232cba7..0000000000 --- a/packages/medusa/src/repositories/discount-rule.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { DiscountRule } from "../models" -import { dataSource } from "../loaders/database" - -export const DiscountRuleRepository = dataSource.getRepository(DiscountRule) -export default DiscountRuleRepository diff --git a/packages/medusa/src/repositories/discount.ts b/packages/medusa/src/repositories/discount.ts deleted file mode 100644 index e703b53dfd..0000000000 --- a/packages/medusa/src/repositories/discount.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { dataSource } from "../loaders/database" -import { Discount } from "../models" - -export const DiscountRepository = dataSource.getRepository(Discount) -export default DiscountRepository diff --git a/packages/medusa/src/repositories/draft-order.ts b/packages/medusa/src/repositories/draft-order.ts deleted file mode 100644 index 5a46ff2ac1..0000000000 --- a/packages/medusa/src/repositories/draft-order.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { DraftOrder } from "../models" -import { dataSource } from "../loaders/database" - -export const DraftOrderRepository = dataSource.getRepository(DraftOrder) -export default DraftOrderRepository diff --git a/packages/medusa/src/repositories/fulfillment-provider.ts b/packages/medusa/src/repositories/fulfillment-provider.ts deleted file mode 100644 index 747ddecbea..0000000000 --- a/packages/medusa/src/repositories/fulfillment-provider.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { FulfillmentProvider } from "../models" -import { dataSource } from "../loaders/database" - -export const FulfillmentProviderRepository = - dataSource.getRepository(FulfillmentProvider) -export default FulfillmentProviderRepository diff --git a/packages/medusa/src/repositories/fulfillment.ts b/packages/medusa/src/repositories/fulfillment.ts deleted file mode 100644 index 174d4f50ad..0000000000 --- a/packages/medusa/src/repositories/fulfillment.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Fulfillment } from "../models" -import { dataSource } from "../loaders/database" - -export const FulfillmentRepository = dataSource.getRepository(Fulfillment) -export default FulfillmentRepository diff --git a/packages/medusa/src/repositories/gift-card-transaction.ts b/packages/medusa/src/repositories/gift-card-transaction.ts deleted file mode 100644 index b99e0aa3de..0000000000 --- a/packages/medusa/src/repositories/gift-card-transaction.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { GiftCardTransaction } from "../models" -import { dataSource } from "../loaders/database" - -export const GiftCardTransactionRepository = - dataSource.getRepository(GiftCardTransaction) -export default GiftCardTransactionRepository diff --git a/packages/medusa/src/repositories/gift-card.ts b/packages/medusa/src/repositories/gift-card.ts deleted file mode 100644 index 1f43e8a772..0000000000 --- a/packages/medusa/src/repositories/gift-card.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { FindOptionsWhere, ILike, Raw } from "typeorm" -import { GiftCard } from "../models" -import { ExtendedFindConfig } from "../types/common" -import { dataSource } from "../loaders/database" -import { promiseAll } from "@medusajs/utils" - -export const GiftCardRepository = dataSource.getRepository(GiftCard).extend({ - async listGiftCardsAndCount( - query: ExtendedFindConfig, - q?: string - ): Promise<[GiftCard[], number]> { - const query_ = { ...query } - query_.where = query_.where as FindOptionsWhere - - if (q) { - delete query_.where.id - - query_.relations = query_.relations ?? {} - query_.relations.order = query_.relations.order ?? true - - query_.where = query_.where as FindOptionsWhere[] - query_.where = [ - { - ...query_.where, - code: ILike(`%${q}%`), - }, - { - ...query_.where, - order: { - display_id: Raw((alias) => `CAST(${alias} as varchar) ILike :q`, { - q: `%${q}%`, - }), - }, - }, - ] - } - - return await promiseAll([this.find(query_), this.count(query_)]) - }, -}) -export default GiftCardRepository diff --git a/packages/medusa/src/repositories/image.ts b/packages/medusa/src/repositories/image.ts deleted file mode 100644 index 217b11470a..0000000000 --- a/packages/medusa/src/repositories/image.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" - -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 { - const queryBuilder = this.createQueryBuilder() - .insert() - .into(Image) - .values(data) - - if (!queryBuilder.connection.driver.isReturningSqlSupported("insert")) { - const rawImages = await queryBuilder.execute() - return rawImages.generatedMaps.map((d) => this.create(d)) as Image[] - } - - const rawImages = await queryBuilder.returning("*").execute() - return rawImages.generatedMaps.map((d) => this.create(d)) - }, - - async upsertImages(imageUrls: string[]) { - const existingImages = await this.find({ - where: { - url: In(imageUrls), - }, - }) - const existingImagesMap = new Map( - existingImages.map<[string, Image]>((img) => [img.url, img]) - ) - - const upsertedImgs: Image[] = [] - const imageToCreate: QueryDeepPartialEntity[] = [] - - imageUrls.forEach((url) => { - const aImg = existingImagesMap.get(url) - if (aImg) { - upsertedImgs.push(aImg) - } else { - const newImg = this.create({ url }) - imageToCreate.push(newImg as QueryDeepPartialEntity) - } - }) - - if (imageToCreate.length) { - const newImgs = await this.insertBulk(imageToCreate) - upsertedImgs.push(...newImgs) - } - - return upsertedImgs - }, -}) -export default ImageRepository diff --git a/packages/medusa/src/repositories/invite.ts b/packages/medusa/src/repositories/invite.ts deleted file mode 100644 index e34aa397b5..0000000000 --- a/packages/medusa/src/repositories/invite.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Invite } from "../models" -import { dataSource } from "../loaders/database" - -export const InviteRepository = dataSource.getRepository(Invite) -export default InviteRepository diff --git a/packages/medusa/src/repositories/line-item-adjustment.ts b/packages/medusa/src/repositories/line-item-adjustment.ts deleted file mode 100644 index e99b7216b0..0000000000 --- a/packages/medusa/src/repositories/line-item-adjustment.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { LineItemAdjustment } from "../models" -import { dataSource } from "../loaders/database" - -export const LineItemAdjustmentRepository = - dataSource.getRepository(LineItemAdjustment) -export default LineItemAdjustmentRepository diff --git a/packages/medusa/src/repositories/line-item-tax-line.ts b/packages/medusa/src/repositories/line-item-tax-line.ts deleted file mode 100644 index 503d417ace..0000000000 --- a/packages/medusa/src/repositories/line-item-tax-line.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { LineItemTaxLine } from "../models" -import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" -import { dataSource } from "../loaders/database" - -export const LineItemTaxLineRepository = dataSource - .getRepository(LineItemTaxLine) - .extend({ - async upsertLines(lines: LineItemTaxLine[]): Promise { - const insertResult = await this.createQueryBuilder() - .insert() - .values(lines as QueryDeepPartialEntity[]) - .orUpdate(["rate", "name", "updated_at"], ["item_id", "code"]) - .execute() - - return insertResult.identifiers as LineItemTaxLine[] - }, - - async deleteForCart(cartId: string): Promise { - const qb = this.createQueryBuilder("line") - .select(["line.id"]) - .innerJoin("line_item", "i", "i.id = line.item_id") - .innerJoin( - "cart", - "c", - "i.cart_id = :cartId AND c.completed_at is NULL", - { cartId } - ) - - const toDelete = await qb.getMany() - - await this.createQueryBuilder() - .delete() - .whereInIds(toDelete.map((d) => d.id)) - .execute() - }, - }) -export default LineItemTaxLineRepository diff --git a/packages/medusa/src/repositories/line-item.ts b/packages/medusa/src/repositories/line-item.ts deleted file mode 100644 index aa38e9587a..0000000000 --- a/packages/medusa/src/repositories/line-item.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { LineItem } from "../models/line-item" -import { ReturnItem } from "../models/return-item" -import { dataSource } from "../loaders/database" - -export const LineItemRepository = dataSource.getRepository(LineItem).extend({ - /** - * Finds line items that are to be returned as part of the Return represented - * by `returnId`. The function joins the associated ReturnItem and the - * LineItem's TaxLines. - * @param returnId - the id of the Return to get LineItems by - * @return the LineItems associated with the Return with its ReturnItem joined - * and mapped to `return_item`. - */ - async findByReturn( - returnId: string - ): Promise<(LineItem & { return_item: ReturnItem })[]> { - const qb = this.createQueryBuilder("li") - .leftJoinAndSelect(`li.tax_lines`, "tax_lines") - .leftJoinAndSelect(`li.adjustments`, "adjustments") - .leftJoinAndMapOne( - `li.return_item`, - ReturnItem, - `ri`, - `ri.item_id = li.id` - ) - .where(`ri.return_id = :returnId`, { returnId }) - - return (await qb.getMany()) as (LineItem & { return_item: ReturnItem })[] - }, -}) - -export default LineItemRepository diff --git a/packages/medusa/src/repositories/money-amount.ts b/packages/medusa/src/repositories/money-amount.ts deleted file mode 100644 index 1d157499b0..0000000000 --- a/packages/medusa/src/repositories/money-amount.ts +++ /dev/null @@ -1,594 +0,0 @@ -import { - Brackets, - In, - IsNull, - Not, - ObjectLiteral, - WhereExpressionBuilder, -} from "typeorm" -import { - MoneyAmount, - ProductVariant, - ProductVariantMoneyAmount, -} from "../models" -import { - PriceListPriceCreateInput, - PriceListPriceUpdateInput, -} from "../types/price-list" -import { ProductVariantPrice } from "../types/product-variant" -import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" -import { dataSource } from "../loaders/database" -import { groupBy } from "lodash" -import { isString } from "../utils" -import partition from "lodash/partition" -import { ulid } from "ulid" -import { promiseAll } from "@medusajs/utils" - -type Price = Partial< - Omit -> & { - amount: number -} - -export const MoneyAmountRepository = dataSource - .getRepository(MoneyAmount) - .extend({ - async insertBulk( - data: QueryDeepPartialEntity[] - ): Promise { - const queryBuilder = this.createQueryBuilder() - .insert() - .into(MoneyAmount) - .values(data) - - let rawMoneyAmounts - if (!queryBuilder.connection.driver.isReturningSqlSupported("insert")) { - rawMoneyAmounts = await queryBuilder.execute() - } else { - rawMoneyAmounts = await queryBuilder.returning("*").execute() - } - - const created = rawMoneyAmounts.generatedMaps.map((d) => - this.create(d) - ) as MoneyAmount[] - - const variantMoneyAmounts = this.manager.create( - ProductVariantMoneyAmount, - data - .filter( - ( - d - ): d is { - variant: QueryDeepPartialEntity - id: string - } => !!d.variant - ) - .map((d) => ({ - variant_id: d.variant.id, - money_amount_id: d.id, - })) - ) - - await this.manager.save(variantMoneyAmounts) - - return created - }, - - /** - * Will be removed in a future release. - * Use `deleteVariantPricesNotIn` instead. - * @deprecated - */ - async findVariantPricesNotIn( - variantId: string, - prices: Price[] - ): Promise { - const pricesNotInPricesPayload = await this.createQueryBuilder() - .leftJoinAndSelect( - "product_variant_money_amount", - "pvma", - "pvma.money_amount_id = ma.id" - ) - .where("pvma.variant_id = :variant_id", { - variant_id: variantId, - }) - .andWhere({ - price_list_id: IsNull(), - }) - .andWhere( - new Brackets((qb) => { - qb.where({ - currency_code: Not(In(prices.map((p) => p.currency_code))), - }).orWhere({ region_id: Not(In(prices.map((p) => p.region_id))) }) - }) - ) - .getMany() - return pricesNotInPricesPayload - }, - - async deleteVariantPricesNotIn( - variantIdOrData: - | string - | { variantId: string; prices: ProductVariantPrice[] }[], - prices?: Price[] - ): Promise { - const data = isString(variantIdOrData) - ? [ - { - variantId: variantIdOrData, - prices: prices!, - }, - ] - : variantIdOrData - - const maDeleteQueryBuilder = this.createQueryBuilder("ma") - const mavDeleteQueryBuilder = this.createQueryBuilder() - .delete() - .from("product_variant_money_amount") - - for (const data_ of data) { - const maIdsForVariant = await this.createQueryBuilder("ma") - .leftJoin( - "product_variant_money_amount", - "pvma", - "pvma.money_amount_id = ma.id" - ) - .addSelect("pvma.variant_id", "variant_id") - .addSelect("pvma.money_amount_id", "money_amount_id") - .where("pvma.variant_id = :variant_id", { - variant_id: data_.variantId, - }) - .getMany() - - const where = { - id: In(maIdsForVariant.map((ma) => ma.id)), - price_list_id: IsNull(), - } - - const orWhere: ObjectLiteral[] = [] - - for (const price of data_.prices) { - if (price.currency_code) { - orWhere.push( - { - currency_code: Not(price.currency_code), - }, - { - region_id: price.region_id - ? Not(price.region_id) - : Not(IsNull()), - currency_code: price.currency_code, - } - ) - } - - if (price.region_id) { - orWhere.push({ - region_id: Not(price.region_id), - }) - } - } - - maDeleteQueryBuilder.orWhere( - new Brackets((localQueryBuild) => { - localQueryBuild.where(where).andWhere(orWhere) - }) - ) - } - const deleteAmounts = await maDeleteQueryBuilder.getMany() - - if (!deleteAmounts.length) { - return - } - - await promiseAll([ - this.delete(deleteAmounts.map((mav) => mav.id)), - mavDeleteQueryBuilder - .where( - deleteAmounts.map((mav) => ({ - money_amount_id: mav.id, - })) - ) - .execute(), - ]) - }, - - async upsertVariantCurrencyPrice( - variantId: string, - price: Price - ): Promise { - let moneyAmount = await this.createQueryBuilder() - .leftJoinAndSelect( - "product_variant_money_amount", - "pvma", - "pvma.money_amount_id = ma.id" - ) - .where("pvma.variant_id = :variantId", { variantId }) - .andWhere("ma.currency_code = :currencyCode", { - currencyCode: price.currency_code, - }) - .andWhere("ma.region_id IS NULL") - .andWhere("ma.price_list_id IS NULL") - .getOne() - - const created = !moneyAmount - - if (!moneyAmount) { - moneyAmount = this.create({ - ...price, - currency_code: price.currency_code?.toLowerCase(), - variant: { id: variantId }, - }) - } else { - moneyAmount.amount = price.amount - } - - const createdAmount = await this.save(moneyAmount) - - if (created) { - await this.createProductVariantMoneyAmounts([ - { - variant_id: variantId, - money_amount_id: createdAmount.id, - }, - ]) - } - - return createdAmount - }, - - async addPriceListPrices( - priceListId: string, - prices: PriceListPriceCreateInput[], - overrideExisting = false - ): Promise { - const [toInsert, joinTableValues] = prices.reduce( - (acc, price) => { - const [prices, joinTableValues] = acc - const id = `ma_${ulid()}` - const variant = this.create({ - ...price, - id, - price_list_id: priceListId, - }) - const joinTableValue = this.manager.create( - ProductVariantMoneyAmount, - { - variant_id: price.variant_id!, - money_amount_id: id, - } - ) - - return [ - [...prices, variant], - [...joinTableValues, joinTableValue], - ] - }, - [[], []] as [MoneyAmount[], ProductVariantMoneyAmount[]] - ) - - const insertResult = await this.createQueryBuilder() - .insert() - .orIgnore(true) - .into(MoneyAmount) - .values(toInsert as QueryDeepPartialEntity[]) - .returning("*") - .execute() - - if (overrideExisting) { - const { raw } = await this.createQueryBuilder() - .delete() - .from(MoneyAmount) - .where({ - price_list_id: priceListId, - id: Not(In(insertResult.identifiers.map((ma) => ma.id))), - }) - .returning("id") - .execute() - - await this.createQueryBuilder() - .delete() - .from("product_variant_money_amount") - .where({ - money_amount_id: In(raw.map((deletedMa) => deletedMa.id)), - }) - .execute() - } - - await this.manager.save(joinTableValues) - - return await this.manager - .createQueryBuilder(MoneyAmount, "ma") - .select() - .where(insertResult.identifiers) - .getMany() - }, - - async deletePriceListPrices( - priceListId: string, - moneyAmountIds: string[] - ): Promise { - await this.createQueryBuilder() - .delete() - .from(MoneyAmount) - .where({ price_list_id: priceListId, id: In(moneyAmountIds) }) - .execute() - }, - - async findManyForVariantInPriceList( - variant_id: string, - price_list_id: string, - requiresPriceList = false - ): Promise<[MoneyAmount[], number]> { - const qb = this.createQueryBuilder("ma") - .leftJoinAndSelect("ma.price_list", "price_list") - .leftJoin( - "product_variant_money_amount", - "pvma", - "pvma.money_amount_id = ma.id" - ) - .where("pvma.variant_id = :variant_id", { variant_id }) - - const getAndWhere = (subQb): WhereExpressionBuilder => { - const andWhere = subQb.where("ma.price_list_id = :price_list_id", { - price_list_id, - }) - if (!requiresPriceList) { - andWhere.orWhere("ma.price_list_id IS NULL") - } - return andWhere - } - - qb.andWhere(new Brackets(getAndWhere)) - - return await qb.getManyAndCount() - }, - - /** - * @deprecated in favor of {@link findManyForVariantsInRegion} - * @param variant_id - * @param region_id - * @param currency_code - * @param customer_id - * @param include_discount_prices - * @param include_tax_inclusive_pricing - */ - async findManyForVariantInRegion( - variant_id: string, - region_id?: string, - currency_code?: string, - customer_id?: string, - include_discount_prices?: boolean, - include_tax_inclusive_pricing = false - ): Promise<[MoneyAmount[], number]> { - const result = await this.findManyForVariantsInRegion( - variant_id, - region_id, - currency_code, - customer_id, - include_discount_prices, - include_tax_inclusive_pricing - ) - - return [result[0][variant_id], result[1]] - }, - - async findCurrencyMoneyAmounts( - where: { variant_id: string; currency_code: string }[] - ) { - const qb = this.createQueryBuilder("ma") - .leftJoin( - "product_variant_money_amount", - "pvma", - "pvma.money_amount_id = ma.id" - ) - .addSelect("pvma.variant_id", "variant_id") - - where.forEach((variantCurrency, i) => - qb.orWhere( - `(pvma.variant_id = :variant_id_${i} AND ma.currency_code = :currency_code_${i} AND ma.region_id IS NULL AND ma.price_list_id IS NULL)`, - { - [`variant_id_${i}`]: variantCurrency.variant_id, - [`currency_code_${i}`]: variantCurrency.currency_code, - } - ) - ) - - const rawAndEntities = await qb.getRawAndEntities() - return rawAndEntities.entities.map((e, i) => { - return { ...e, variant_id: rawAndEntities.raw[i].variant_id } - }) - }, - - async findRegionMoneyAmounts( - where: { variant_id: string; region_id: string }[] - ) { - const qb = this.createQueryBuilder("ma") - .leftJoin( - "product_variant_money_amount", - "pvma", - "pvma.money_amount_id = ma.id" - ) - .addSelect("pvma.variant_id", "variant_id") - - where.forEach((w, i) => - qb.orWhere( - `(pvma.variant_id = :variant_id_${i} AND ma.region_id = :region_id_${i} AND ma.price_list_id IS NULL)`, - { - [`variant_id_${i}`]: w.variant_id, - [`region_id_${i}`]: w.region_id, - } - ) - ) - - const rawAndEntities = await qb.getRawAndEntities() - return rawAndEntities.entities.map((e, i) => { - return { ...e, variant_id: rawAndEntities.raw[i].variant_id } - }) - }, - - async findManyForVariantsInRegion( - variant_ids: string | string[], - region_id?: string, - currency_code?: string, - customer_id?: string, - include_discount_prices?: boolean, - include_tax_inclusive_pricing = false - ): Promise<[Record, number]> { - variant_ids = Array.isArray(variant_ids) ? variant_ids : [variant_ids] - - if (!variant_ids.length) { - return [{}, 0] - } - const date = new Date() - - const qb = this.createQueryBuilder("ma") - .leftJoinAndSelect("ma.price_list", "price_list") - .leftJoinAndSelect( - "product_variant_money_amount", - "pvma", - "pvma.money_amount_id = ma.id" - ) - .addSelect("pvma.variant_id", "variant_id") - .andWhere("pvma.variant_id IN (:...variantIds)", { - variantIds: variant_ids, - }) - .andWhere("(ma.price_list_id is null or price_list.status = 'active')") - .andWhere( - "(price_list.ends_at is null OR price_list.ends_at > :date)", - { - date: date.toUTCString(), - } - ) - .andWhere( - "(price_list.starts_at is null OR price_list.starts_at < :date)", - { - date: date.toUTCString(), - } - ) - - if (include_tax_inclusive_pricing) { - qb.leftJoin("ma.currency", "currency") - .leftJoin("ma.region", "region") - .addSelect(["currency.includes_tax", "region.includes_tax"]) - } - if (region_id || currency_code) { - qb.andWhere( - new Brackets((qb) => { - if (region_id && !currency_code) { - qb.where({ region_id: region_id }) - } - if (!region_id && currency_code) { - qb.where({ currency_code: currency_code }) - } - if (currency_code && region_id) { - qb.where({ region_id: region_id }).orWhere({ - currency_code: currency_code, - }) - } - }) - ) - } else if (!customer_id && !include_discount_prices) { - qb.andWhere("price_list.id IS null") - } - - if (customer_id) { - qb.leftJoin("price_list.customer_groups", "cgroup") - .leftJoin( - "customer_group_customers", - "cgc", - "cgc.customer_group_id = cgroup.id" - ) - .andWhere("(cgroup.id is null OR cgc.customer_id = :customer_id)", { - customer_id, - }) - } else { - qb.leftJoin("price_list.customer_groups", "cgroup").andWhere( - "cgroup.id is null" - ) - } - - const count = await qb.getCount() - const res = await qb.getRawAndEntities() - - const { entities, raw } = res - - const prices = entities.map((p, i) => { - p["variant_id"] = raw[i]["variant_id"] - return p - }) - - const groupedPrices = groupBy(prices, "variant_id") - - return [groupedPrices, count] - }, - - async updatePriceListPrices( - priceListId: string, - updates: PriceListPriceUpdateInput[] - ): Promise { - const [existingPrices, newPrices] = partition( - updates, - (update) => update.id - ) - - const [newPriceEntities, joinTableValues] = newPrices.reduce( - (acc, price) => { - const [prices, joinTableValues] = acc - const id = `ma_${ulid()}` - const variantPrice = this.create({ - ...price, - id, - price_list_id: priceListId, - }) - const joinTableValue = this.manager.create( - ProductVariantMoneyAmount, - { - variant_id: price.variant_id!, - money_amount_id: id, - } - ) - - prices.push(variantPrice) - joinTableValues.push(joinTableValue) - - return [prices, joinTableValues] - }, - [[], []] as [MoneyAmount[], ProductVariantMoneyAmount[]] - ) - - const [prices] = await promiseAll([ - this.save([...existingPrices, ...newPriceEntities]), - await this.manager.save(joinTableValues), - ]) - - return prices - }, - - async getPricesForVariantInRegion( - variantId: string, - regionId: string | undefined - ): Promise { - return this.createQueryBuilder() - .leftJoinAndSelect( - "product_variant_money_amount", - "pvma", - "pvma.money_amount_id = ma.id" - ) - .where("pvma.variant_id = :variantId", { variantId }) - .where("ma.region_id = :regionId", { regionId }) - .getMany() - }, - - async createProductVariantMoneyAmounts( - toCreate: { variant_id: string; money_amount_id: string }[] - ) { - return await this.createQueryBuilder() - .insert() - .into("product_variant_money_amount") - .values(toCreate) - .execute() - }, - }) - -export default MoneyAmountRepository diff --git a/packages/medusa/src/repositories/note.ts b/packages/medusa/src/repositories/note.ts deleted file mode 100644 index 3392992374..0000000000 --- a/packages/medusa/src/repositories/note.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Note } from "../models" -import { dataSource } from "../loaders/database" - -export const NoteRepository = dataSource.getRepository(Note) -export default NoteRepository diff --git a/packages/medusa/src/repositories/notification-provider.ts b/packages/medusa/src/repositories/notification-provider.ts deleted file mode 100644 index c948cc8502..0000000000 --- a/packages/medusa/src/repositories/notification-provider.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { NotificationProvider } from "../models/notification-provider" -import { dataSource } from "../loaders/database" - -export const NotificationProviderRepository = - dataSource.getRepository(NotificationProvider) -export default NotificationProviderRepository diff --git a/packages/medusa/src/repositories/notification.ts b/packages/medusa/src/repositories/notification.ts deleted file mode 100644 index 4decb78619..0000000000 --- a/packages/medusa/src/repositories/notification.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Notification } from "../models" -import { dataSource } from "../loaders/database" - -export const NotificationRepository = dataSource.getRepository(Notification) -export default NotificationRepository diff --git a/packages/medusa/src/repositories/oauth.ts b/packages/medusa/src/repositories/oauth.ts deleted file mode 100644 index e6b3cfc9da..0000000000 --- a/packages/medusa/src/repositories/oauth.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Oauth } from "../models" -import { dataSource } from "../loaders/database" - -export const OauthRepository = dataSource.getRepository(Oauth) -export default OauthRepository diff --git a/packages/medusa/src/repositories/order-edit.ts b/packages/medusa/src/repositories/order-edit.ts deleted file mode 100644 index 67f3073edc..0000000000 --- a/packages/medusa/src/repositories/order-edit.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { OrderEdit } from "../models/order-edit" -import { dataSource } from "../loaders/database" - -export const OrderEditRepository = dataSource.getRepository(OrderEdit) -export default OrderEditRepository diff --git a/packages/medusa/src/repositories/order-item-change.ts b/packages/medusa/src/repositories/order-item-change.ts deleted file mode 100644 index 19b99c5497..0000000000 --- a/packages/medusa/src/repositories/order-item-change.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { OrderItemChange } from "../models" -import { dataSource } from "../loaders/database" - -export const OrderItemChangeRepository = - dataSource.getRepository(OrderItemChange) -export default OrderItemChangeRepository diff --git a/packages/medusa/src/repositories/order.ts b/packages/medusa/src/repositories/order.ts deleted file mode 100644 index cd2aaac80b..0000000000 --- a/packages/medusa/src/repositories/order.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { objectToStringPath, promiseAll } from "@medusajs/utils" -import { flatten } from "lodash" -import { FindManyOptions, FindOptionsRelations, In } from "typeorm" -import { dataSource } from "../loaders/database" -import { Order } from "../models" -import { - getGroupedRelations, - mergeEntitiesWithRelations, -} from "../utils/repository" - -const ITEMS_REL_NAME = "items" -const REGION_REL_NAME = "region" -const DISCOUNTS_REL_NAME = "discounts" - -export const OrderRepository = dataSource.getRepository(Order).extend({ - async findWithRelations( - relations: FindOptionsRelations = {}, - optionsWithoutRelations: Omit, "relations"> = {} - ): Promise { - const entities = await this.find(optionsWithoutRelations) - const entitiesIds = entities.map(({ id }) => id) - - const groupedRelations = getGroupedRelations(objectToStringPath(relations)) - - const entitiesIdsWithRelations = await promiseAll( - Object.entries(groupedRelations).map(async ([topLevel, rels]) => { - // If top level is region or items then get deleted region as well - return this.find({ - where: { id: In(entitiesIds) }, - select: ["id"], - relations: rels, - withDeleted: [ - ITEMS_REL_NAME, - REGION_REL_NAME, - DISCOUNTS_REL_NAME, - ].includes(topLevel), - relationLoadStrategy: "join", - }) - }) - ).then(flatten) - - const entitiesAndRelations = entities.concat(entitiesIdsWithRelations) - return mergeEntitiesWithRelations(entitiesAndRelations) - }, - - async findOneWithRelations( - relations: FindOptionsRelations = {}, - optionsWithoutRelations: Omit, "relations"> = {} - ): Promise { - // Limit 1 - optionsWithoutRelations.take = 1 - - const result = await this.findWithRelations( - relations, - optionsWithoutRelations - ) - return result[0] - }, -}) - -export default OrderRepository diff --git a/packages/medusa/src/repositories/payment-collection.ts b/packages/medusa/src/repositories/payment-collection.ts deleted file mode 100644 index 4005f8c477..0000000000 --- a/packages/medusa/src/repositories/payment-collection.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { PaymentCollection } from "../models" -import { dataSource } from "../loaders/database" -import { FindManyOptions } from "typeorm" - -export const PaymentCollectionRepository = dataSource - .getRepository(PaymentCollection) - .extend({ - async getPaymentCollectionIdBySessionId( - sessionId: string, - config: FindManyOptions = {} - ): Promise { - const paymentCollection = await this.find({ - where: { - payment_sessions: { - id: sessionId, - }, - }, - relations: { - ...(config.relations ?? {}), - payment_sessions: true, - }, - select: config.select ?? {}, - }) - - if (!paymentCollection.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Payment collection related to Payment Session id ${sessionId} was not found` - ) - } - - return paymentCollection[0] - }, - - async getPaymentCollectionIdByPaymentId( - paymentId: string, - config: FindManyOptions = {} - ): Promise { - const paymentCollection = await this.find({ - where: { - payments: { - id: paymentId, - }, - }, - relations: { - ...(config.relations ?? {}), - payment_sessions: true, - }, - select: config.select ?? {}, - }) - - if (!paymentCollection.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Payment collection related to Payment id ${paymentId} was not found` - ) - } - - return paymentCollection[0] - }, - }) -export default PaymentCollectionRepository diff --git a/packages/medusa/src/repositories/payment-provider.ts b/packages/medusa/src/repositories/payment-provider.ts deleted file mode 100644 index 7de45e4538..0000000000 --- a/packages/medusa/src/repositories/payment-provider.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { PaymentProvider } from "../models" -import { dataSource } from "../loaders/database" - -export const PaymentProviderRepository = - dataSource.getRepository(PaymentProvider) -export default PaymentProviderRepository diff --git a/packages/medusa/src/repositories/payment-session.ts b/packages/medusa/src/repositories/payment-session.ts deleted file mode 100644 index aee2f90505..0000000000 --- a/packages/medusa/src/repositories/payment-session.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { PaymentSession } from "../models" -import { dataSource } from "../loaders/database" - -export const PaymentSessionRepository = dataSource.getRepository(PaymentSession) -export default PaymentSessionRepository diff --git a/packages/medusa/src/repositories/payment.ts b/packages/medusa/src/repositories/payment.ts deleted file mode 100644 index 06957536f6..0000000000 --- a/packages/medusa/src/repositories/payment.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Payment } from "../models" -import { dataSource } from "../loaders/database" - -export const PaymentRepository = dataSource.getRepository(Payment) -export default PaymentRepository diff --git a/packages/medusa/src/repositories/price-list.ts b/packages/medusa/src/repositories/price-list.ts deleted file mode 100644 index 1d824a0396..0000000000 --- a/packages/medusa/src/repositories/price-list.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { FindOperator, FindOptionsWhere, ILike, In } from "typeorm" -import { PriceList, ProductVariantMoneyAmount } from "../models" -import { ExtendedFindConfig } from "../types/common" -import { dataSource } from "../loaders/database" -import { promiseAll } from "@medusajs/utils" - -export const PriceListRepository = dataSource.getRepository(PriceList).extend({ - async listAndCount( - query: ExtendedFindConfig, - q?: string - ): Promise<[PriceList[], number]> { - const query_ = { ...query } - query_.relationLoadStrategy = "query" - query_.where = query.where as FindOptionsWhere - - const groups = query_.where.customer_groups as unknown as FindOperator< - string[] - > - delete query_.where.customer_groups - - if (groups || q) { - query_.relations = query_.relations ?? {} - query_.relations.customer_groups = - query_.relations.customer_groups ?? true - - if (groups) { - query_.where.customer_groups = { - id: In(groups.value), - } - } - } - - if (q) { - const groupsWhere = query_.where.customer_groups ?? {} - - query_.where = query_.where ?? {} - query_.where = [ - { - ...query_.where, - name: ILike(`%${q}%`), - }, - { - ...query_.where, - description: ILike(`%${q}%`), - }, - { - ...query_.where, - customer_groups: { - ...groupsWhere, - name: ILike(`%${q}%`), - }, - }, - ] - } - - return await promiseAll([this.find(query_), this.count(query_)]) - }, - - async listPriceListsVariantIdsMap( - priceListIds: string | string[] - ): Promise<{ [priceListId: string]: string[] }> { - priceListIds = Array.isArray(priceListIds) ? priceListIds : [priceListIds] - - const data = await this.createQueryBuilder("pl") - .innerJoin("pl.prices", "prices") - .innerJoinAndSelect( - ProductVariantMoneyAmount, - "pvma", - "pvma.money_amount_id = prices.id" - ) - .where("pl.id IN (:...ids)", { ids: priceListIds }) - .execute() - - return data.reduce((acc, curr) => { - acc[curr["pl_id"]] ??= [] - acc[curr["pl_id"]].push(curr["pvma_variant_id"]) - acc[curr["pl_id"]] = [...new Set(acc[curr["pl_id"]])] - return acc - }, {}) - }, -}) - -export default PriceListRepository diff --git a/packages/medusa/src/repositories/product-category.ts b/packages/medusa/src/repositories/product-category.ts deleted file mode 100644 index b9dc301e69..0000000000 --- a/packages/medusa/src/repositories/product-category.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { - DeleteResult, - FindOneOptions, - FindOptionsWhere, - ILike, - In, -} from "typeorm" -import { ProductCategory } from "../models/product-category" -import { ExtendedFindConfig, QuerySelector } from "../types/common" -import { dataSource } from "../loaders/database" -import { objectToStringPath, promiseAll } from "@medusajs/utils" -import { isEmpty } from "lodash" - -export const ProductCategoryRepository = dataSource - .getTreeRepository(ProductCategory) - .extend({ - async findOneWithDescendants( - query: FindOneOptions, - treeScope: QuerySelector = {} - ): Promise { - const productCategory = await this.findOne(query) - - if (!productCategory) { - return productCategory - } - - return sortChildren( - // Returns the productCategory with all of its descendants until the last child node - await this.findDescendantsTree(productCategory), - treeScope - ) - }, - - async getFreeTextSearchResultsAndCount( - options: ExtendedFindConfig = { - where: {}, - }, - q?: string, - treeScope: QuerySelector = {}, - includeTree = false - ): Promise<[ProductCategory[], number]> { - const entityName = "product_category" - const options_ = { ...options } - options_.where = options_.where as FindOptionsWhere - - const columnsSelected = objectToStringPath(options_.select, { - includeParentPropertyFields: false, - }) - const relationsSelected = objectToStringPath(options_.relations) - - const fetchSelectColumns = (relationName: string): string[] => { - const modelColumns = this.metadata.ownColumns.map( - (column) => column.propertyName - ) - const selectColumns = columnsSelected.length - ? columnsSelected - : modelColumns - - return selectColumns.map((column) => { - return `${relationName}.${column}` - }) - } - - const queryBuilder = this.createQueryBuilder(entityName) - .select(fetchSelectColumns(entityName)) - .skip(options_.skip) - .take(options_.take) - .addOrderBy(`${entityName}.rank`, "ASC") - .addOrderBy(`${entityName}.handle`, "ASC") - - if (q) { - delete options_.where?.name - delete options_.where?.handle - - options_.where = [ - { - ...options_.where, - name: ILike(`%${q}%`), - }, - { - ...options_.where, - handle: ILike(`%${q}%`), - }, - ] - } - - queryBuilder.where(options_.where) - - const includedTreeRelations: string[] = relationsSelected.filter((rel) => - ProductCategory.treeRelations.includes(rel) - ) - - includedTreeRelations.forEach((treeRelation) => { - const treeWhere = Object.entries(treeScope) - .map((entry) => `${treeRelation}.${entry[0]} = :${entry[0]}`) - .join(" AND ") - - queryBuilder - .leftJoin( - `${entityName}.${treeRelation}`, - treeRelation, - treeWhere, - treeScope - ) - .addSelect(fetchSelectColumns(treeRelation)) - }) - - const nonTreeRelations: string[] = relationsSelected.filter( - (rel) => !ProductCategory.treeRelations.includes(rel) - ) - - nonTreeRelations.forEach((relation) => { - queryBuilder.leftJoinAndSelect(`${entityName}.${relation}`, relation) - }) - - let [categories, count] = await queryBuilder.getManyAndCount() - - categories = await promiseAll( - categories.map(async (productCategory) => { - if (includeTree) { - productCategory = await this.findDescendantsTree(productCategory) - } - - return sortChildren(productCategory, treeScope) - }) - ) - - return [categories, count] - }, - - async addProducts( - productCategoryId: string, - productIds: string[] - ): Promise { - const valuesToInsert = productIds.map((id) => ({ - product_category_id: productCategoryId, - product_id: id, - })) - - await this.createQueryBuilder() - .insert() - .into(ProductCategory.productCategoryProductJoinTable) - .values(valuesToInsert) - .orIgnore() - .execute() - }, - - async removeProducts( - productCategoryId: string, - productIds: string[] - ): Promise { - return await this.createQueryBuilder() - .delete() - .from(ProductCategory.productCategoryProductJoinTable) - .where({ - product_category_id: productCategoryId, - product_id: In(productIds), - }) - .execute() - }, - }) - -export default ProductCategoryRepository - -const scopeChildren = ( - category: ProductCategory, - treeScope: QuerySelector = {} -): ProductCategory => { - if (isEmpty(treeScope)) { - return category - } - - if (category.category_children) { - category.category_children = category.category_children.filter( - (categoryChild) => { - return !Object.entries(treeScope).some( - ([attribute, value]) => categoryChild[attribute] !== value - ) - } - ) - } - - return category -} - -const sortChildren = ( - category: ProductCategory, - treeScope: QuerySelector = {} -): ProductCategory => { - if (category.category_children) { - category.category_children = category.category_children - .map( - // Before we sort the children, we need scope the children - // to conform to treeScope conditions - (child) => sortChildren(scopeChildren(child, treeScope), treeScope) - ) - .sort((a, b) => { - // Sort by rank first - const rankDiff = a.rank - b.rank - - // If the ranks are the same, sort by handle in ascending order - if (rankDiff === 0) { - return a.handle.localeCompare(b.handle) - } - - return rankDiff - }) - } - - return category -} diff --git a/packages/medusa/src/repositories/product-collection.ts b/packages/medusa/src/repositories/product-collection.ts deleted file mode 100644 index be4a133edd..0000000000 --- a/packages/medusa/src/repositories/product-collection.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ProductCollection } from "../models" -import { dataSource } from "../loaders/database" -import { ExtendedFindConfig } from "../types/common" -import { promiseAll } from "@medusajs/utils" - -// eslint-disable-next-line max-len -export const ProductCollectionRepository = dataSource - .getRepository(ProductCollection) - .extend({ - async findAndCountByDiscountConditionId( - conditionId: string, - query: ExtendedFindConfig - ): Promise<[ProductCollection[], number]> { - const qb = this.createQueryBuilder("pc") - .setFindOptions(query) - .innerJoin( - "discount_condition_product_collection", - "dc_pc", - `dc_pc.product_collection_id = pc.id AND dc_pc.condition_id = :dcId`, - { dcId: conditionId } - ) - - return await promiseAll([qb.getMany(), qb.getCount()]) - }, - }) -export default ProductCollectionRepository diff --git a/packages/medusa/src/repositories/product-option-value.ts b/packages/medusa/src/repositories/product-option-value.ts deleted file mode 100644 index 5c1316ff63..0000000000 --- a/packages/medusa/src/repositories/product-option-value.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ProductOptionValue } from "../models" -import { dataSource } from "../loaders/database" - -export const ProductOptionValueRepository = - dataSource.getRepository(ProductOptionValue) -export default ProductOptionValueRepository diff --git a/packages/medusa/src/repositories/product-option.ts b/packages/medusa/src/repositories/product-option.ts deleted file mode 100644 index ba6715507c..0000000000 --- a/packages/medusa/src/repositories/product-option.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ProductOption } from "../models" -import { dataSource } from "../loaders/database" - -export const ProductOptionRepository = dataSource.getRepository(ProductOption) -export default ProductOptionRepository diff --git a/packages/medusa/src/repositories/product-tag.ts b/packages/medusa/src/repositories/product-tag.ts deleted file mode 100644 index a81bd5f1a1..0000000000 --- a/packages/medusa/src/repositories/product-tag.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { In } from "typeorm" -import { ProductTag } from "../models/product-tag" -import { ExtendedFindConfig } from "../types/common" -import { dataSource } from "../loaders/database" -import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" -import { promiseAll } from "@medusajs/utils" - -type UpsertTagsInput = (Partial & { - value: string -})[] - -type ProductTagSelector = Partial & { - q?: string - discount_condition_id?: string -} - -export type DefaultWithoutRelations = Omit< - ExtendedFindConfig, - "relations" -> - -export type FindWithoutRelationsOptions = DefaultWithoutRelations & { - where: DefaultWithoutRelations["where"] & { - discount_condition_id?: string - } -} - -export const ProductTagRepository = dataSource - .getRepository(ProductTag) - .extend({ - async insertBulk( - data: QueryDeepPartialEntity[] - ): Promise { - const queryBuilder = this.createQueryBuilder() - .insert() - .into(ProductTag) - .values(data) - - if (!queryBuilder.connection.driver.isReturningSqlSupported("insert")) { - const rawTags = await queryBuilder.execute() - return rawTags.generatedMaps.map((d) => this.create(d)) as ProductTag[] - } - - const rawTags = await queryBuilder.returning("*").execute() - return rawTags.generatedMaps.map((d) => this.create(d)) - }, - - async listTagsByUsage(take = 10): Promise { - const qb = this.createQueryBuilder("pt") - .select(["id", "COUNT(pts.product_tag_id) as usage_count", "value"]) - .leftJoin("product_tags", "pts", "pt.id = pts.product_tag_id") - .groupBy("id") - .orderBy("usage_count", "DESC") - .limit(take) - - return await qb.getRawMany() - }, - - async upsertTags(tags: UpsertTagsInput): Promise { - const tagsValues = tags.map((tag) => tag.value) - const existingTags = await this.find({ - where: { - value: In(tagsValues), - }, - }) - const existingTagsMap = new Map( - existingTags.map<[string, ProductTag]>((tag) => [tag.value, tag]) - ) - - const upsertedTags: ProductTag[] = [] - const tagsToCreate: QueryDeepPartialEntity[] = [] - - for (const tag of tags) { - const aTag = existingTagsMap.get(tag.value) - if (aTag) { - upsertedTags.push(aTag) - } else { - const newTag = this.create(tag) - tagsToCreate.push(newTag as QueryDeepPartialEntity) - } - } - - if (tagsToCreate.length) { - const newTags = await this.insertBulk(tagsToCreate) - upsertedTags.push(...newTags) - } - - return upsertedTags - }, - - async findAndCountByDiscountConditionId( - conditionId: string, - query: ExtendedFindConfig - ) { - const qb = this.createQueryBuilder("pt") - .where(query.where) - .setFindOptions(query) - .innerJoin( - "discount_condition_product_tag", - "dc_pt", - `dc_pt.product_tag_id = pt.id AND dc_pt.condition_id = :dcId`, - { dcId: conditionId } - ) - - return await promiseAll([qb.getMany(), qb.getCount()]) - }, - }) - -export default ProductTagRepository diff --git a/packages/medusa/src/repositories/product-tax-rate.ts b/packages/medusa/src/repositories/product-tax-rate.ts deleted file mode 100644 index 6f477946b3..0000000000 --- a/packages/medusa/src/repositories/product-tax-rate.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ProductTaxRate } from "../models" -import { dataSource } from "../loaders/database" - -export const ProductTaxRateRepository = dataSource.getRepository(ProductTaxRate) -export default ProductTaxRateRepository diff --git a/packages/medusa/src/repositories/product-type.ts b/packages/medusa/src/repositories/product-type.ts deleted file mode 100644 index f1d246671d..0000000000 --- a/packages/medusa/src/repositories/product-type.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { ProductType } from "../models" -import { ExtendedFindConfig } from "../types/common" -import { dataSource } from "../loaders/database" -import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" -import { promiseAll } from "@medusajs/utils" - -type UpsertTypeInput = Partial & { - value: string -} - -export const ProductTypeRepository = dataSource - .getRepository(ProductType) - .extend({ - async upsertType(type?: UpsertTypeInput): Promise { - if (!type) { - return null - } - - const existing = await this.findOne({ - where: { value: type.value }, - }) - - if (existing) { - return existing - } - - const created = this.create({ - value: type.value, - }) - - const queryBuilder = this.createQueryBuilder() - .insert() - .into(ProductType) - .values(created as QueryDeepPartialEntity) - - if (!queryBuilder.connection.driver.isReturningSqlSupported("insert")) { - const rawTypes = await queryBuilder.execute() - return this.create(rawTypes.generatedMaps[0]) - } - - const rawTypes = await queryBuilder.returning("*").execute() - return this.create(rawTypes.generatedMaps[0]) - }, - - async findAndCountByDiscountConditionId( - conditionId: string, - query: ExtendedFindConfig - ): Promise<[ProductType[], number]> { - const qb = this.createQueryBuilder("pt") - .where(query.where) - .setFindOptions(query) - .innerJoin( - "discount_condition_product_type", - "dc_pt", - `dc_pt.product_type_id = pt.id AND dc_pt.condition_id = :dcId`, - { dcId: conditionId } - ) - - return await promiseAll([qb.getMany(), qb.getCount()]) - }, - }) -export default ProductTypeRepository diff --git a/packages/medusa/src/repositories/product-variant.ts b/packages/medusa/src/repositories/product-variant.ts deleted file mode 100644 index 523d654ffc..0000000000 --- a/packages/medusa/src/repositories/product-variant.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { FindManyOptions } from "typeorm" -import { ProductVariant } from "../models/product-variant" -import { FindOptionsOrder } from "typeorm/find-options/FindOptionsOrder" -import { dataSource } from "../loaders/database" - -export type FindWithRelationsOptions = FindManyOptions & { - order?: FindOptionsOrder - withDeleted?: boolean -} - -export const ProductVariantRepository = dataSource.getRepository(ProductVariant) -export default ProductVariantRepository diff --git a/packages/medusa/src/repositories/product.ts b/packages/medusa/src/repositories/product.ts deleted file mode 100644 index 11751b86f7..0000000000 --- a/packages/medusa/src/repositories/product.ts +++ /dev/null @@ -1,862 +0,0 @@ -import { ExtendedFindConfig } from "@medusajs/types" -import { objectToStringPath } from "@medusajs/utils" -import { cloneDeep } from "lodash" -import { isDefined } from "medusa-core-utils" -import { - Brackets, - FindOperator, - FindOptionsWhere, - In, - SelectQueryBuilder, -} from "typeorm" -import { dataSource } from "../loaders/database" -import { - PriceList, - Product, - ProductCategory, - ProductTag, - SalesChannel, -} from "../models" -import { - applyOrdering, - getGroupedRelations, - mergeEntitiesWithRelations, - queryEntityWithIds, - queryEntityWithoutRelations, -} from "../utils/repository" - -export type DefaultWithoutRelations = Omit< - ExtendedFindConfig, - "relations" -> - -type CategoryQueryParams = { - value: string[] -} - -export type FindWithoutRelationsOptions = DefaultWithoutRelations & { - where: DefaultWithoutRelations["where"] & { - price_list_id?: FindOperator - sales_channel_id?: FindOperator - category_id?: CategoryQueryParams - categories?: FindOptionsWhere - tags?: FindOperator - include_category_children?: boolean - discount_condition_id?: string - } -} - -export const ProductRepository = dataSource.getRepository(Product).extend({ - async queryProducts( - optionsWithoutRelations: FindWithoutRelationsOptions, - shouldCount = false - ): Promise<[Product[], number]> { - const tags = optionsWithoutRelations?.where?.tags - delete optionsWithoutRelations?.where?.tags - - const price_lists = optionsWithoutRelations?.where?.price_list_id - delete optionsWithoutRelations?.where?.price_list_id - - const sales_channels = optionsWithoutRelations?.where?.sales_channel_id - delete optionsWithoutRelations?.where?.sales_channel_id - - const categoryId = optionsWithoutRelations?.where?.category_id - delete optionsWithoutRelations?.where?.category_id - - const categoriesQuery = optionsWithoutRelations.where.categories || {} - delete optionsWithoutRelations?.where?.categories - - const includeCategoryChildren = - optionsWithoutRelations?.where?.include_category_children - delete optionsWithoutRelations?.where?.include_category_children - - const discount_condition_id = - optionsWithoutRelations?.where?.discount_condition_id - delete optionsWithoutRelations?.where?.discount_condition_id - - return await queryEntityWithoutRelations({ - repository: this, - optionsWithoutRelations, - shouldCount, - customJoinBuilders: [ - async (qb, alias) => { - if (tags) { - qb.leftJoin(`${alias}.tags`, "tags").andWhere( - `tags.id IN (:...tag_ids)`, - { - tag_ids: tags.value, - } - ) - return { relation: "tags", preventOrderJoin: true } - } - - return - }, - async (qb, alias) => { - if (price_lists) { - qb.leftJoin(`${alias}.variants`, "variants") - .leftJoin("variants.prices", "prices") - .andWhere("prices.price_list_id IN (:...price_list_ids)", { - price_list_ids: price_lists.value, - }) - return { relation: "prices", preventOrderJoin: true } - } - - return - }, - async (qb, alias) => { - if (sales_channels) { - qb.innerJoin( - `${alias}.sales_channels`, - "sales_channels", - "sales_channels.id IN (:...sales_channels_ids)", - { sales_channels_ids: sales_channels.value } - ) - return { relation: "sales_channels", preventOrderJoin: true } - } - - return - }, - async (qb, alias) => { - const categoryIds: string[] = await this.getCategoryIdsFromInput( - categoryId, - includeCategoryChildren - ) - - if (categoryIds.length || categoriesQuery) { - const joinScope = {} - - if (categoryIds.length) { - Object.assign(joinScope, { id: categoryIds }) - } - - if (categoriesQuery) { - Object.assign(joinScope, categoriesQuery) - } - - this._applyCategoriesQuery(qb, { - alias, - categoryAlias: "categories", - where: joinScope, - joinName: categoryIds.length ? "innerJoin" : "leftJoin", - }) - - return { relation: "categories", preventOrderJoin: true } - } - - return - }, - async (qb, alias) => { - if (discount_condition_id) { - qb.innerJoin( - "discount_condition_product", - "dc_product", - `dc_product.product_id = ${alias}.id AND dc_product.condition_id = :dcId`, - { dcId: discount_condition_id } - ) - } - - return - }, - ], - }) - }, - - async queryProductsWithIds({ - entityIds, - groupedRelations, - withDeleted = false, - select = [], - order = {}, - where = {}, - }: { - entityIds: string[] - groupedRelations: { [toplevel: string]: string[] } - withDeleted?: boolean - select?: (keyof Product)[] - order?: { [column: string]: "ASC" | "DESC" } - where?: FindOptionsWhere - }): Promise { - return await queryEntityWithIds({ - repository: this, - entityIds, - groupedRelations, - withDeleted, - select, - customJoinBuilders: [ - (queryBuilder, alias, topLevel) => { - if (topLevel === "variants") { - const joinMethod = select.filter( - (key) => !!key.match(/^variants\.\w+$/i) - ).length - ? "leftJoin" - : "leftJoinAndSelect" - - queryBuilder[joinMethod](`${alias}.${topLevel}`, topLevel) - - if ( - !Object.keys(order!).some((key) => key.startsWith("variants")) - ) { - // variant_rank being select false, apply the filter here directly - queryBuilder.addOrderBy(`${topLevel}.variant_rank`, "ASC") - } - - return false - } - - return - }, - (queryBuilder, alias, topLevel) => { - if (topLevel === "categories") { - const joinScope = where! - .categories as FindOptionsWhere - - this._applyCategoriesQuery(queryBuilder, { - alias, - categoryAlias: "categories", - where: joinScope, - joinName: "leftJoinAndSelect", - }) - - return false - } - - return - }, - ], - }) - }, - - async findWithRelationsAndCount( - relations: string[] = [], - idsOrOptionsWithoutRelations: FindWithoutRelationsOptions = { where: {} } - ): Promise<[Product[], number]> { - return await this._findWithRelations({ - relations, - idsOrOptionsWithoutRelations, - withDeleted: false, - shouldCount: true, - }) - }, - - async findWithRelations( - relations: string[] = [], - idsOrOptionsWithoutRelations: FindWithoutRelationsOptions | string[] = { - where: {}, - }, - withDeleted = false - ): Promise { - const [products] = await this._findWithRelations({ - relations, - idsOrOptionsWithoutRelations, - withDeleted, - shouldCount: false, - }) - - return products - }, - - async findOneWithRelations( - relations: string[] = [], - optionsWithoutRelations: FindWithoutRelationsOptions = { where: {} } - ): Promise { - // Limit 1 - optionsWithoutRelations.take = 1 - - const result = await this.findWithRelations( - relations, - optionsWithoutRelations - ) - return result[0] - }, - - async bulkAddToCollection( - productIds: string[], - collectionId: string - ): Promise { - await this.createQueryBuilder() - .update(Product) - .set({ collection_id: collectionId }) - .where({ id: In(productIds) }) - .execute() - - return this.findByIds(productIds) - }, - - async bulkRemoveFromCollection( - productIds: string[], - collectionId: string - ): Promise { - await this.createQueryBuilder() - .update(Product) - .set({ collection_id: null }) - .where({ id: In(productIds), collection_id: collectionId }) - .execute() - - return this.findByIds(productIds) - }, - - async getFreeTextSearchResultsAndCount( - q: string, - options: FindWithoutRelationsOptions = { where: {} }, - relations: string[] = [] - ): Promise<[Product[], number]> { - const option_ = cloneDeep(options) - - const productAlias = "product" - const pricesAlias = "prices" - const variantsAlias = "variants" - const collectionAlias = "collection" - const tagsAlias = "tags" - - if ("description" in option_.where) { - delete option_.where.description - } - - if ("title" in option_.where) { - delete option_.where.title - } - - const tags = option_.where.tags - delete option_.where.tags - - const price_lists = option_.where.price_list_id - delete option_.where.price_list_id - - const sales_channels = option_.where.sales_channel_id - delete option_.where.sales_channel_id - - const discount_condition_id = option_.where.discount_condition_id - delete option_.where.discount_condition_id - - const categoryId = option_.where.category_id - delete option_.where.category_id - - const includeCategoryChildren = option_?.where?.include_category_children - delete option_?.where?.include_category_children - - const categoriesQuery = option_.where.categories || {} - delete option_.where.categories - - let qb = this.createQueryBuilder(`${productAlias}`) - .leftJoinAndSelect(`${productAlias}.variants`, variantsAlias) - .leftJoinAndSelect(`${productAlias}.collection`, `${collectionAlias}`) - .select([`${productAlias}.id`]) - .where(option_.where) - .andWhere( - new Brackets((qb) => { - qb.where(`${productAlias}.description ILIKE :q`, { q: `%${q}%` }) - .orWhere(`${productAlias}.title ILIKE :q`, { q: `%${q}%` }) - .orWhere(`${variantsAlias}.title ILIKE :q`, { q: `%${q}%` }) - .orWhere(`${variantsAlias}.sku ILIKE :q`, { q: `%${q}%` }) - .orWhere(`${collectionAlias}.title ILIKE :q`, { q: `%${q}%` }) - }) - ) - .skip(option_.skip) - .take(option_.take) - - if (discount_condition_id) { - qb.innerJoin( - "discount_condition_product", - "dc_product", - `dc_product.product_id = ${productAlias}.id AND dc_product.condition_id = :dcId`, - { dcId: discount_condition_id } - ) - } - - if (tags) { - qb.leftJoin(`${productAlias}.tags`, tagsAlias).andWhere( - `${tagsAlias}.id IN (:...tag_ids)`, - { - tag_ids: tags.value, - } - ) - } - - if (price_lists) { - const variantPricesAlias = `${variantsAlias}_prices` - qb.leftJoin(`${productAlias}.variants`, variantPricesAlias) - .leftJoin(`${variantPricesAlias}.prices`, pricesAlias) - .andWhere(`${pricesAlias}.price_list_id IN (:...price_list_ids)`, { - price_list_ids: price_lists.value, - }) - } - - if (sales_channels) { - qb.innerJoin( - `${productAlias}.sales_channels`, - "sales_channels", - "sales_channels.id IN (:...sales_channels_ids)", - { sales_channels_ids: sales_channels.value } - ) - } - - if (categoriesQuery) { - const joinScope = {} - const categoryIds: string[] = await this.getCategoryIdsFromInput( - categoryId, - includeCategoryChildren - ) - - if (categoryIds.length) { - Object.assign(joinScope, { id: categoryIds }) - } - - if (categoriesQuery) { - Object.assign(joinScope, categoriesQuery) - } - - this._applyCategoriesQuery(qb, { - alias: productAlias, - categoryAlias: "categories", - where: joinScope, - joinName: categoryIds.length ? "innerJoin" : "leftJoin", - }) - } - - const joinedWithTags = !!tags - const joinedWithPriceLists = !!price_lists - applyOrdering({ - repository: this, - order: (options.order as any) ?? {}, - qb, - alias: productAlias, - shouldJoin: (relation) => - relation !== variantsAlias && - (relation !== pricesAlias || !joinedWithPriceLists) && - (relation !== tagsAlias || !joinedWithTags), - }) - - if (option_.withDeleted) { - qb = qb.withDeleted() - } - - const [results, count] = await qb.getManyAndCount() - const orderedResultsSet = new Set(results.map((p) => p.id)) - - const products = await this.findWithRelations( - relations, - [...orderedResultsSet], - option_.withDeleted - ) - const productsMap = new Map(products.map((p) => [p.id, p])) - - // Looping through the orderedResultsSet in order to maintain the original order and assign the data returned by findWithRelations - const orderedProducts: Product[] = [] - orderedResultsSet.forEach((id) => { - orderedProducts.push(productsMap.get(id)!) - }) - - return [orderedProducts, count] - }, - - async getCategoryIdsFromInput( - categoryId?: CategoryQueryParams, - includeCategoryChildren = false - ): Promise { - let categoryIds = categoryId?.value - - if (!isDefined(categoryIds)) { - return [] - } - - if (includeCategoryChildren) { - const categoryRepository = this.manager.getTreeRepository(ProductCategory) - const categories = await categoryRepository.find({ - where: { id: In(categoryIds) }, - }) - - for (const category of categories) { - const categoryChildren = await categoryRepository.findDescendantsTree( - category - ) - - categoryIds = categoryIds.concat( - this.getCategoryIdsRecursively(categoryChildren) - ) - } - } - - return categoryIds - }, - - getCategoryIdsRecursively(productCategory: ProductCategory) { - let result = [productCategory.id] - - ;(productCategory.category_children || []).forEach((child) => { - result = result.concat(this.getCategoryIdsRecursively(child)) - }) - - return result - }, - - async _findWithRelations({ - relations = [], - idsOrOptionsWithoutRelations = { - where: {}, - }, - withDeleted = false, - shouldCount = false, - }: { - relations: string[] - idsOrOptionsWithoutRelations: string[] | FindWithoutRelationsOptions - withDeleted: boolean - shouldCount: boolean - }): Promise<[Product[], number]> { - withDeleted = Array.isArray(idsOrOptionsWithoutRelations) - ? withDeleted - : idsOrOptionsWithoutRelations.withDeleted ?? false - const isOptionsArray = Array.isArray(idsOrOptionsWithoutRelations) - const originalWhere = isOptionsArray - ? undefined - : cloneDeep(idsOrOptionsWithoutRelations.where) - const originalOrder: any = isOptionsArray - ? undefined - : { ...idsOrOptionsWithoutRelations.order } - const originalSelect = isOptionsArray - ? undefined - : (objectToStringPath(idsOrOptionsWithoutRelations.select, { - includeParentPropertyFields: false, - }) as (keyof Product)[]) - const clonedOptions = isOptionsArray - ? idsOrOptionsWithoutRelations - : cloneDeep(idsOrOptionsWithoutRelations) - - let count: number - let entities: Product[] - - if (isOptionsArray) { - entities = await this.find({ - where: { - id: In(clonedOptions as string[]), - }, - withDeleted, - }) - count = entities.length - } else { - const result = await this.queryProducts( - clonedOptions as FindWithoutRelationsOptions, - shouldCount - ) - entities = result[0] - count = result[1] - } - const entitiesIds = entities.map(({ id }) => id) - - if (entitiesIds.length === 0) { - // no need to continue - return [[], count] - } - - if (relations.length === 0) { - // Since we are finding by the ids that have been retrieved above and those ids are already - // applying skip/take. Remove those options to avoid getting no results - if (!Array.isArray(clonedOptions)) { - delete clonedOptions.skip - delete clonedOptions.take - } - - const toReturn = await this.find({ - ...(isOptionsArray - ? {} - : (clonedOptions as FindWithoutRelationsOptions)), - where: { - id: In(entitiesIds), - ...(Array.isArray(clonedOptions) ? {} : clonedOptions.where), - }, - }) - return [toReturn, toReturn.length] - } - - const groupedRelations = getGroupedRelations(relations) - - const entitiesIdsWithRelations = await this.queryProductsWithIds({ - entityIds: entitiesIds, - groupedRelations, - select: originalSelect, - order: originalOrder, - where: originalWhere, - withDeleted, - }) - - const entitiesAndRelations = entities.concat(entitiesIdsWithRelations) - const entitiesToReturn = - mergeEntitiesWithRelations(entitiesAndRelations) - - return [entitiesToReturn, count] - }, - - async isProductInSalesChannels( - id: string, - salesChannelIds: string[] - ): Promise { - return ( - (await this.createQueryBuilder("product") - .leftJoin( - "product.sales_channels", - "sales_channels", - "sales_channels.id IN (:...salesChannelIds)", - { salesChannelIds } - ) - .getCount()) > 0 - ) - }, - - _applyCategoriesQuery( - qb: SelectQueryBuilder, - { alias, categoryAlias, where, joinName } - ) { - const joinWhere = Object.entries(where ?? {}) - .map(([column, condition]) => { - if (Array.isArray(condition)) { - return `${categoryAlias}.${column} IN (:...${column})` - } else { - return `${categoryAlias}.${column} = :${column}` - } - }) - .join(" AND ") - - qb[joinName](`${alias}.${categoryAlias}`, categoryAlias, joinWhere, where) - - return qb - }, - - /* async findAndCount( - options: ExtendedFindConfig, - q?: string - ): Promise<[Product[], number]> { - const options_ = { ...options } - options_.relationLoadStrategy = "query" - - const queryBuilder = await this.prepareQueryBuilder_(options_, q) - return await queryBuilder.getManyAndCount() - }, - - async findOne( - options: ExtendedFindConfig - ): Promise { - const options_ = { ...options } - options_.relationLoadStrategy = "query" - - const queryBuilder = await this.prepareQueryBuilder_(options_) - return await queryBuilder.getOne() - }, - - async prepareQueryBuilder_( - options: ExtendedFindConfig, - q?: string - ): Promise> { - const options_ = { ...options } - - const productAlias = "product" - const queryBuilder = this.createQueryBuilder(productAlias) - - // TODO: https://github.com/typeorm/typeorm/issues/9719 - // https://github.com/typeorm/typeorm/issues/6294 - // Cleanup the repo and fix order/skip/take and relation load strategy when those issues are resolved - - const orderFieldsCollectionPointSeparated = objectToStringPath( - options.order ?? {} - ) - - const isDepth1 = !orderFieldsCollectionPointSeparated.some( - (field) => field.indexOf(".") !== -1 - ) - options_.relationLoadStrategy = isDepth1 - ? options_.relationLoadStrategy - : "join" - - options_.relations = options_.relations ?? {} - options_.where = options_.where as FindOptionsWhere - - const priceListId = options_.where.price_list_id as FindOperator - const tags = options_.where.tags as FindOperator - const salesChannelId = options_.where.sales_channel_id as FindOperator< - string[] - > - const categoryId = options_.where.category_id as FindOperator - const discountConditionId = options_.where.discount_condition_id - const categoriesQuery = (options_.where.categories || - {}) as FindOptionsWhere - const includeCategoryChildren = - options_.where.include_category_children ?? false - - delete options_.where.price_list_id - delete options_.where.tags - delete options_.where.sales_channel_id - delete options_.where.category_id - delete options_.where.discount_condition_id - delete options_.where.include_category_children - delete options_.where.categories - - if (q) { - options_.relations = options_.relations ?? {} - options_.relations.variants = options_.relations.variants ?? true - options_.relations.collection = options_.relations.collection ?? true - - options_.where = [ - { - ...options_.where, - description: ILike(`%${q}%`), - }, - { - ...options_.where, - title: ILike(`%${q}%`), - }, - { - ...options_.where, - variants: { - title: ILike(`%${q}%`), - }, - }, - { - ...options_.where, - variants: { - sku: ILike(`%${q}%`), - }, - }, - { - ...options_.where, - collection: { - title: ILike(`%${q}%`), - }, - }, - ] - } - - // Add explicit ordering for variant ranking on the variants join directly - // This constraint is applied if no other order is applied - if (options_.relations.variants && !isObject(options_.order?.variants)) { - queryBuilder.leftJoin( - (subQueryBuilder) => { - return subQueryBuilder - .from(ProductVariant, "v") - .orderBy("v.variant_rank", "ASC") - }, - "variants", - "product.id = variants.product_id" - ) - } - - if (priceListId) { - const priceListIds = priceListId.value - - queryBuilder - .leftJoin(`${productAlias}.variants`, "variants_") - .leftJoin("variants_.prices", "ma") - .andWhere("ma.price_list_id IN (:...price_list_ids)", { - price_list_ids: priceListIds, - }) - } - - if (tags) { - const joinMethod = options_.relations.tags - ? queryBuilder.leftJoinAndSelect.bind(queryBuilder) - : queryBuilder.leftJoin.bind(queryBuilder) - - const tagIds = tags.value - - // For an unknown reason, the implementation of the SelectQueryBuilder.setFindOptions -> buildWhere - // Only check if it is a find operator MoreThan or LessThan. Otherwise, it has to be a relation of - // isManyToOne or isOneToOne in order to be valid. Otherwise, it throws `This relation isn't supported by given find operator` - // We might need to wait for an update or open a PR around that subject - - joinMethod(`${productAlias}.tags`, "tags").andWhere( - `tags.id IN (:...tag_ids)`, - { - tag_ids: tagIds, - } - ) - } - - if (salesChannelId) { - const joinMethod = options_.relations.sales_channels - ? queryBuilder.innerJoinAndSelect.bind(queryBuilder) - : queryBuilder.innerJoin.bind(queryBuilder) - - const scIds = salesChannelId.value - - joinMethod( - `${productAlias}.sales_channels`, - "sales_channels", - "sales_channels.id IN (:...sales_channels_ids)", - { - sales_channels_ids: scIds, - } - ) - } - - if (categoryId) { - const joinMethod = options_.relations.categories - ? queryBuilder.innerJoinAndSelect.bind(queryBuilder) - : queryBuilder.innerJoin.bind(queryBuilder) - - let categoryIds = categoryId.value - - if (includeCategoryChildren) { - const categoryRepository = - this.manager.getTreeRepository(ProductCategory) - - const categories = await categoryRepository.find({ - where: { - id: In(categoryIds), - ...categoriesQuery, - }, - }) - - for (const category of categories) { - const categoryChildren = await categoryRepository.findDescendantsTree( - category - ) - - categoryIds = categoryIds.concat( - fetchCategoryDescendantsIds(categoryChildren, categoriesQuery) - ) - } - } - - if (categoryIds.length) { - const categoryAlias = "categories" - const joinScope = { - ...categoriesQuery, - id: categoryIds, - } - const joinWhere = Object.entries(joinScope) - .map((entry) => { - if (Array.isArray(entry[1])) { - return `${categoryAlias}.${entry[0]} IN (:...${entry[0]})` - } else { - return `${categoryAlias}.${entry[0]} = :${entry[0]}` - } - }) - .join(" AND ") - - joinMethod( - `${productAlias}.${categoryAlias}`, - categoryAlias, - joinWhere, - joinScope - ) - } - } - - if (discountConditionId) { - queryBuilder.innerJoin( - "discount_condition_product", - "dc_product", - `dc_product.product_id = product.id AND dc_product.condition_id = :dcId`, - { dcId: discountConditionId } - ) - } - - if (options_.withDeleted) { - queryBuilder.withDeleted() - } - - queryBuilder.setFindOptions(options_) - - return queryBuilder - },*/ -}) - -export default ProductRepository diff --git a/packages/medusa/src/repositories/publishable-api-key-sales-channel.ts b/packages/medusa/src/repositories/publishable-api-key-sales-channel.ts deleted file mode 100644 index 11e1cd96dd..0000000000 --- a/packages/medusa/src/repositories/publishable-api-key-sales-channel.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Brackets, In } from "typeorm" - -import { PublishableApiKeySalesChannel, SalesChannel } from "../models" -import { dataSource } from "../loaders/database" -import SalesChannelRepository from "./sales-channel" -import { generateEntityId } from "../utils" - -const publishableApiKeySalesChannelAlias = "PublishableKeySalesChannel" - -export const PublishableApiKeySalesChannelRepository = dataSource - .getRepository(PublishableApiKeySalesChannel) - .extend({ - /** - * Query a list of sales channels that are assigned to the publishable key scope - * - * @param publishableApiKeyId - id of the key to retrieve channels for - * @param config - querying params - */ - async findSalesChannels( - publishableApiKeyId: string, - config?: { q?: string } - ): Promise { - const salesChannelAlias = "sales_channel" - - const queryBuilder = this.createQueryBuilder( - publishableApiKeySalesChannelAlias - ) - .select(`${salesChannelAlias}.*`) - .from(SalesChannel, salesChannelAlias) - .where( - `${publishableApiKeySalesChannelAlias}.publishable_key_id = :publishableApiKeyId`, - { - publishableApiKeyId, - } - ) - .andWhere( - `${publishableApiKeySalesChannelAlias}.sales_channel_id = ${salesChannelAlias}.id` - ) - - if (config?.q) { - queryBuilder.andWhere( - new Brackets((qb) => { - qb.where(`${salesChannelAlias}.description ILIKE :q`, { - q: `%${config.q}%`, - }).orWhere(`${salesChannelAlias}.name ILIKE :q`, { - q: `%${config.q}%`, - }) - }) - ) - } - - const records = await queryBuilder.getRawMany() - return records.map((salesChannel: SalesChannel) => - SalesChannelRepository.create(salesChannel) - ) - }, - - /** - * Assign (multiple) sales channels to the Publishable Key scope - * - * @param publishableApiKeyId - publishable key id - * @param salesChannelIds - an array of SC ids - */ - async addSalesChannels( - publishableApiKeyId: string, - salesChannelIds: string[] - ): Promise { - const valuesToInsert = salesChannelIds.map((id) => ({ - id: generateEntityId(undefined, "pksc"), - sales_channel_id: id, - publishable_key_id: publishableApiKeyId, - })) - - await this.createQueryBuilder() - .insert() - .into(PublishableApiKeySalesChannel) - .values(valuesToInsert) - .orIgnore() - .execute() - }, - - /** - * Remove multiple sales channels from the PK scope - * - * @param publishableApiKeyId -publishable key id - * @param salesChannelIds - an array of SC ids - */ - async removeSalesChannels( - publishableApiKeyId: string, - salesChannelIds: string[] - ): Promise { - await this.createQueryBuilder() - .delete() - .from(PublishableApiKeySalesChannel) - .where({ - sales_channel_id: In(salesChannelIds), - publishable_key_id: publishableApiKeyId, - }) - .execute() - }, - }) -export default PublishableApiKeySalesChannelRepository diff --git a/packages/medusa/src/repositories/publishable-api-key.ts b/packages/medusa/src/repositories/publishable-api-key.ts deleted file mode 100644 index e4a0f37ee0..0000000000 --- a/packages/medusa/src/repositories/publishable-api-key.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { PublishableApiKey } from "../models" -import { dataSource } from "../loaders/database" - -// eslint-disable-next-line max-len -export const PublishableApiKeyRepository = dataSource.getRepository(PublishableApiKey) -export default PublishableApiKeyRepository diff --git a/packages/medusa/src/repositories/refund.ts b/packages/medusa/src/repositories/refund.ts deleted file mode 100644 index 435af473fa..0000000000 --- a/packages/medusa/src/repositories/refund.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Refund } from "../models" -import { dataSource } from "../loaders/database" - -export const RefundRepository = dataSource.getRepository(Refund) -export default RefundRepository diff --git a/packages/medusa/src/repositories/region.ts b/packages/medusa/src/repositories/region.ts deleted file mode 100644 index e2fe60896d..0000000000 --- a/packages/medusa/src/repositories/region.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Region } from "../models" -import { dataSource } from "../loaders/database" - -export const RegionRepository = dataSource.getRepository(Region) -export default RegionRepository diff --git a/packages/medusa/src/repositories/return-item.ts b/packages/medusa/src/repositories/return-item.ts deleted file mode 100644 index e22558ba0b..0000000000 --- a/packages/medusa/src/repositories/return-item.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ReturnItem } from "../models" -import { dataSource } from "../loaders/database" - -export const ReturnItemRepository = dataSource.getRepository(ReturnItem) -export default ReturnItemRepository diff --git a/packages/medusa/src/repositories/return-reason.ts b/packages/medusa/src/repositories/return-reason.ts deleted file mode 100644 index 3c9db98f29..0000000000 --- a/packages/medusa/src/repositories/return-reason.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ReturnReason } from "../models" -import { dataSource } from "../loaders/database" - -export const ReturnReasonRepository = dataSource.getRepository(ReturnReason) -export default ReturnReasonRepository diff --git a/packages/medusa/src/repositories/return.ts b/packages/medusa/src/repositories/return.ts deleted file mode 100644 index efde970670..0000000000 --- a/packages/medusa/src/repositories/return.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Return } from "../models" -import { dataSource } from "../loaders/database" - -export const ReturnRepository = dataSource.getRepository(Return) -export default ReturnRepository diff --git a/packages/medusa/src/repositories/sales-channel.ts b/packages/medusa/src/repositories/sales-channel.ts deleted file mode 100644 index e4d35442fc..0000000000 --- a/packages/medusa/src/repositories/sales-channel.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { DeleteResult, FindOptionsWhere, ILike, In } from "typeorm" -import { SalesChannel } from "../models" -import { ExtendedFindConfig } from "../types/common" -import { dataSource } from "../loaders/database" -import { generateEntityId } from "../utils" -import { ProductSalesChannel } from "../models/product-sales-channel" - -const productSalesChannelTable = "product_sales_channel" - -export const SalesChannelRepository = dataSource - .getRepository(SalesChannel) - .extend({ - async getFreeTextSearchResults_( - q: string, - options: ExtendedFindConfig & { withCount?: boolean } = { - where: {}, - } - ): Promise { - const options_ = { ...options } - - options_.where = options_.where as FindOptionsWhere - delete options_?.where?.name - delete options_?.where?.description - - options_.where = [ - { - ...options_.where, - name: ILike(`%${q}%`), - }, - { - ...options_.where, - description: ILike(`%${q}%`), - }, - ] - - let qb = this.createQueryBuilder() - .select() - .where(options_.where) - .skip(options_.skip) - .take(options_.take) - - if (options_.withDeleted) { - qb = qb.withDeleted() - } - - return await (options_.withCount ? qb.getManyAndCount() : qb.getMany()) - }, - - async getFreeTextSearchResultsAndCount( - q: string, - options: ExtendedFindConfig = { - where: {}, - } - ): Promise<[SalesChannel[], number]> { - return (await this.getFreeTextSearchResults_(q, { - ...options, - withCount: true, - })) as [SalesChannel[], number] - }, - - async getFreeTextSearchResults( - q: string, - options: ExtendedFindConfig = { - where: {}, - } - ): Promise { - return (await this.getFreeTextSearchResults_( - q, - options - )) as SalesChannel[] - }, - - async removeProducts( - salesChannelId: string, - productIds: string[] - ): Promise { - const whereOptions = { - sales_channel_id: salesChannelId, - product_id: In(productIds), - } - - return await this.createQueryBuilder() - .delete() - .from(productSalesChannelTable) - .where(whereOptions) - .execute() - }, - - async addProducts( - salesChannelId: string, - productIds: string[], - isMedusaV2Enabled?: boolean - ): Promise { - let valuesToInsert = productIds.map((id) => ({ - sales_channel_id: salesChannelId, - product_id: id, - })) - - if (isMedusaV2Enabled) { - valuesToInsert = valuesToInsert.map((v) => ({ - ...v, - id: generateEntityId(undefined, "prodsc"), - })) - } - - await this.createQueryBuilder() - .insert() - .into( - isMedusaV2Enabled ? ProductSalesChannel : productSalesChannelTable - ) - .values(valuesToInsert) - .orIgnore() - .execute() - }, - - async listProductIdsBySalesChannelIds( - salesChannelIds: string | string[] - ): Promise<{ [salesChannelId: string]: string[] }> { - salesChannelIds = Array.isArray(salesChannelIds) - ? salesChannelIds - : [salesChannelIds] - - const result = await this.createQueryBuilder() - .select(["sales_channel_id", "product_id"]) - .from(productSalesChannelTable, "psc") - .where({ sales_channel_id: In(salesChannelIds) }) - .execute() - - return result.reduce((acc, curr) => { - acc[curr.sales_channel_id] ??= [] - acc[curr.sales_channel_id].push(curr.product_id) - - return acc - }, {}) - }, - }) - -export default SalesChannelRepository diff --git a/packages/medusa/src/repositories/shipping-method-tax-line.ts b/packages/medusa/src/repositories/shipping-method-tax-line.ts deleted file mode 100644 index b7656cac59..0000000000 --- a/packages/medusa/src/repositories/shipping-method-tax-line.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { ShippingMethodTaxLine } from "../models" -import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" -import { dataSource } from "../loaders/database" - -export const ShippingMethodTaxLineRepository = dataSource - .getRepository(ShippingMethodTaxLine) - .extend({ - async upsertLines( - lines: ShippingMethodTaxLine[] - ): Promise { - const insertResult = await this.createQueryBuilder() - .insert() - .values(lines as QueryDeepPartialEntity[]) - .orUpdate({ - conflict_target: ["shipping_method_id", "code"], - overwrite: ["rate", "name", "updated_at"], - }) - .execute() - - return insertResult.identifiers as ShippingMethodTaxLine[] - }, - - async deleteForCart(cartId: string): Promise { - const qb = this.createQueryBuilder("line") - .select(["line.id"]) - .innerJoin("shipping_method", "sm", "sm.id = line.shipping_method_id") - .innerJoin( - "cart", - "c", - "sm.cart_id = :cartId AND c.completed_at is NULL", - { cartId } - ) - - const toDelete = await qb.getMany() - - await this.createQueryBuilder() - .delete() - .whereInIds(toDelete.map((d) => d.id)) - .execute() - }, - }) - -export default ShippingMethodTaxLineRepository diff --git a/packages/medusa/src/repositories/shipping-method.ts b/packages/medusa/src/repositories/shipping-method.ts deleted file mode 100644 index c06c693b17..0000000000 --- a/packages/medusa/src/repositories/shipping-method.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ShippingMethod } from "../models" -import { dataSource } from "../loaders/database" - -export const ShippingMethodRepository = dataSource.getRepository(ShippingMethod) -export default ShippingMethodRepository diff --git a/packages/medusa/src/repositories/shipping-option-requirement.ts b/packages/medusa/src/repositories/shipping-option-requirement.ts deleted file mode 100644 index 69e2f78a37..0000000000 --- a/packages/medusa/src/repositories/shipping-option-requirement.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ShippingOptionRequirement } from "../models" -import { dataSource } from "../loaders/database" - -export const ShippingOptionRequirementRepository = dataSource.getRepository( - ShippingOptionRequirement -) -export default ShippingOptionRequirementRepository diff --git a/packages/medusa/src/repositories/shipping-option.ts b/packages/medusa/src/repositories/shipping-option.ts deleted file mode 100644 index a668d8d6f1..0000000000 --- a/packages/medusa/src/repositories/shipping-option.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ShippingOption } from "../models" -import { dataSource } from "../loaders/database" -import { In } from "typeorm" - -export const ShippingOptionRepository = dataSource - .getRepository(ShippingOption) - .extend({ - async upsertShippingProfile( - shippingOptionIds: string[], - shippingProfileId: string - ): Promise { - await this.createQueryBuilder() - .update(ShippingOption) - .set({ profile_id: shippingProfileId }) - .where({ id: In(shippingOptionIds) }) - .execute() - - return this.findByIds(shippingOptionIds) - }, - }) - -export default ShippingOptionRepository diff --git a/packages/medusa/src/repositories/shipping-profile.ts b/packages/medusa/src/repositories/shipping-profile.ts deleted file mode 100644 index 2d02c121c8..0000000000 --- a/packages/medusa/src/repositories/shipping-profile.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ShippingProfile } from "../models" -import { dataSource } from "../loaders/database" - -export const ShippingProfileRepository = dataSource - .getRepository(ShippingProfile) - .extend({ - async findByProducts( - productIds: string | string[] - ): Promise<{ [product_id: string]: ShippingProfile[] }> { - productIds = Array.isArray(productIds) ? productIds : [productIds] - - const shippingProfiles = await this.createQueryBuilder("sp") - .select("*") - .innerJoin("product_shipping_profile", "psp", "psp.profile_id = sp.id") - .where("psp.product_id IN (:...productIds)", { productIds }) - .execute() - - return shippingProfiles.reduce((acc, productShippingProfile) => { - acc[productShippingProfile.product_id] ??= [] - acc[productShippingProfile.product_id].push(productShippingProfile) - return acc - }, {}) - }, - }) -export default ShippingProfileRepository diff --git a/packages/medusa/src/repositories/shipping-tax-rate.ts b/packages/medusa/src/repositories/shipping-tax-rate.ts deleted file mode 100644 index 986544672e..0000000000 --- a/packages/medusa/src/repositories/shipping-tax-rate.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ShippingTaxRate } from "../models" -import { dataSource } from "../loaders/database" - -export const ShippingTaxRateRepository = - dataSource.getRepository(ShippingTaxRate) -export default ShippingTaxRateRepository diff --git a/packages/medusa/src/repositories/store.ts b/packages/medusa/src/repositories/store.ts deleted file mode 100644 index b3986e939f..0000000000 --- a/packages/medusa/src/repositories/store.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Store } from "../models" -import { dataSource } from "../loaders/database" - -export const StoreRepository = dataSource.getRepository(Store) -export default StoreRepository diff --git a/packages/medusa/src/repositories/swap.ts b/packages/medusa/src/repositories/swap.ts deleted file mode 100644 index dfbfa0c01f..0000000000 --- a/packages/medusa/src/repositories/swap.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Swap } from "../models" -import { dataSource } from "../loaders/database" - -export const SwapRepository = dataSource.getRepository(Swap) -export default SwapRepository diff --git a/packages/medusa/src/repositories/tax-provider.ts b/packages/medusa/src/repositories/tax-provider.ts deleted file mode 100644 index f98804db91..0000000000 --- a/packages/medusa/src/repositories/tax-provider.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { TaxProvider } from "../models" -import { dataSource } from "../loaders/database" - -export const TaxProviderRepository = dataSource.getRepository(TaxProvider) -export default TaxProviderRepository diff --git a/packages/medusa/src/repositories/tax-rate.ts b/packages/medusa/src/repositories/tax-rate.ts deleted file mode 100644 index 7a4c340b8f..0000000000 --- a/packages/medusa/src/repositories/tax-rate.ts +++ /dev/null @@ -1,267 +0,0 @@ -import { unionBy } from "lodash" -import { - DeleteResult, - FindManyOptions, - FindOptionsSelect, - In, - Not, - SelectQueryBuilder, -} from "typeorm" -import { - Product, - ProductTaxRate, - ProductTypeTaxRate, - ShippingTaxRate, - TaxRate, -} from "../models" -import { TaxRateListByConfig } from "../types/tax-rate" -import { isDefined } from "medusa-core-utils" -import { objectToStringPath, promiseAll } from "@medusajs/utils" -import { dataSource } from "../loaders/database" - -const resolveableFields = [ - "product_count", - "product_type_count", - "shipping_option_count", -] - -export const TaxRateRepository = dataSource.getRepository(TaxRate).extend({ - getFindQueryBuilder(findOptions: FindManyOptions) { - const qb = this.createQueryBuilder("tr") - const cleanOptions = findOptions - - const resolverFields: string[] = [] - if (isDefined(findOptions.select)) { - const selectableCols: (keyof TaxRate)[] = [] - const legacySelect = objectToStringPath( - findOptions.select as FindOptionsSelect, - { includeParentPropertyFields: false } - ) as (keyof TaxRate)[] - for (const k of legacySelect) { - if (!resolveableFields.includes(k)) { - selectableCols.push(k) - } else { - resolverFields.push(k) - } - } - cleanOptions.select = selectableCols - } - - qb.setFindOptions(cleanOptions) - - if (resolverFields.length > 0) { - this.applyResolutionsToQueryBuilder(qb, resolverFields) - } - - return qb - }, - - async findWithResolution(findOptions: FindManyOptions) { - const qb = this.getFindQueryBuilder(findOptions) - return await qb.getMany() - }, - - async findOneWithResolution(findOptions: FindManyOptions) { - const qb = this.getFindQueryBuilder(findOptions) - return await qb.getOne() - }, - - async findAndCountWithResolution(findOptions: FindManyOptions) { - const qb = this.getFindQueryBuilder(findOptions) - return await promiseAll([qb.getMany(), qb.getCount()]) - }, - - applyResolutionsToQueryBuilder( - qb: SelectQueryBuilder, - resolverFields: string[] - ): SelectQueryBuilder { - for (const k of resolverFields) { - switch (k) { - case "product_count": - qb.loadRelationCountAndMap( - `${qb.alias}.product_count`, - `${qb.alias}.products` - ) - break - case "product_type_count": - qb.loadRelationCountAndMap( - `${qb.alias}.product_type_count`, - `${qb.alias}.product_types` - ) - break - case "shipping_option_count": - qb.loadRelationCountAndMap( - `${qb.alias}.shipping_option_count`, - `${qb.alias}.shipping_options` - ) - break - default: - break - } - } - - return qb - }, - - async removeFromProduct( - id: string, - productIds: string[] - ): Promise { - return await this.createQueryBuilder() - .delete() - .from(ProductTaxRate) - .where({ rate_id: id, product_id: In(productIds) }) - .execute() - }, - - async addToProduct( - id: string, - productIds: string[], - overrideExisting = false - ): Promise { - const toInsert = productIds.map((pId) => ({ rate_id: id, product_id: pId })) - const insertResult = await this.createQueryBuilder() - .insert() - .orIgnore(true) - .into(ProductTaxRate) - .values(toInsert) - .execute() - - if (overrideExisting) { - await this.createQueryBuilder() - .delete() - .from(ProductTaxRate) - .where({ rate_id: id, product_id: Not(In(productIds)) }) - .execute() - } - - return await this.manager - .createQueryBuilder(ProductTaxRate, "ptr") - .select() - .where(insertResult.identifiers) - .getMany() - }, - - async removeFromProductType( - id: string, - productTypeIds: string[] - ): Promise { - return await this.createQueryBuilder() - .delete() - .from(ProductTypeTaxRate) - .where({ rate_id: id, product_type_id: In(productTypeIds) }) - .execute() - }, - - async addToProductType( - id: string, - productTypeIds: string[], - overrideExisting = false - ): Promise { - const toInsert = productTypeIds.map((pId) => ({ - rate_id: id, - product_type_id: pId, - })) - const insertResult = await this.createQueryBuilder() - .insert() - .orIgnore(true) - .into(ProductTypeTaxRate) - .values(toInsert) - .execute() - - if (overrideExisting) { - await this.createQueryBuilder() - .delete() - .from(ProductTypeTaxRate) - .where({ rate_id: id, product_type_id: Not(In(productTypeIds)) }) - .execute() - } - - return await this.manager - .createQueryBuilder(ProductTypeTaxRate, "ptr") - .select() - .where(insertResult.identifiers) - .getMany() - }, - - async removeFromShippingOption( - id: string, - optionIds: string[] - ): Promise { - return await this.createQueryBuilder() - .delete() - .from(ShippingTaxRate) - .where({ rate_id: id, shipping_option_id: In(optionIds) }) - .execute() - }, - - async addToShippingOption( - id: string, - optionIds: string[], - overrideExisting = false - ): Promise { - const toInsert = optionIds.map((pId) => ({ - rate_id: id, - shipping_option_id: pId, - })) - const insertResult = await this.createQueryBuilder() - .insert() - .orIgnore(true) - .into(ShippingTaxRate) - .values(toInsert) - .execute() - - if (overrideExisting) { - await this.createQueryBuilder() - .delete() - .from(ShippingTaxRate) - .where({ rate_id: id, shipping_option_id: Not(In(optionIds)) }) - .execute() - } - - return await this.manager - .createQueryBuilder(ShippingTaxRate, "str") - .select() - .where(insertResult.identifiers) - .getMany() - }, - - async listByProduct(productId: string, config: TaxRateListByConfig) { - const productRates = this.createQueryBuilder("txr") - .leftJoin(ProductTaxRate, "ptr", "ptr.rate_id = txr.id") - .leftJoin(Product, "prod", "prod.id = ptr.product_id") - .where("prod.id = :productId", { productId }) - - const typeRates = this.createQueryBuilder("txr") - .leftJoin(ProductTypeTaxRate, "pttr", "pttr.rate_id = txr.id") - .leftJoin(Product, "prod", "prod.type_id = pttr.product_type_id") - .where("prod.id = :productId", { productId }) - - if (isDefined(config.region_id)) { - productRates.andWhere("txr.region_id = :regionId", { - regionId: config.region_id, - }) - typeRates.andWhere("txr.region_id = :regionId", { - regionId: config.region_id, - }) - } - - const results = await promiseAll([ - productRates.getMany(), - typeRates.getMany(), - ]) - - // Only return unique rates by joining the two arrays from typeRates and - // productRates matching based on the id - return unionBy(...results, (txr) => txr.id) - }, - - async listByShippingOption(optionId: string) { - const rates = this.createQueryBuilder("txr") - .leftJoin(ShippingTaxRate, "ptr", "ptr.rate_id = txr.id") - .where("ptr.shipping_option_id = :optionId", { optionId }) - - return await rates.getMany() - }, -}) -export default TaxRateRepository diff --git a/packages/medusa/src/repositories/tracking-link.ts b/packages/medusa/src/repositories/tracking-link.ts deleted file mode 100644 index 6d341d4b3b..0000000000 --- a/packages/medusa/src/repositories/tracking-link.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { TrackingLink } from "../models" -import { dataSource } from "../loaders/database" - -export const TrackingLinkRepository = dataSource.getRepository(TrackingLink) -export default TrackingLinkRepository diff --git a/packages/medusa/src/repositories/user.ts b/packages/medusa/src/repositories/user.ts deleted file mode 100644 index a49b2d55eb..0000000000 --- a/packages/medusa/src/repositories/user.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { User } from "../models" -import { dataSource } from "../loaders/database" - -export const UserRepository = dataSource.getRepository(User) -export default UserRepository diff --git a/packages/medusa/src/scripts/discount-rule-migration.ts b/packages/medusa/src/scripts/discount-rule-migration.ts deleted file mode 100644 index fd87cd8ac6..0000000000 --- a/packages/medusa/src/scripts/discount-rule-migration.ts +++ /dev/null @@ -1,132 +0,0 @@ -import dotenv from "dotenv" -import { DataSource } from "typeorm" -import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" -import Logger from "../loaders/logger" -import { - DiscountCondition, - DiscountConditionOperator, - DiscountConditionType, -} from "../models/discount-condition" -import { DiscountConditionProduct } from "../models/discount-condition-product" -import { DiscountRule } from "../models/discount-rule" -import { DiscountConditionRepository } from "../repositories/discount-condition" -import { typeormConfig } from "./db-config" - -dotenv.config() - -const migrate = async function ({ typeormConfig }): Promise { - const dataSource = new DataSource(typeormConfig) - await dataSource.initialize() - - const BATCH_SIZE = 1000 - - await dataSource.transaction(async (manager) => { - const discountRuleCount = await manager - .createQueryBuilder() - .from(DiscountRule, "dr") - .getCount() - - let offset = 0 - while (offset < discountRuleCount) { - const discountRules = await manager - .createQueryBuilder() - .from(DiscountRule, "dr") - .select("dr.id") - .innerJoin( - "discount_rule_products", - "drp", - "dr.id = drp.discount_rule_id" - ) - .distinct(true) - .limit(BATCH_SIZE) - .offset(offset) - .getRawMany() - - const discountConditionRepo = manager.withRepository( - DiscountConditionRepository - ) - await manager - .createQueryBuilder() - .insert() - .into(DiscountCondition) - .values( - discountRules.map( - (dr) => - discountConditionRepo.create({ - type: DiscountConditionType.PRODUCTS, - operator: DiscountConditionOperator.IN, - discount_rule_id: dr.dr_id, - }) as QueryDeepPartialEntity - ) - ) - .orIgnore() - .execute() - offset += BATCH_SIZE - } - - const discountRuleProductCount = await manager.query( - "SELECT COUNT(*) FROM discount_rule_products" - ) - - offset = 0 - while (offset < parseInt(discountRuleProductCount[0].count)) { - const getConditionProductsResult = await manager - .createQueryBuilder() - .from(DiscountRule, "dr") - .innerJoin( - "discount_rule_products", - "drp", - "dr.id = drp.discount_rule_id" - ) - .innerJoin("discount_condition", "dc", "dr.id = dc.discount_rule_id") - .select("dc.id as cond_id, drp.product_id") - .limit(BATCH_SIZE) - .offset(offset) - .getRawMany() - - await manager - .createQueryBuilder() - .insert() - .into(DiscountConditionProduct) - .values( - getConditionProductsResult.map((dr) => ({ - condition_id: dr.cond_id, - product_id: dr.product_id, - })) - ) - .orIgnore() - .execute() - - offset += BATCH_SIZE - } - }) - - // Validate results - const noDanglingProductsValidation = await dataSource.manager - .query(`SELECT drp.discount_rule_id, drp.product_id, dcp.product_id - FROM "discount_rule_products" drp - LEFT JOIN discount_condition dc ON dc.discount_rule_id = drp.discount_rule_id - LEFT JOIN discount_condition_product dcp - ON dcp.condition_id = dc.id AND dcp.product_id = drp.product_id - WHERE dcp.product_id IS NULL`) - - if ( - noDanglingProductsValidation && - noDanglingProductsValidation?.length === 0 - ) { - Logger.info(`Discount entities have been successfully migrated`) - process.exit() - } else { - Logger.error(`Discount entities could not be migrated`) - process.exit(1) - } -} - -migrate({ typeormConfig }) - .then(() => { - Logger.info("Database migration completed successfully") - process.exit() - }) - .catch((err) => Logger.log(err)) - -export default migrate diff --git a/packages/medusa/src/scripts/gift-card-tax-rate-migration.ts b/packages/medusa/src/scripts/gift-card-tax-rate-migration.ts deleted file mode 100644 index e8b9f1d0a7..0000000000 --- a/packages/medusa/src/scripts/gift-card-tax-rate-migration.ts +++ /dev/null @@ -1,101 +0,0 @@ -import dotenv from "dotenv" -import { createConnection, IsNull } from "typeorm" -import Logger from "../loaders/logger" -import { GiftCard } from "../models/gift-card" -import { typeormConfig } from "./db-config" - -dotenv.config() - -const BATCH_SIZE = 1000 -const migrationName = 'gift-card-tax-rate-migration' - -Logger.info(`typeormConfig: ${JSON.stringify(typeormConfig)}`) - -const migrate = async function ({ typeormConfig }): Promise { - const connection = await createConnection(typeormConfig) - - await connection.transaction(async (manager) => { - let offset = 0 - - // Get all the GiftCards where the gift_card.tax_rate is null - const giftCardsCount = await manager - .createQueryBuilder() - .withDeleted() - .from(GiftCard, "gc") - .select("gc.id") - .where("gc.tax_rate IS NULL") - .getCount() - - const totalBatches = Math.ceil(giftCardsCount / BATCH_SIZE) - - if (totalBatches == 0) { - Logger.info(`${migrationName}: No records to update, skipping migration!`) - - return - } - - Logger.info(`${migrationName}: Running migration for ${giftCardsCount} GiftCards`) - Logger.info(`${migrationName}: Running migration in ${totalBatches} batch(es) of ${BATCH_SIZE}`) - - for (let batch = 1; batch <= totalBatches; batch++) { - Logger.info(`${migrationName}: Starting batch ${batch} of ${totalBatches}`) - - // Get all the GiftCards and its region where the gift_card.tax_rate is null - const giftCardRegionRecords = await manager - .createQueryBuilder() - .withDeleted() - .from(GiftCard, "gc") - .select("gc.id, gc.region_id, gc.tax_rate, r.tax_rate as region_tax_rate") - .innerJoin("region", "r", "gc.region_id = r.id") - .where("gc.tax_rate IS NULL") - .limit(BATCH_SIZE) - .offset(offset) - .getRawMany() - - // Loop through each gift card record and update the value of gift_card.tax_rate - // with region.tax_rate value - giftCardRegionRecords.forEach(async (gcr) => { - await manager - .createQueryBuilder() - .update(GiftCard) - .set({ tax_rate: gcr.region_tax_rate }) - .where("id = :id", { id: gcr.id }) - .execute() - }) - - offset += BATCH_SIZE - - Logger.info(`${migrationName}: Finished batch ${batch} of ${totalBatches}`) - } - - const recordsFailedToBackfill = await manager - .createQueryBuilder() - .withDeleted() - .from(GiftCard, "gc") - .select("gc.id") - .where("gc.tax_rate IS NULL") - .getCount() - - if (recordsFailedToBackfill == 0) { - Logger.info(`${migrationName}: successfully ran for ${giftCardsCount} GiftCards`) - } else { - Logger.info(`${migrationName}: ${recordsFailedToBackfill} GiftCards have no tax_rate set`) - Logger.info(`${migrationName}: 1. Check if all GiftCards have a region associated with it`) - Logger.info(`${migrationName}: If not, they need to be associated with a region & re-run migration`) - Logger.info(`${migrationName}: 2. Check if regions have a tax_rate added to it`) - Logger.info(`${migrationName}: If regions intentionally have no tax_rate, this can be ignored`) - Logger.info(`${migrationName}: If not, add a tax_rate to region & re-run migration`) - } - }) -} - -migrate({ typeormConfig }) - .then(() => { - Logger.info("Database migration completed") - process.exit() - }).catch((err) => { - Logger.error(`Database migration failed - ${JSON.stringify(err)}`) - process.exit(1) - }) - -export default migrate diff --git a/packages/medusa/src/scripts/line-item-adjustment-migration.ts b/packages/medusa/src/scripts/line-item-adjustment-migration.ts deleted file mode 100644 index c8b2f73cb8..0000000000 --- a/packages/medusa/src/scripts/line-item-adjustment-migration.ts +++ /dev/null @@ -1,103 +0,0 @@ -import dotenv from "dotenv" -import { createConnection, SelectQueryBuilder } from "typeorm" -import { LineItem } from "../models/line-item" -import { LineItemAdjustment } from "../models/line-item-adjustment" -import { typeormConfig } from "./db-config" -import Logger from "../loaders/logger" - -dotenv.config() - -const migrate = async function ({ typeormConfig }) { - const connection = await createConnection(typeormConfig) - - const BATCH_SIZE = 1000 - - await connection.transaction(async (manager) => { - const getDiscountableLineItems = (qb: SelectQueryBuilder) => { - return qb - .from(LineItem, "li") - .select([ - "li.order_id as order_id", - "SUM(li.quantity * li.unit_price)::bigint AS discountable_subtotal", - ]) - .where("li.allow_discounts = true") - .groupBy("li.order_id") - } - - const getLineItemAllocations = (qb: SelectQueryBuilder) => - qb - .from(LineItem, "li") - .select([ - "disc.id AS discount_id", - "dr.allocation", - "dr.type", - "dr.value", - "li.*", - "li.order_id", - "ods.discountable_subtotal", - "li.quantity * li.unit_price AS li_subtotal", - `COALESCE(ROUND(CASE - WHEN dr.type = 'percentage' THEN li.quantity*li.unit_price * (dr.value::float / 100) - WHEN dr.type = 'fixed' THEN li.quantity*li.unit_price * (LEAST(COALESCE(dr.value, 0), ods.discountable_subtotal)::float / ods.discountable_subtotal) - ELSE 0 - END), 0) AS discount_total`, - ]) - .leftJoin("order", "o", "o.id = li.order_id") - .leftJoin("order_discounts", "od", "o.id = od.order_id") - .leftJoin("discount", "disc", "od.discount_id = disc.id") - .leftJoin("discount_rule", "dr", "dr.id = disc.rule_id") - .leftJoinAndSelect( - getDiscountableLineItems, - "ods", - "ods.order_id = li.order_id" - ) - .where("dr.type != :type", { type: "free_shipping" }) - - const totalAdjustments = await manager - .createQueryBuilder() - .from(getLineItemAllocations, "lia") - .select("COUNT(*)") - .getRawOne() - .then((result) => parseInt(result.count, 10)) - - let offset = 0 - while (offset < totalAdjustments) { - const lineItemAdjustments = await manager - .createQueryBuilder() - .from(getLineItemAllocations, "lia") - .select([ - "lia.id AS item_id", - "lia.discount_id", - "lia.discount_total AS amount", - "'discount' AS description", - ]) - .limit(BATCH_SIZE) - .offset(offset) - .getRawMany() - - await manager - .createQueryBuilder() - .insert() - .into(LineItemAdjustment) - .values( - lineItemAdjustments.map((lia) => - Object.assign(new LineItemAdjustment(), { - ...lia, - }) - ) - ) - .orIgnore() - .execute() - offset += BATCH_SIZE - } - }) -} - -migrate({ typeormConfig }) - .then(() => { - Logger.info("Database migration completed successfully") - process.exit() - }) - .catch((err) => Logger.log(err)) - -export default migrate diff --git a/packages/medusa/src/scripts/migrate-inventory-items.ts b/packages/medusa/src/scripts/migrate-inventory-items.ts deleted file mode 100644 index e14fd9d23c..0000000000 --- a/packages/medusa/src/scripts/migrate-inventory-items.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { IInventoryService, IStockLocationService } from "@medusajs/types" -import { - ProductVariantInventoryService, - ProductVariantService, -} from "../services" - -import { AwilixContainer } from "awilix" -import { EntityManager } from "typeorm" -import { ProductVariant } from "../models" -import dotenv from "dotenv" -import express from "express" -import loaders from "../loaders" -import { promiseAll } from "@medusajs/utils" -import Logger from "../loaders/logger" - -dotenv.config() - -const BATCH_SIZE = 100 - -const migrateProductVariant = async ( - variant: ProductVariant, - locationId: string, - { - container, - transactionManager, - }: { container: AwilixContainer; transactionManager: EntityManager } -) => { - const productVariantInventoryService: ProductVariantInventoryService = - container.resolve("productVariantInventoryService") - - const productVariantInventoryServiceTx = - productVariantInventoryService.withTransaction(transactionManager) - - const existingVariantInventoryItems = - await productVariantInventoryServiceTx.listByVariant(variant.id) - - if (existingVariantInventoryItems.length) { - return - } - - const inventoryService: IInventoryService = - container.resolve("inventoryService") - - if (!variant.manage_inventory) { - return - } - - const context = { transactionManager } - const inventoryItem = await inventoryService.createInventoryItem( - { - sku: variant.sku, - material: variant.material, - width: variant.width, - length: variant.length, - height: variant.height, - weight: variant.weight, - origin_country: variant.origin_country, - hs_code: variant.hs_code, - mid_code: variant.mid_code, - requires_shipping: true, - }, - context - ) - - await productVariantInventoryServiceTx.attachInventoryItem( - variant.id, - inventoryItem.id, - 1 - ) - - await inventoryService.createInventoryLevel( - { - location_id: locationId, - inventory_item_id: inventoryItem.id, - stocked_quantity: variant.inventory_quantity, - incoming_quantity: 0, - }, - context - ) -} - -const migrateStockLocation = async (container: AwilixContainer) => { - const stockLocationService: IStockLocationService = container.resolve( - "stockLocationService" - ) - const existing = await stockLocationService.list({}, { take: 1 }) - - if (existing.length) { - return existing[0].id - } - - const stockLocation = await stockLocationService.create({ name: "Default" }) - - return stockLocation.id -} - -const processBatch = async ( - variants: ProductVariant[], - locationId: string, - container: AwilixContainer -) => { - const manager = container.resolve("manager") - return await manager.transaction(async (transactionManager) => { - await promiseAll( - variants.map(async (variant) => { - await migrateProductVariant(variant, locationId, { - container, - transactionManager, - }) - }) - ) - }) -} - -const migrate = async function ({ directory }) { - const app = express() - const { container } = await loaders({ - directory, - expressApp: app, - isTest: false, - }) - - const variantService: ProductVariantService = await container.resolve( - "productVariantService" - ) - - const defaultLocationId = await migrateStockLocation(container) - - const [variants, totalCount] = await variantService.listAndCount( - {}, - { take: BATCH_SIZE, order: { id: "ASC" } } - ) - - await processBatch(variants, defaultLocationId, container) - - let processedCount = variants.length - Logger.info(`Processed ${processedCount} of ${totalCount}`) - while (processedCount < totalCount) { - const nextBatch = await variantService.list( - {}, - { - skip: processedCount, - take: BATCH_SIZE, - order: { id: "ASC" }, - } - ) - - await processBatch(nextBatch, defaultLocationId, container) - - processedCount += nextBatch.length - Logger.info(`Processed ${processedCount} of ${totalCount}`) - } - - Logger.info("Done") - process.exit(0) -} - -migrate({ directory: process.cwd() }) diff --git a/packages/medusa/src/scripts/migrate-to-pricing-module.ts b/packages/medusa/src/scripts/migrate-to-pricing-module.ts index 20a82e55e1..2437b2bd81 100644 --- a/packages/medusa/src/scripts/migrate-to-pricing-module.ts +++ b/packages/medusa/src/scripts/migrate-to-pricing-module.ts @@ -1,3 +1,5 @@ +// TODO: we need to discuss this +/* import { IPricingModuleService, PricingTypes } from "@medusajs/types" import { promiseAll } from "@medusajs/utils" import { AwilixContainer } from "awilix" @@ -213,3 +215,4 @@ migrate({ directory: process.cwd() }) Logger.info("Failed to migrate price lists") process.exit(1) }) +*/ diff --git a/packages/medusa/src/scripts/sales-channels-migration.ts b/packages/medusa/src/scripts/sales-channels-migration.ts deleted file mode 100644 index 1c9a7affb0..0000000000 --- a/packages/medusa/src/scripts/sales-channels-migration.ts +++ /dev/null @@ -1,85 +0,0 @@ -import dotenv from "dotenv" -import { createConnection } from "typeorm" -import Logger from "../loaders/logger" -import { Product } from "../models/product" -import { Store } from "../models/store" -import { typeormConfig } from "./db-config" - -dotenv.config() - -const migrate = async function ({ typeormConfig }): Promise { - const connection = await createConnection(typeormConfig) - - const BATCH_SIZE = 1000 - - await connection.transaction(async (manager) => { - const store: Store | undefined = await manager - .createQueryBuilder() - .from(Store, "store") - .select("store.default_sales_channel_id") - .getRawOne() - - if (!store?.default_sales_channel_id) { - Logger.error( - `The default sales channel does not exists yet. Run your project and then re run the migration.` - ) - process.exit(1) - } - - let shouldContinue = true - while (shouldContinue) { - const products = await manager - .createQueryBuilder() - .from(Product, "product") - .leftJoin( - "product_sales_channel", - "product_sc", - "product_sc.product_id = product.id" - ) - .andWhere("product_sc.product_id IS NULL") - .select("product.id as id") - .distinct(true) - .limit(BATCH_SIZE) - .getRawMany() - - if (products.length > 0) { - await manager - .createQueryBuilder() - .insert() - .into("product_sales_channel") - .values( - products.map((product) => ({ - product_id: product.id, - sales_channel_id: store.default_sales_channel_id, - })) - ) - .orIgnore() - .execute() - } - - const danglingProductCount = await manager - .createQueryBuilder() - .from(Product, "product") - .leftJoin( - "product_sales_channel", - "product_sc", - "product_sc.product_id = product.id" - ) - .andWhere("product_sc.product_id IS NULL") - .getCount() - shouldContinue = !!danglingProductCount - } - }) - - Logger.info(`Product entities have been successfully migrated`) - process.exit() -} - -migrate({ typeormConfig }) - .then(() => { - Logger.info("Database migration completed successfully") - process.exit() - }) - .catch((err) => Logger.log(err)) - -export default migrate diff --git a/packages/medusa/src/scripts/utils/migrate-money-amounts-to-pricing-module.ts b/packages/medusa/src/scripts/utils/migrate-money-amounts-to-pricing-module.ts index 040533d73b..9198c17d98 100644 --- a/packages/medusa/src/scripts/utils/migrate-money-amounts-to-pricing-module.ts +++ b/packages/medusa/src/scripts/utils/migrate-money-amounts-to-pricing-module.ts @@ -1,3 +1,5 @@ +// TODO: we need to discuss this +/* import { IPricingModuleService, MedusaContainer } from "@medusajs/types" import { MedusaError, promiseAll } from "@medusajs/utils" @@ -82,3 +84,4 @@ export const migrateProductVariantPricing = async function ( Logger.log(`Processed ${processedCount} of ${totalCount}`) } } +*/ diff --git a/packages/medusa/src/services/__fixtures__/new-totals.ts b/packages/medusa/src/services/__fixtures__/new-totals.ts deleted file mode 100644 index 6388c73d47..0000000000 --- a/packages/medusa/src/services/__fixtures__/new-totals.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { asClass, asValue, createContainer } from "awilix" -import { IdMap, MockManager } from "medusa-test-utils" -import { - GiftCard, - LineItem, - LineItemTaxLine, - ShippingMethod, - ShippingMethodTaxLine, -} from "../../models" -import TaxCalculationStrategy from "../../strategies/tax-calculation" -import { taxProviderServiceMock } from "../__mocks__/tax-provider" - -export const defaultContainerMock = createContainer() -defaultContainerMock.register("manager", asValue(MockManager)) -defaultContainerMock.register( - "taxProviderService", - asValue(taxProviderServiceMock) -) -defaultContainerMock.register("featureFlagRouter", asValue(new FlagRouter({}))) -defaultContainerMock.register( - "taxCalculationStrategy", - asClass(TaxCalculationStrategy) -) - -export const lineItems = [ - { - id: IdMap.getId("item_1_with_tax_lines"), - cart_id: "", - order_id: "", - swap_id: "", - claim_order_id: "", - title: "title", - description: "description", - unit_price: 1000, - quantity: 1, - tax_lines: [ - { - id: IdMap.getId("item_1_with_tax_lines_tax_line_1"), - item_id: IdMap.getId("item_1_with_tax_lines"), - rate: 20, - name: "default", - code: "default", - }, - ] as LineItemTaxLine[], - }, -] as LineItem[] - -export const shippingMethods = [ - { - id: IdMap.getId("sm_1_with_tax_lines"), - price: 1000, - tax_lines: [ - { - id: IdMap.getId("sm_1_with_tax_lines_tax_line_1"), - shipping_method_id: IdMap.getId("sm_1_with_tax_lines"), - rate: 20, - name: "default", - code: "default", - }, - ] as ShippingMethodTaxLine[], - }, -] as ShippingMethod[] - -export const giftCards = [ - { - id: IdMap.getId("gift_card_1"), - code: "CODE", - value: 10000, - balance: 10000, - }, -] as GiftCard[] - -export const giftCardsWithTaxRate = [ - { - id: IdMap.getId("gift_card_1"), - code: "CODE", - value: 10000, - balance: 10000, - tax_rate: 20, - }, -] as GiftCard[] diff --git a/packages/medusa/src/services/__fixtures__/payment-provider.ts b/packages/medusa/src/services/__fixtures__/payment-provider.ts deleted file mode 100644 index 5c70162c7c..0000000000 --- a/packages/medusa/src/services/__fixtures__/payment-provider.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { asClass, asFunction, asValue, createContainer } from "awilix" -import { MockManager, MockRepository } from "medusa-test-utils" -import { - AbstractPaymentProcessor, - PaymentProcessorContext, - PaymentProcessorError, - PaymentProcessorSessionResponse, -} from "../../interfaces" -import Logger from "../../loaders/logger" -import { PaymentSessionStatus } from "../../models" -import { CustomerServiceMock } from "../__mocks__/customer" -import { PaymentServiceMock } from "../__mocks__/payment" -import { PaymentProviderServiceMock } from "../__mocks__/payment-provider" -import PaymentProviderService from "../payment-provider" - -export const defaultContainer = createContainer() -defaultContainer.register( - "paymentProviderService", - asClass(PaymentProviderService) -) -defaultContainer.register("paymentService", asValue(PaymentServiceMock)) -defaultContainer.register("manager", asValue(MockManager)) -defaultContainer.register("paymentSessionRepository", asValue(MockRepository())) -defaultContainer.register( - "paymentProviderRepository", - asValue(PaymentProviderServiceMock) -) -defaultContainer.register("paymentRepository", asValue(MockRepository())) -defaultContainer.register("refundRepository", asValue(MockRepository())) -defaultContainer.register("customerService", asValue(CustomerServiceMock)) -defaultContainer.register("featureFlagRouter", asValue(new FlagRouter({}))) -defaultContainer.register("logger", asValue(Logger)) -defaultContainer.register( - "pp_payment_processor", - asFunction((cradle) => new PaymentProcessor(cradle)) -) - -export class PaymentProcessor extends AbstractPaymentProcessor { - constructor(container) { - super(container) - } - authorizePayment(context: PaymentProcessorContext): Promise< - | PaymentProcessorError - | { - status: PaymentSessionStatus - data: PaymentProcessorSessionResponse["session_data"] - } - > { - return Promise.resolve({} as any) - } - - getPaymentStatus( - paymentSessionData: Record - ): Promise { - return Promise.resolve(PaymentSessionStatus.PENDING) - } - - init(): Promise { - return Promise.resolve(undefined) - } - - initiatePayment( - context: PaymentProcessorContext - ): Promise { - return Promise.resolve({} as PaymentProcessorSessionResponse) - } - - retrievePayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > { - return Promise.resolve({}) - } - - updatePayment( - context: PaymentProcessorContext - ): Promise { - return Promise.resolve(undefined) - } - - capturePayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > { - return Promise.resolve({}) - } - - refundPayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > { - return Promise.resolve({}) - } - - cancelPayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > { - return Promise.resolve({}) - } - - deletePayment( - paymentSessionData: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > { - return Promise.resolve({}) - } - - updatePaymentData( - sessionId: string, - data: Record - ): Promise< - PaymentProcessorError | PaymentProcessorSessionResponse["session_data"] - > { - return Promise.resolve({}) - } -} - -export const defaultPaymentSessionInputData = { - provider_id: "payment_processor", - cart: { - context: {}, - id: "cart-test", - email: "test@medusajs.com", - shipping_address: {}, - shipping_methods: [], - billing_address: { - first_name: "Virgil", - last_name: "Van Dijk", - address_1: "24 Dunks Drive", - city: "Los Angeles", - country_code: "US", - province: "CA", - postal_code: "93011", - }, - }, - currency_code: "usd", - amount: 1000, -} diff --git a/packages/medusa/src/services/__fixtures__/tax-provider.ts b/packages/medusa/src/services/__fixtures__/tax-provider.ts deleted file mode 100644 index 5e437feaa3..0000000000 --- a/packages/medusa/src/services/__fixtures__/tax-provider.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { cacheServiceMock } from "../__mocks__/cache"; -import TaxProviderService from "../tax-provider"; -import { EventBusServiceMock } from "../__mocks__/event-bus"; -import { asClass, asValue, createContainer } from "awilix"; -import { MockManager, MockRepository } from "medusa-test-utils" - -export function getCacheKey(id, regionId) { - return `txrtcache:${id}:${regionId}` -} - -export const defaultContainer = createContainer() -defaultContainer.register("manager", asValue(MockManager)) -defaultContainer.register("taxRateService", asValue({})) -defaultContainer.register("systemTaxService", asValue("system")) -defaultContainer.register("tp_test", asValue("good")) -defaultContainer.register("cacheService", asValue(cacheServiceMock)) -defaultContainer.register("taxProviderService", asClass(TaxProviderService)) -defaultContainer.register("taxProviderRepository", asValue(MockRepository)) -defaultContainer.register("lineItemTaxLineRepository", asValue(MockRepository({ create: (d) => d }))) -defaultContainer.register("shippingMethodTaxLineRepository", asValue(MockRepository)) -defaultContainer.register("eventBusService", asValue(EventBusServiceMock)) - -export const getTaxLineFactory = ({ items, region }) => { - const cart = { - shipping_methods: [], - items: items.map((i) => { - return { - id: i.id, - variant: { - product_id: i.product_id, - }, - } - }), - } - - const calculationContext = { - region, - customer: {}, - allocation_map: {}, - shipping_address: {}, - shipping_methods: [], - } - - return { cart, calculationContext } -} diff --git a/packages/medusa/src/services/__mocks__/auth.js b/packages/medusa/src/services/__mocks__/auth.js deleted file mode 100644 index 6cc537c01b..0000000000 --- a/packages/medusa/src/services/__mocks__/auth.js +++ /dev/null @@ -1,26 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -const adminUser = { - _id: IdMap.getId("admin_user", true), - password: "1235", - name: "hi", -} - -const mock = jest.fn().mockImplementation(() => { - return { - authenticate: jest.fn().mockImplementation((email, password) => { - return Promise.resolve({ - success: true, - user: adminUser, - }) - }), - authenticateAPIToken: jest.fn().mockImplementation(token => { - return Promise.resolve({ - success: true, - user: adminUser, - }) - }), - } -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/cache.js b/packages/medusa/src/services/__mocks__/cache.js deleted file mode 100644 index 359bccef67..0000000000 --- a/packages/medusa/src/services/__mocks__/cache.js +++ /dev/null @@ -1,11 +0,0 @@ -export const cacheServiceMock = { - set: jest.fn().mockImplementation(async () => void 0), - get: jest.fn().mockImplementation(async () => null), - invalidate: jest.fn().mockImplementation(async () => void 0), -} - -const mock = jest.fn().mockImplementation(() => { - return cacheServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/cart.js b/packages/medusa/src/services/__mocks__/cart.js deleted file mode 100644 index c4b1bc5749..0000000000 --- a/packages/medusa/src/services/__mocks__/cart.js +++ /dev/null @@ -1,446 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { MedusaError } from "medusa-core-utils" - -export const carts = { - emptyCart: { - id: IdMap.getId("emptyCart"), - items: [], - region_id: IdMap.getId("testRegion"), - shipping_options: [ - { - id: IdMap.getId("freeShipping"), - profile_id: "default_profile", - data: { - some_data: "yes", - }, - }, - ], - }, - testCart: { - id: IdMap.getId("test-cart"), - items: [], - payment: { - data: "some-data", - }, - payment_session: { - status: "authorized", - }, - total: 1000, - region_id: IdMap.getId("testRegion"), - }, - testCartTaxInclusive: { - id: IdMap.getId("test-cart"), - items: [], - payment: { - data: "some-data", - }, - payment_session: { - status: "authorized", - }, - total: 1000, - region_id: IdMap.getId("testRegion"), - shipping_options: [ - { - id: IdMap.getId("tax-inclusive-option"), - includes_tax: true, - }, - ], - }, - testSwapCart: { - id: IdMap.getId("test-swap"), - items: [], - type: "swap", - payment: { - data: "some-data", - }, - payment_session: { - status: "authorized", - }, - metadata: { - swap_id: "test-swap", - }, - total: 1000, - region_id: IdMap.getId("testRegion"), - }, - regionCart: { - id: IdMap.getId("regionCart"), - name: "Product 1", - region_id: IdMap.getId("testRegion"), - items: [], - }, - frCart: { - id: IdMap.getId("fr-cart"), - title: "test", - region_id: IdMap.getId("region-france"), - items: [ - { - id: IdMap.getId("existingLine"), - title: "merge line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - variant_id: IdMap.getId("eur-10-us-12"), - unit_price: 10, - variant: { - id: IdMap.getId("eur-10-us-12"), - }, - product: { - id: IdMap.getId("product"), - }, - quantity: 10, - }, - ], - shipping_methods: [ - { - id: IdMap.getId("freeShipping"), - profile_id: "default_profile", - }, - ], - shipping_options: [ - { - id: IdMap.getId("freeShipping"), - profile_id: "default_profile", - }, - ], - shipping_address: {}, - billing_address: {}, - discounts: [], - customer_id: "", - }, - cartWithPaySessions: { - id: IdMap.getId("cartWithPaySessions"), - region_id: IdMap.getId("testRegion"), - items: [ - { - id: IdMap.getId("existingLine"), - title: "merge line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - content: { - unit_price: 123, - variant: { - id: IdMap.getId("can-cover"), - }, - product: { - id: IdMap.getId("product"), - }, - quantity: 1, - }, - quantity: 10, - }, - ], - payment_sessions: [ - { - provider_id: "default_provider", - data: { - id: "default_provider_session", - }, - }, - { - provider_id: "unregistered", - data: { - id: "unregistered_session", - }, - }, - ], - shipping_address: {}, - billing_address: {}, - discounts: [], - customer_id: "", - }, - discountCart: { - id: IdMap.getId("discount-cart"), - discounts: [], - region_id: IdMap.getId("region-france"), - items: [ - { - id: IdMap.getId("line"), - title: "merge line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - content: [ - { - unit_price: 8, - variant: { - id: IdMap.getId("eur-8-us-10"), - }, - product: { - id: IdMap.getId("product"), - }, - quantity: 1, - }, - { - unit_price: 10, - variant: { - id: IdMap.getId("eur-10-us-12"), - }, - product: { - id: IdMap.getId("product"), - }, - quantity: 1, - }, - ], - quantity: 10, - }, - { - id: IdMap.getId("existingLine"), - title: "merge line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - content: { - unit_price: 10, - variant: { - id: IdMap.getId("eur-10-us-12"), - }, - product: { - id: IdMap.getId("product"), - }, - quantity: 1, - }, - quantity: 10, - }, - ], - }, - cartWithMetadataLineItem: { - id: IdMap.getId("cartLineItemMetadata"), - discounts: [], - region_id: IdMap.getId("region-france"), - items: [ - { - id: IdMap.getId("lineWithMetadata"), - title: "merge line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - unit_price: 10, - variant: { - id: IdMap.getId("eur-10-us-12"), - }, - product: { - id: IdMap.getId("product"), - }, - quantity: 10, - metadata: { - status: "confirmed", - }, - }, - ], - }, -} - -export const CartServiceMock = { - withTransaction: function () { - return this - }, - updatePaymentSession: jest.fn().mockImplementation((data) => { - return Promise.resolve() - }), - authorizePayment: jest.fn().mockImplementation((id, data) => { - if (id === IdMap.getId("test-cart2")) { - return Promise.resolve({ - ...carts.testCart, - payment_session: { status: "requires_more" }, - id: IdMap.getId("test-cart2"), - }) - } - return Promise.resolve(carts.testCart) - }), - refreshPaymentSession: jest.fn().mockImplementation((data) => { - return Promise.resolve() - }), - update: jest.fn().mockImplementation((data) => { - return Promise.resolve() - }), - create: jest.fn().mockImplementation((data) => { - if (data.region_id === IdMap.getId("testRegion")) { - return Promise.resolve(carts.regionCart) - } - if (data.region_id === IdMap.getId("fail")) { - throw new MedusaError(MedusaError.Types.INVALID_DATA, "Region not found") - } - return Promise.resolve(carts.regionCart) - }), - retrieveWithTotals: jest.fn().mockImplementation((cartId) => { - if (cartId === IdMap.getId("fr-cart")) { - return Promise.resolve(carts.frCart) - } - if (cartId === IdMap.getId("swap-cart")) { - return Promise.resolve(carts.testSwapCart) - } - if (cartId === IdMap.getId("test-cart")) { - return Promise.resolve(carts.testCart) - } - if (cartId === IdMap.getId("cartLineItemMetadata")) { - return Promise.resolve(carts.cartWithMetadataLineItem) - } - if (cartId === IdMap.getId("regionCart")) { - return Promise.resolve(carts.regionCart) - } - if (cartId === IdMap.getId("emptyCart")) { - return Promise.resolve(carts.emptyCart) - } - if (cartId === IdMap.getId("cartWithPaySessions")) { - return Promise.resolve(carts.cartWithPaySessions) - } - if (cartId === IdMap.getId("test-cart2")) { - return Promise.resolve(carts.testCart) - } - if (cartId === IdMap.getId("tax-inclusive-option")) { - return Promise.resolve(carts.testCartTaxInclusive) - } - throw new MedusaError(MedusaError.Types.NOT_FOUND, "cart not found") - }), - retrieve: jest.fn().mockImplementation((cartId) => { - if (cartId === IdMap.getId("fr-cart")) { - return Promise.resolve(carts.frCart) - } - if (cartId === IdMap.getId("swap-cart")) { - return Promise.resolve(carts.testSwapCart) - } - if (cartId === IdMap.getId("test-cart")) { - return Promise.resolve(carts.testCart) - } - if (cartId === IdMap.getId("cartLineItemMetadata")) { - return Promise.resolve(carts.cartWithMetadataLineItem) - } - if (cartId === IdMap.getId("regionCart")) { - return Promise.resolve(carts.regionCart) - } - if (cartId === IdMap.getId("emptyCart")) { - return Promise.resolve(carts.emptyCart) - } - if (cartId === IdMap.getId("cartWithPaySessions")) { - return Promise.resolve(carts.cartWithPaySessions) - } - if (cartId === IdMap.getId("test-cart2")) { - return Promise.resolve(carts.testCart) - } - if (cartId === IdMap.getId("tax-inclusive-option")) { - return Promise.resolve(carts.testCartTaxInclusive) - } - throw new MedusaError(MedusaError.Types.NOT_FOUND, "cart not found") - }), - addLineItem: jest.fn().mockImplementation((cartId, lineItem) => { - return Promise.resolve() - }), - addOrUpdateLineItems: jest.fn().mockImplementation((cartId, lineItem) => { - return Promise.resolve() - }), - setPaymentMethod: jest.fn().mockImplementation((cartId, method) => { - if (method.provider_id === "default_provider") { - return Promise.resolve(carts.cartWithPaySessions) - } - - throw new MedusaError(MedusaError.Types.NOT_ALLOWED, "Not allowed") - }), - removeLineItem: jest.fn().mockImplementation((cartId, lineItem) => { - if (cartId === IdMap.getId("fr-cart")) { - return Promise.resolve(carts.frCart) - } - if (cartId === IdMap.getId("regionCart")) { - return Promise.resolve(carts.regionCart) - } - if (cartId === IdMap.getId("emptyCart")) { - return Promise.resolve(carts.emptyCart) - } - if (cartId === IdMap.getId("cartWithPaySessions")) { - return Promise.resolve(carts.cartWithPaySessions) - } - throw new MedusaError(MedusaError.Types.NOT_FOUND, "cart not found") - }), - updateLineItem: jest.fn().mockImplementation((cartId, lineItem) => { - if (cartId === IdMap.getId("fr-cart")) { - return Promise.resolve(carts.frCart) - } - if (cartId === IdMap.getId("cartLineItemMetadata")) { - return Promise.resolve(carts.cartWithMetadataLineItem) - } - if (cartId === IdMap.getId("regionCart")) { - return Promise.resolve(carts.regionCart) - } - if (cartId === IdMap.getId("emptyCart")) { - return Promise.resolve(carts.emptyCart) - } - if (cartId === IdMap.getId("cartWithPaySessions")) { - return Promise.resolve(carts.cartWithPaySessions) - } - throw new MedusaError(MedusaError.Types.NOT_FOUND, "cart not found") - }), - setRegion: jest.fn().mockImplementation((cartId, regionId) => { - if (regionId === IdMap.getId("fail")) { - throw new MedusaError(MedusaError.Types.NOT_FOUND, "Region not found") - } - return Promise.resolve() - }), - updateEmail: jest.fn().mockImplementation((cartId, email) => { - return Promise.resolve() - }), - updateShippingAddress: jest.fn().mockImplementation((cartId, address) => { - return Promise.resolve() - }), - updateBillingAddress: jest.fn().mockImplementation((cartId, address) => { - return Promise.resolve() - }), - applyDiscount: jest.fn().mockImplementation((cartId, code) => { - return Promise.resolve() - }), - setPaymentSession: jest.fn().mockImplementation((cartId) => { - return Promise.resolve() - }), - setPaymentSessions: jest.fn().mockImplementation((cartId) => { - return Promise.resolve() - }), - setShippingOptions: jest.fn().mockImplementation((cartId) => { - return Promise.resolve() - }), - decorate: jest.fn().mockImplementation((cart) => { - cart.decorated = true - return cart - }), - addShippingMethod: jest.fn().mockImplementation((cartId) => { - return Promise.resolve() - }), - retrieveShippingOption: jest.fn().mockImplementation((cartId, optionId) => { - if (optionId === IdMap.getId("freeShipping")) { - return { - id: IdMap.getId("freeShipping"), - profile_id: "default_profile", - } - } - if (optionId === IdMap.getId("withData")) { - return { - id: IdMap.getId("withData"), - profile_id: "default_profile", - data: { - some_data: "yes", - }, - } - } - }), - retrievePaymentSession: jest.fn().mockImplementation((cartId, providerId) => { - if (providerId === "default_provider") { - return { - provider_id: "default_provider", - data: { - money_id: "success", - }, - } - } - - if (providerId === "nono") { - return { - provider_id: "nono", - data: { - money_id: "fail", - }, - } - } - }), - refreshAdjustments_: jest.fn().mockImplementation((cart) => { - return Promise.resolve({}) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return CartServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/claim.js b/packages/medusa/src/services/__mocks__/claim.js deleted file mode 100644 index b29fe7bbc8..0000000000 --- a/packages/medusa/src/services/__mocks__/claim.js +++ /dev/null @@ -1,26 +0,0 @@ -import { IdMap } from "medusa-test-utils" -export const ClaimServiceMock = { - withTransaction: function() { - return this - }, - retrieve: jest.fn().mockImplementation((data) => { - return Promise.resolve({ order_id: IdMap.getId("test-order") }) - }), - - cancel: jest.fn().mockImplementation((f) => { - return Promise.resolve({ f }) - }), - - cancelFulfillment: jest.fn().mockImplementation((f) => { - return Promise.resolve({ f }) - }), - create: jest.fn().mockImplementation((f) => { - return Promise.resolve(f) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return ClaimServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/currency.js b/packages/medusa/src/services/__mocks__/currency.js deleted file mode 100644 index a4b6b94f07..0000000000 --- a/packages/medusa/src/services/__mocks__/currency.js +++ /dev/null @@ -1,40 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const currency = { - code: IdMap.getId("currency-1"), - symbol: "SYM", - symbol_native: "SYM", - name: "Symbol", -} - -export const CurrencyServiceMock = { - withTransaction: function() { - return this - }, - retrieve: jest.fn().mockImplementation((code) => { - return Promise.resolve({ - ...currency, - code: code, - }) - }), - - update: jest.fn().mockImplementation((code, data) => { - return Promise.resolve({ - ...currency, - ...data, - }) - }), - - listAndCount: jest.fn().mockImplementation(() => { - return Promise.resolve([ - [currency], - 1, - ]) - }) -} - -const mock = jest.fn().mockImplementation(() => { - return CurrencyServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/customer-group.js b/packages/medusa/src/services/__mocks__/customer-group.js deleted file mode 100644 index 0a50f82cb8..0000000000 --- a/packages/medusa/src/services/__mocks__/customer-group.js +++ /dev/null @@ -1,20 +0,0 @@ -export const CustomerGroupServiceMock = { - withTransaction: function () { - return this - }, - - create: jest.fn().mockImplementation((f) => { - return Promise.resolve(f) - }), - - retrieve: jest.fn().mockImplementation((f) => { - return Promise.resolve(f) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return CustomerGroupServiceMock -}) - -export default mock - diff --git a/packages/medusa/src/services/__mocks__/customer.js b/packages/medusa/src/services/__mocks__/customer.js deleted file mode 100644 index be43c9f564..0000000000 --- a/packages/medusa/src/services/__mocks__/customer.js +++ /dev/null @@ -1,74 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import Scrypt from "scrypt-kdf" - -export const CustomerServiceMock = { - withTransaction: function () { - return this - }, - create: jest.fn().mockImplementation((data) => { - return Promise.resolve({ ...data, id: IdMap.getId("lebron") }) - }), - update: jest.fn().mockImplementation((id, data) => { - return Promise.resolve({ ...data, id: IdMap.getId("lebron") }) - }), - decorate: jest.fn().mockImplementation((data) => { - const d = Object.assign({}, data) - d.decorated = true - return d - }), - generateResetPasswordToken: jest.fn().mockImplementation((id) => { - return Promise.resolve() - }), - retrieve: jest.fn().mockImplementation((id) => { - if (id === IdMap.getId("lebron")) { - return Promise.resolve({ - id: IdMap.getId("lebron"), - first_name: "LeBron", - last_name: "James", - email: "lebron@james.com", - password_hash: "1234", - }) - } - return Promise.resolve() - }), - retrieveByEmail: jest.fn().mockImplementation((email) => { - if (email === "lebron@james.com") { - return Promise.resolve({ - id: IdMap.getId("lebron"), - email, - password_hash: "1234", - }) - } - if (email === "test@testdom.com") { - return Promise.resolve({ - id: IdMap.getId("testdom"), - email, - password_hash: "1234", - }) - } - return Promise.resolve(undefined) - }), - retrieveRegisteredByEmail: jest.fn().mockImplementation((email) => { - if (email === "oliver@test.dk") { - return Scrypt.kdf("123456789", { logN: 1, r: 1, p: 1 }).then((hash) => ({ - email, - password_hash: hash.toString("base64"), - has_account: true, - })) - } - if (email === "lebron@james1.com") { - return Promise.resolve({ - id: IdMap.getId("lebron"), - email, - password_hash: "1234", - }) - } - return Promise.resolve(undefined) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return CustomerServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/discount.js b/packages/medusa/src/services/__mocks__/discount.js deleted file mode 100644 index ec129b81c1..0000000000 --- a/packages/medusa/src/services/__mocks__/discount.js +++ /dev/null @@ -1,190 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const discounts = { - dynamic: { - id: IdMap.getId("dynamic"), - code: "Something", - is_dynamic: true, - rule: { - id: IdMap.getId("dynamic_rule"), - type: "percentage", - allocation: "total", - value: 10, - }, - regions: [IdMap.getId("region-france")], - }, - total10Percent: { - id: IdMap.getId("total10"), - code: "10%OFF", - rule: { - id: IdMap.getId("total10_rule"), - type: "percentage", - allocation: "total", - value: 10, - }, - regions: [IdMap.getId("region-france")], - }, - item10Percent: { - id: IdMap.getId("item10Percent"), - code: "MEDUSA", - rule: { - id: IdMap.getId("item10Percent_rule"), - type: "percentage", - allocation: "item", - value: 10, - }, - regions: [IdMap.getId("region-france")], - }, - total10Fixed: { - id: IdMap.getId("total10Fixed"), - code: "MEDUSA", - rule: { - id: IdMap.getId("total10Fixed_rule"), - type: "fixed", - allocation: "total", - value: 10, - }, - regions: [IdMap.getId("region-france")], - }, - item9Fixed: { - id: IdMap.getId("item9Fixed"), - code: "MEDUSA", - rule: { - id: IdMap.getId("item9Fixed_rule"), - type: "fixed", - allocation: "item", - value: 9, - }, - regions: [IdMap.getId("region-france")], - }, - item2Fixed: { - id: IdMap.getId("item2Fixed"), - code: "MEDUSA", - rule: { - id: IdMap.getId("item2Fixed_rule"), - type: "fixed", - allocation: "item", - value: 2, - }, - regions: [IdMap.getId("region-france")], - }, - item10FixedNoVariants: { - id: IdMap.getId("item10FixedNoVariants"), - code: "MEDUSA", - rule: { - id: IdMap.getId("item10FixedNoVariants_rule"), - type: "fixed", - allocation: "item", - value: 10, - }, - regions: [IdMap.getId("region-france")], - }, - expiredDiscount: { - id: IdMap.getId("expired"), - code: "MEDUSA", - ends_at: new Date("December 17, 1995 03:24:00"), - rule: { - id: IdMap.getId("expired_rule"), - type: "fixed", - allocation: "item", - value: 10, - }, - regions: [IdMap.getId("region-france")], - }, - freeShipping: { - id: IdMap.getId("freeshipping"), - code: "FREESHIPPING", - rule: { - id: IdMap.getId("freeshipping_rule"), - type: "free_shipping", - allocation: "total", - value: 10, - }, - regions: [IdMap.getId("region-france")], - }, - USDiscount: { - id: IdMap.getId("us-discount"), - code: "US10", - rule: { - id: IdMap.getId("us-discount_rule"), - type: "free_shipping", - allocation: "total", - value: 10, - }, - regions: [IdMap.getId("us")], - }, - alreadyExists: { - code: "ALREADYEXISTS", - rule: { - id: IdMap.getId("ALREADYEXISTS_rule"), - type: "percentage", - allocation: "total", - value: 20, - }, - regions: [IdMap.getId("fr-cart")], - }, -} - -export const DiscountServiceMock = { - withTransaction: function () { - return this - }, - create: jest.fn().mockImplementation((data) => { - return Promise.resolve(data) - }), - retrieveByCode: jest.fn().mockImplementation((data) => { - if (data === "10%OFF") { - return Promise.resolve(discounts.total10Percent) - } - if (data === "FREESHIPPING") { - return Promise.resolve(discounts.freeShipping) - } - if (data === "US10") { - return Promise.resolve(discounts.USDiscount) - } - return Promise.resolve(undefined) - }), - retrieve: jest.fn().mockImplementation((data) => { - if (data === IdMap.getId("total10")) { - return Promise.resolve(discounts.total10Percent) - } - if (data === IdMap.getId("item10Percent")) { - return Promise.resolve(discounts.item10Percent) - } - if (data === IdMap.getId("freeshipping")) { - return Promise.resolve(discounts.freeShipping) - } - return Promise.resolve(undefined) - }), - update: jest.fn().mockImplementation((data) => { - return Promise.resolve() - }), - delete: jest.fn().mockImplementation((data) => { - return Promise.resolve({ - id: IdMap.getId("total10"), - object: "discount", - deleted: true, - }) - }), - list: jest.fn().mockImplementation((data) => { - return Promise.resolve([{}]) - }), - listAndCount: jest.fn().mockImplementation((data) => { - return Promise.resolve([{}]) - }), - addRegion: jest.fn().mockReturnValue(Promise.resolve()), - removeRegion: jest.fn().mockReturnValue(Promise.resolve()), - addValidProduct: jest.fn().mockReturnValue(Promise.resolve()), - removeValidProduct: jest.fn().mockReturnValue(Promise.resolve()), - generateGiftCard: jest.fn().mockReturnValue( - Promise.resolve({ - id: IdMap.getId("gift_card_id"), - }) - ), -} - -const mock = jest.fn().mockImplementation(() => { - return DiscountServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/document.js b/packages/medusa/src/services/__mocks__/document.js deleted file mode 100644 index a86d14d0ef..0000000000 --- a/packages/medusa/src/services/__mocks__/document.js +++ /dev/null @@ -1,21 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const DocumentServiceMock = { - create: jest.fn().mockImplementation(data => { - return Promise.resolve({ - _id: "doc1234", - }) - }), - retrieve: jest.fn().mockImplementation(data => { - return Promise.resolve(undefined) - }), - update: jest.fn().mockImplementation(data => { - return Promise.resolve() - }), -} - -const mock = jest.fn().mockImplementation(() => { - return DocumentServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/fulfillment-provider.js b/packages/medusa/src/services/__mocks__/fulfillment-provider.js deleted file mode 100644 index 762856305a..0000000000 --- a/packages/medusa/src/services/__mocks__/fulfillment-provider.js +++ /dev/null @@ -1,76 +0,0 @@ -export const DefaultProviderMock = { - validateOption: jest.fn().mockImplementation(data => { - if (data.id === "new") { - return Promise.resolve(true) - } - - return Promise.resolve(false) - }), - canCalculate: jest.fn().mockImplementation(data => { - if (data.id === "bonjour") { - return Promise.resolve(true) - } - - return Promise.resolve(false) - }), - cancelFulfillment: jest.fn().mockImplementation(data => { - return {} - }), - calculatePrice: jest.fn().mockImplementation(data => { - return Promise.resolve() - }), - createOrder: jest.fn().mockImplementation(data => { - return Promise.resolve(data) - }), - getFulfillmentDocuments: jest.fn().mockImplementation(() => { - return Promise.resolve([ - { - name: "Test", - type: "pdf", - base_64: "verylong", - }, - ]) - }), - createReturn: jest.fn().mockImplementation(data => { - return Promise.resolve({ - ...data, - shipped: true, - }) - }), - getReturnDocuments: jest.fn().mockImplementation(() => { - return Promise.resolve([ - { - name: "Test Return", - type: "pdf", - base_64: "verylong return", - }, - ]) - }), - getShipmentDocuments: jest.fn().mockImplementation(() => { - return Promise.resolve([ - { - name: "Test Shipment", - type: "pdf", - base_64: "verylong shipment", - }, - ]) - }), -} - -export const FulfillmentProviderServiceMock = { - retrieveProvider: jest.fn().mockImplementation(providerId => { - if (providerId === "default_provider") { - return DefaultProviderMock - } - throw new Error("Provider Not Found") - }), - list: jest.fn().mockImplementation(() => { - return Promise.resolve() - }), -} - -const mock = jest.fn().mockImplementation(() => { - return FulfillmentProviderServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/fulfillment.js b/packages/medusa/src/services/__mocks__/fulfillment.js deleted file mode 100644 index b71eb79526..0000000000 --- a/packages/medusa/src/services/__mocks__/fulfillment.js +++ /dev/null @@ -1,26 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const FulfillmentServiceMock = { - withTransaction: function() { - return this - }, - retrieve: jest.fn().mockImplementation(data => { - switch (data) { - case IdMap.getId("order-fulfillment"): - return Promise.resolve({ order_id: IdMap.getId("test-order") }) - case IdMap.getId("swap-fulfillment"): - return Promise.resolve({ swap_id: IdMap.getId("test-swap") }) - case IdMap.getId("claim-fulfillment"): - return Promise.resolve({ claim_order_id: IdMap.getId("test-claim") }) - } - }), - cancelFulfillment: jest.fn().mockImplementation(data => { - return Promise.resolve({ order_id: IdMap.getId("test-order") }) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return FulfillmentServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/inventory.js b/packages/medusa/src/services/__mocks__/inventory.js deleted file mode 100644 index 352df04b7c..0000000000 --- a/packages/medusa/src/services/__mocks__/inventory.js +++ /dev/null @@ -1,93 +0,0 @@ -export const InventoryServiceMock = { - withTransaction: function () { - return this - }, - - listInventoryItems: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - listReservationItems: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - listInventoryLevels: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - retrieveInventoryItem: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - retrieveInventoryLevel: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - createReservationItem: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - createInventoryItem: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - createInventoryLevel: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - updateInventoryLevel: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - updateInventoryItem: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - updateReservationItem: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - deleteReservationItemsByLineItem: jest - .fn() - .mockImplementation((id, config) => { - return Promise.resolve() - }), - - deleteReservationItem: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - deleteInventoryItem: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - deleteInventoryLevel: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - adjustInventory: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - confirmInventory: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - retrieveAvailableQuantity: jest.fn().mockImplementation((id, config) => { - return Promise.resolve(10) - }), - - retrieveStockedQuantity: jest.fn().mockImplementation((id, config) => { - return Promise.resolve(9) - }), - - retrieveReservedQuantity: jest.fn().mockImplementation((id, config) => { - return Promise.resolve(1) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return InventoryServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/invite.js b/packages/medusa/src/services/__mocks__/invite.js deleted file mode 100644 index 5d21174d72..0000000000 --- a/packages/medusa/src/services/__mocks__/invite.js +++ /dev/null @@ -1,27 +0,0 @@ -export const InviteServiceMock = { - withTransaction: function () { - return this - }, - - list: jest.fn().mockImplementation((selector, config) => { - return Promise.resolve({}) - }), - - create: jest.fn().mockImplementation(data => { - return Promise.resolve({}) - }), - - accept: jest.fn().mockImplementation((token, user_id) => { - return Promise.resolve({}) - }), - - resend: jest.fn().mockImplementation((id, inviter) => { - return Promise.resolve({}) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return InviteServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/line-item-adjustment.js b/packages/medusa/src/services/__mocks__/line-item-adjustment.js deleted file mode 100644 index 167b93a5d4..0000000000 --- a/packages/medusa/src/services/__mocks__/line-item-adjustment.js +++ /dev/null @@ -1,65 +0,0 @@ -export const LineItemAdjustmentServiceMock = { - withTransaction: function () { - return this - }, - create: jest.fn().mockImplementation((data) => { - return Promise.resolve({ ...data }) - }), - update: jest.fn().mockImplementation((data) => { - return Promise.resolve({ ...data }) - }), - validate: jest.fn().mockImplementation((data) => { - if (data.title === "invalid lineitem") { - throw new Error(`"content" is required`) - } - return data - }), - delete: jest.fn().mockImplementation((data) => { - return Promise.resolve({}) - }), - createAdjustmentForLineItem: jest - .fn() - .mockImplementation((cart, lineItem) => { - return Promise.resolve({ - item_id: lineItem.id, - amount: 1000, - discount_id: "disc_2", - id: "lia-1", - description: "discount", - }) - }), - createAdjustments: jest.fn().mockImplementation((cart, lineItem) => { - if (lineItem) { - return Promise.resolve({ - item_id: lineItem.id, - amount: 1000, - discount_id: "disc_2", - id: "lia-1", - description: "discount", - }) - } - - return Promise.resolve([ - { - item_id: "li-1", - amount: 200, - discount_id: "disc_2", - id: "lia-1", - description: "discount", - }, - { - item_id: "li-3", - amount: 100, - discount_id: "disc_3", - id: "lia-2", - description: "discount", - }, - ]) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return LineItemAdjustmentServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/line-item.js b/packages/medusa/src/services/__mocks__/line-item.js deleted file mode 100644 index d71b950e9c..0000000000 --- a/packages/medusa/src/services/__mocks__/line-item.js +++ /dev/null @@ -1,71 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import { MedusaError } from "medusa-core-utils" - -export const LineItemServiceMock = { - withTransaction: function () { - return this - }, - list: jest.fn().mockImplementation((data) => { - return Promise.resolve([]) - }), - retrieve: jest.fn().mockImplementation((id) => { - return Promise.resolve({}) - }), - create: jest.fn().mockImplementation((data) => { - return Promise.resolve({ ...data }) - }), - update: jest.fn().mockImplementation((data) => { - return Promise.resolve({ ...data }) - }), - validate: jest.fn().mockImplementation((data) => { - if (data.title === "invalid lineitem") { - throw new Error(`"content" is required`) - } - return data - }), - isEqual: jest.fn().mockImplementation((line, match) => { - if (Array.isArray(line.content)) { - if ( - Array.isArray(match.content) && - match.content.length === line.content.length - ) { - return line.content.every( - (c, index) => - c.variant.id === match[index].variant.id && - c.quantity === match[index].quantity - ) - } - } else if (!Array.isArray(match.content)) { - return ( - line.content.variant.id === match.content.variant.id && - line.content.quantity === match.content.quantity - ) - } - - return false - }), - generate: jest - .fn() - .mockImplementation((variantId, regionId, quantity, metadata = {}) => { - if ( - variantId === IdMap.getId("fail") || - regionId === IdMap.getId("fail") - ) { - throw new MedusaError(MedusaError.Types.INVALID_DATA, "Doesn't exist") - } - - return Promise.resolve({ - variant_id: variantId, - unit_price: 100, - quantity, - ...metadata, - }) - }), - delete: jest.fn().mockImplementation(() => Promise.resolve()), -} - -const mock = jest.fn().mockImplementation(() => { - return LineItemServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/new-totals.js b/packages/medusa/src/services/__mocks__/new-totals.js deleted file mode 100644 index bf7af612b8..0000000000 --- a/packages/medusa/src/services/__mocks__/new-totals.js +++ /dev/null @@ -1,44 +0,0 @@ -const NewTotalsService = require("../new-totals") - -export const newTotalsServiceMock = { - withTransaction: function () { - return this - }, - getLineItemTotals: jest.fn().mockImplementation(() => { - return Promise.resolve({}) - }), - getGiftCardTotals: jest.fn().mockImplementation((order, lineItems) => { - return Promise.resolve({}) - }), - getGiftCardTransactionsTotals: jest - .fn() - .mockImplementation((order, lineItems) => { - return Promise.resolve({}) - }), - getShippingMethodTotals: jest.fn().mockImplementation((order, lineItems) => { - return Promise.resolve({}) - }), - getGiftCardableAmount: jest - .fn() - .mockImplementation( - ({ - gift_cards_taxable, - subtotal, - shipping_total, - discount_total, - tax_total, - }) => { - return Promise.resolve( - (gift_cards_taxable - ? subtotal + shipping_total - discount_total - : subtotal + shipping_total + tax_total - discount_total) || 0 - ) - } - ), -} - -const mock = jest.fn().mockImplementation(() => { - return newTotalsServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/order-edit-item-change.js b/packages/medusa/src/services/__mocks__/order-edit-item-change.js deleted file mode 100644 index bda9e2e870..0000000000 --- a/packages/medusa/src/services/__mocks__/order-edit-item-change.js +++ /dev/null @@ -1,31 +0,0 @@ -export const orderEditItemChangeServiceMock = { - withTransaction: function () { - return this - }, - retrieveItemChangeByOrderEdit: jest - .fn() - .mockImplementation((itemChangeId, orderEditId) => { - return Promise.resolve({ - id: itemChangeId, - order_edit_id: orderEditId, - }) - }), - create: jest.fn().mockImplementation((data) => { - return Promise.resolve(data) - }), - delete: jest.fn().mockImplementation(() => { - return Promise.resolve() - }), - create: jest.fn().mockImplementation(() => { - return Promise.resolve({}) - }), - list: jest.fn().mockImplementation(() => { - return Promise.resolve([]) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return orderEditItemChangeServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/order-edit.js b/packages/medusa/src/services/__mocks__/order-edit.js deleted file mode 100644 index fedf0787ce..0000000000 --- a/packages/medusa/src/services/__mocks__/order-edit.js +++ /dev/null @@ -1,161 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const orderEdit = { - id: IdMap.getId("testCreatedOrder"), - order_id: IdMap.getId("test-order"), - internal_note: "internal note", - declined_reason: null, - declined_at: null, - declined_by: null, - canceled_at: null, - canceled_by: null, - requested_at: null, - requested_by: null, - created_at: new Date(), - created_by: "admin_user", - confirmed_at: null, - confirmed_by: null, -} - -const computeLineItems = (orderEdit) => ({ - ...orderEdit, - items: [ - { - id: IdMap.getId("existingLine"), - title: "merge line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - content: { - unit_price: 123, - variant: { - id: IdMap.getId("can-cover"), - }, - product: { - id: IdMap.getId("validId"), - }, - quantity: 1, - }, - quantity: 10, - }, - ], - removedItems: [], -}) -export const orderEditServiceMock = { - withTransaction: function () { - return this - }, - retrieve: jest.fn().mockImplementation((orderId) => { - if (orderId === IdMap.getId("testCreatedOrder")) { - return Promise.resolve(orderEdit) - } - if (orderId === IdMap.getId("testConfirmOrderEdit")) { - return Promise.resolve({ - ...orderEdit, - id: IdMap.getId("testConfirmOrderEdit"), - confirmed_at: new Date(), - confirmed_by: "admin_user", - status: "confirmed", - }) - } - if (orderId === IdMap.getId("testDeclineOrderEdit")) { - return Promise.resolve({ - ...orderEdit, - id: IdMap.getId("testDeclineOrderEdit"), - declined_reason: "Wrong size", - declined_at: new Date(), - status: "declined", - }) - } - if (orderId === IdMap.getId("testCompleteOrderEdit")) { - return Promise.resolve({ - ...orderEdit, - id: IdMap.getId("testCompleteOrderEdit"), - confirmed_at: new Date(), - status: "completed", - }) - } - if (orderId === IdMap.getId("testCancelOrderEdit")) { - return Promise.resolve({ - ...orderEdit, - id: orderId, - canceled_at: new Date(), - status: "canceled", - }) - } - if (orderId === IdMap.getId("testRequestOrder")) { - return Promise.resolve({ - ...orderEdit, - id: IdMap.getId("testRequestOrder"), - requested_by: IdMap.getId("admin_user"), - requested_at: new Date(), - status: "requested", - }) - } - return Promise.resolve(undefined) - }), - listAndCount: jest.fn().mockImplementation(() => { - return Promise.resolve([[orderEdit], 1]) - }), - computeLineItems: jest.fn().mockImplementation((orderEdit) => { - return Promise.resolve(computeLineItems(orderEdit)) - }), - create: jest.fn().mockImplementation((data, context) => { - return Promise.resolve({ - order_id: data.order_id, - internal_note: data.internal_note, - created_by: context.loggedInUserId, - }) - }), - update: jest.fn().mockImplementation((id, data) => { - return Promise.resolve(data) - }), - decline: jest.fn().mockImplementation((id, reason, userId) => { - return Promise.resolve({ - id, - declined_reason: reason, - declined_by: userId, - declined_at: new Date(), - }) - }), - delete: jest.fn().mockImplementation((_) => { - return Promise.resolve() - }), - decorateTotals: jest.fn().mockImplementation((orderEdit) => { - const withLineItems = computeLineItems(orderEdit) - return Promise.resolve({ - ...withLineItems, - }) - }), - deleteItemChange: jest.fn().mockImplementation((_) => { - return Promise.resolve() - }), - requestConfirmation: jest.fn().mockImplementation((orderEditId, userId) => { - return Promise.resolve({ - ...orderEdit, - id: orderEditId, - requested_at: new Date(), - requested_by: userId, - }) - }), - cancel: jest.fn().mockImplementation(() => { - return Promise.resolve({}) - }), - confirm: jest.fn().mockImplementation(() => { - return Promise.resolve({}) - }), - complete: jest.fn().mockImplementation(() => { - return Promise.resolve({}) - }), - updateLineItem: jest.fn().mockImplementation((_) => { - return Promise.resolve() - }), - removeLineItem: jest.fn().mockImplementation((_) => { - return Promise.resolve() - }), -} - -const mock = jest.fn().mockImplementation(() => { - return orderEditServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/order.js b/packages/medusa/src/services/__mocks__/order.js deleted file mode 100644 index 0aa252803a..0000000000 --- a/packages/medusa/src/services/__mocks__/order.js +++ /dev/null @@ -1,245 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const orders = { - testOrder: { - id: IdMap.getId("test-order"), - email: "virgil@vandijk.dk", - sales_channel_id: "test-channel", - sales_channel: { - id: "test-channel", - }, - billing_address: { - first_name: "Virgil", - last_name: "Van Dijk", - address_1: "24 Dunks Drive", - city: "Los Angeles", - country_code: "US", - province: "CA", - postal_code: "93011", - }, - shipping_address: { - first_name: "Virgil", - last_name: "Van Dijk", - address_1: "24 Dunks Drive", - city: "Los Angeles", - country_code: "US", - province: "CA", - postal_code: "93011", - }, - items: [ - { - id: IdMap.getId("existingLine"), - title: "merge line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - content: { - unit_price: 123, - variant: { - id: IdMap.getId("can-cover"), - }, - product: { - id: IdMap.getId("validId"), - }, - quantity: 1, - }, - quantity: 10, - }, - ], - regionid: IdMap.getId("testRegion"), - currency_code: "USD", - customerid: IdMap.getId("testCustomer"), - fulfillments: [], - payment_method: { - providerid: "default_provider", - data: {}, - }, - no_notification: true, - shipping_method: [ - { - providerid: "default_provider", - profileid: IdMap.getId("validId"), - data: {}, - items: {}, - }, - ], - }, - processedOrder: { - id: IdMap.getId("processed-order"), - email: "oliver@test.dk", - billing_address: { - first_name: "Oli", - last_name: "Medusa", - address_1: "testaddress", - city: "LA", - country_code: "US", - postal_code: "90002", - }, - shipping_address: { - first_name: "Oli", - last_name: "Medusa", - address_1: "testaddress", - city: "LA", - country_code: "US", - postal_code: "90002", - }, - items: [ - { - id: IdMap.getId("existingLine"), - title: "merge line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - content: { - unit_price: 123, - variant: { - id: IdMap.getId("can-cover"), - }, - product: { - id: IdMap.getId("validId"), - }, - quantity: 1, - }, - quantity: 10, - }, - ], - regionid: IdMap.getId("region-france"), - currency_code: "EUR", - customerid: IdMap.getId("test-customer"), - payment_method: { - providerid: "default_provider", - }, - no_notification: false, - shipping_methods: [ - { - id: IdMap.getId("expensiveShipping"), - name: "Expensive Shipping", - price: 100, - providerid: "default_provider", - profileid: IdMap.getId("default"), - }, - { - id: IdMap.getId("freeShipping"), - name: "Free Shipping", - price: 10, - providerid: "default_provider", - profileid: IdMap.getId("profile1"), - }, - ], - tax_rate: 0, - fulfillment_status: "fulfilled", - payment_status: "captured", - status: "completed", - }, -} - -export const OrderServiceMock = { - withTransaction: function () { - return this - }, - - create: jest.fn().mockImplementation((data) => { - return Promise.resolve(orders.testOrder) - }), - registerReturnReceived: jest.fn().mockImplementation((data) => { - return Promise.resolve() - }), - createFromCart: jest.fn().mockImplementation((data) => { - return Promise.resolve(orders.testOrder) - }), - update: jest.fn().mockImplementation((data) => { - if (data === IdMap.getId("test-order")) { - return Promise.resolve(orders.testOrder) - } - if (data === IdMap.getId("processed-order")) { - return Promise.resolve(orders.processedOrder) - } - return Promise.resolve(undefined) - }), - setMetadata: jest.fn().mockImplementation((id, key, value) => { - if (id === IdMap.getId("test-order")) { - return Promise.resolve(orders.testOrder) - } - return Promise.resolve(undefined) - }), - deleteMetadata: jest.fn().mockImplementation((id, key, value) => { - if (id === IdMap.getId("test-order")) { - return Promise.resolve(orders.testOrder) - } - return Promise.resolve(undefined) - }), - retrieve: jest.fn().mockImplementation((orderId) => { - if (orderId === IdMap.getId("test-order")) { - return Promise.resolve(orders.testOrder) - } - if (orderId === IdMap.getId("processed-order")) { - return Promise.resolve(orders.processedOrder) - } - return Promise.resolve(undefined) - }), - retrieveWithTotals: jest.fn().mockImplementation((orderId) => { - if (orderId === IdMap.getId("test-order")) { - return Promise.resolve(orders.testOrder) - } - if (orderId === IdMap.getId("processed-order")) { - return Promise.resolve(orders.processedOrder) - } - return Promise.resolve(undefined) - }), - retrieveByCartId: jest.fn().mockImplementation((cartId) => { - return Promise.resolve({ id: IdMap.getId("test-order") }) - }), - retrieveByCartIdWithTotals: jest.fn().mockImplementation((cartId) => { - return Promise.resolve({ id: IdMap.getId("test-order") }) - }), - decorate: jest.fn().mockImplementation((order) => { - order.decorated = true - return order - }), - cancel: jest.fn().mockImplementation((order) => { - if (order === IdMap.getId("test-order")) { - orders.testOrder.status = "cancelled" - return Promise.resolve(orders.testOrder) - } - return Promise.resolve(undefined) - }), - - cancelFulfillment: jest.fn().mockImplementation((f) => { - return Promise.resolve({ f }) - }), - - archive: jest.fn().mockImplementation((order) => { - if (order === IdMap.getId("processed-order")) { - orders.processedOrder.status = "archived" - return Promise.resolve(orders.processedOrder) - } - return Promise.resolve(undefined) - }), - createFulfillment: jest.fn().mockImplementation((order) => { - if (order === IdMap.getId("test-order")) { - orders.testOrder.fulfillment_status = "fulfilled" - return Promise.resolve(orders.testOrder) - } - return Promise.resolve(undefined) - }), - capturePayment: jest.fn().mockImplementation((order) => { - if (order === IdMap.getId("test-order")) { - orders.testOrder.payment_status = "captured" - return Promise.resolve(orders.testOrder) - } - return Promise.resolve(undefined) - }), - receiveReturn: jest.fn().mockImplementation((order) => { - if (order === IdMap.getId("test-order")) { - return Promise.resolve(orders.testOrder) - } - return Promise.resolve(undefined) - }), - list: jest.fn().mockImplementation(() => { - return Promise.resolve([orders.testOrder]) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return OrderServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/payment-collection.js b/packages/medusa/src/services/__mocks__/payment-collection.js deleted file mode 100644 index 6a5845613d..0000000000 --- a/packages/medusa/src/services/__mocks__/payment-collection.js +++ /dev/null @@ -1,17 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const PaymentCollectionServiceMock = { - withTransaction: function () { - return this - }, - create: jest.fn().mockImplementation((data) => { - const id = data.id ?? IdMap.getId("paycol_1") - return Promise.resolve({ ...data, id }) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return PaymentCollectionServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/payment-provider.js b/packages/medusa/src/services/__mocks__/payment-provider.js deleted file mode 100644 index 8c2236a45b..0000000000 --- a/packages/medusa/src/services/__mocks__/payment-provider.js +++ /dev/null @@ -1,82 +0,0 @@ -import { isString } from "../../utils"; - -export const DefaultProviderMock = { - getStatus: jest.fn().mockImplementation((data) => { - if (data.money_id === "success") { - return Promise.resolve("authorized") - } - - if (data.money_id === "fail") { - return Promise.resolve("fail") - } - - return Promise.resolve("initial") - }), - retrievePayment: jest.fn().mockImplementation((data) => { - return Promise.resolve(data) - }), - list: jest.fn().mockImplementation(() => { - return Promise.resolve() - }), - capturePayment: jest.fn().mockReturnValue(Promise.resolve()), - refundPayment: jest.fn().mockReturnValue(Promise.resolve()), - cancelPayment: jest.fn().mockReturnValue(Promise.resolve({})), - deletePayment: jest.fn().mockReturnValue(Promise.resolve({})), - authorizePayment: jest.fn().mockReturnValue(Promise.resolve({})), -} - -export const PaymentProviderServiceMock = { - withTransaction: function () { - return this - }, - updateSession: jest.fn().mockImplementation((session, cart) => { - return Promise.resolve({ - ...session, - id: `${session.id}_updated`, - }) - }), - list: jest.fn().mockImplementation(() => { - return Promise.resolve() - }), - registerInstalledProviders: jest.fn().mockImplementation(() => { - return Promise.resolve() - }), - createSession: jest.fn().mockImplementation((providerIdOrSessionInput, cart) => { - if (isString(providerIdOrSessionInput)) { - return Promise.resolve({ - id: `${providerIdOrSessionInput}_session`, - cartId: cart._id, - }) - } else { - return Promise.resolve({ - id: `${providerIdOrSessionInput.providerId}_session`, - }) - } - }), - retrieveProvider: jest.fn().mockImplementation((providerId) => { - if (providerId === "default_provider") { - return DefaultProviderMock - } - throw new Error("Provider Not Found") - }), - refreshSession: jest.fn().mockImplementation((session, inputData) => { - DefaultProviderMock.deletePayment() - PaymentProviderServiceMock.createSession(inputData) - return Promise.resolve({ - ...session, - id: `${session.id}_refreshed`, - }) - }), - authorizePayment: jest - .fn() - .mockReturnValue(Promise.resolve({ status: "authorized" })), - createPayment: jest.fn().mockImplementation((session, inputData) => { - Promise.resolve(inputData) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return PaymentProviderServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/payment.js b/packages/medusa/src/services/__mocks__/payment.js deleted file mode 100644 index dd53e15436..0000000000 --- a/packages/medusa/src/services/__mocks__/payment.js +++ /dev/null @@ -1,15 +0,0 @@ -export const PaymentServiceMock = { - withTransaction: function () { - return this - }, - create: jest.fn().mockImplementation((data) => { - const id = data.id ?? IdMap.getId("pay_1") - return Promise.resolve({ ...data, id }) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return PaymentServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/price-list.js b/packages/medusa/src/services/__mocks__/price-list.js deleted file mode 100644 index 214a34bc4a..0000000000 --- a/packages/medusa/src/services/__mocks__/price-list.js +++ /dev/null @@ -1,43 +0,0 @@ -export const PriceListServiceMock = { - withTransaction: function() { - return this - }, - - create: jest.fn().mockImplementation((f) => { - return Promise.resolve(f) - }), - - retrieve: jest.fn().mockImplementation((f) => { - return Promise.resolve(f) - }), - - update: jest.fn().mockImplementation((id, update) => { - return Promise.resolve({ id, ...update }) - }), - - delete: jest.fn().mockImplementation((id) => { - return Promise.resolve(id) - }), - - addPrices: jest.fn().mockImplementation((id, prices) => { - return Promise.resolve({ id, prices }) - }), - - deletePrices: jest.fn().mockImplementation((id, prices) => { - return Promise.resolve({ id, prices }) - }), - - listAndCount: jest.fn().mockImplementation((fields, config) => { - return Promise.resolve([[{ id: "pl_1" }, { id: "pl_2" }], 2]) - }), - - upsertCustomerGroups_: jest.fn().mockImplementation((id, groups) => { - return Promise.resolve() - }), -} - -const mock = jest.fn().mockImplementation(() => { - return PriceListServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/pricing.js b/packages/medusa/src/services/__mocks__/pricing.js deleted file mode 100644 index 05608a4340..0000000000 --- a/packages/medusa/src/services/__mocks__/pricing.js +++ /dev/null @@ -1,26 +0,0 @@ -export const PricingServiceMock = { - withTransaction: function () { - return this - }, - setProductPrices: jest.fn().mockImplementation((prod) => { - return Promise.resolve(prod) - }), - setAdminProductPricing: jest.fn().mockImplementation((prod) => { - return Promise.resolve(prod) - }), - setVariantPrices: jest.fn().mockImplementation(([variant]) => { - return Promise.resolve([variant]) - }), - setAdminVariantPricing: jest.fn().mockImplementation(([variant]) => { - return Promise.resolve([variant]) - }), - setShippingOptionPrices: jest.fn().mockImplementation((opts) => { - return Promise.resolve(opts) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return PricingServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/product-category.js b/packages/medusa/src/services/__mocks__/product-category.js deleted file mode 100644 index 4c0b403782..0000000000 --- a/packages/medusa/src/services/__mocks__/product-category.js +++ /dev/null @@ -1,43 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { IdMap } from "medusa-test-utils" - -export const validProdCategoryId = "skinny-jeans" -export const invalidProdCategoryId = "not-found" - -export const ProductCategoryServiceMock = { - withTransaction: function () { - return this - }, - create: jest.fn().mockImplementation((data) => { - return Promise.resolve({ id: IdMap.getId(validProdCategoryId), ...data }) - }), - retrieve: jest.fn().mockImplementation((id) => { - if (id === IdMap.getId(invalidProdCategoryId)) { - throw new MedusaError(MedusaError.Types.NOT_FOUND, "ProductCategory not found") - } - - if (id === IdMap.getId(validProdCategoryId)) { - return Promise.resolve({ id: IdMap.getId(validProdCategoryId) }) - } - }), - delete: jest.fn().mockReturnValue(Promise.resolve()), - update: jest.fn().mockImplementation((id, data) => { - if (id === IdMap.getId(invalidProdCategoryId)) { - throw new MedusaError(MedusaError.Types.NOT_FOUND, "ProductCategory not found") - } - - return Promise.resolve(Object.assign({ id }, data)) - }), - list: jest.fn().mockImplementation((data) => { - return Promise.resolve([{ id: IdMap.getId(validProdCategoryId) }]) - }), - listAndCount: jest.fn().mockImplementation((data) => { - return Promise.resolve([[{ id: IdMap.getId(validProdCategoryId) }], 1]) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return ProductCategoryServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/product-collection.js b/packages/medusa/src/services/__mocks__/product-collection.js deleted file mode 100644 index 94e0c43fab..0000000000 --- a/packages/medusa/src/services/__mocks__/product-collection.js +++ /dev/null @@ -1,45 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { IdMap } from "medusa-test-utils" - -export const ProductCollectionServiceMock = { - withTransaction: function () { - return this - }, - create: jest.fn().mockImplementation((data) => { - return Promise.resolve({ id: IdMap.getId("col"), ...data }) - }), - retrieve: jest.fn().mockImplementation((id) => { - if (id === IdMap.getId("col")) { - return Promise.resolve({ id: IdMap.getId("col"), title: "Suits" }) - } - }), - delete: jest.fn().mockReturnValue(Promise.resolve()), - update: jest.fn().mockImplementation((id, value) => { - return Promise.resolve({ id, title: value }) - }), - addProducts: jest.fn().mockImplementation((id, product_ids) => { - if (id === IdMap.getId("col")) { - return Promise.resolve({ - id, - products: product_ids.map((i) => ({ id: i })), - }) - } - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Product collection with id: ${id} was not found` - ) - }), - removeProducts: jest.fn().mockReturnValue(Promise.resolve()), - list: jest.fn().mockImplementation((data) => { - return Promise.resolve([{ id: IdMap.getId("col"), title: "Suits" }]) - }), - listAndCount: jest.fn().mockImplementation((data) => { - return Promise.resolve([[{ id: IdMap.getId("col"), title: "Suits" }], 1]) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return ProductCollectionServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/product-variant-inventory.js b/packages/medusa/src/services/__mocks__/product-variant-inventory.js deleted file mode 100644 index f30feb4663..0000000000 --- a/packages/medusa/src/services/__mocks__/product-variant-inventory.js +++ /dev/null @@ -1,41 +0,0 @@ -import { MedusaError } from "medusa-core-utils" - -export const ProductVariantInventoryServiceMock = { - withTransaction: function () { - return this - }, - adjustInventory: jest.fn().mockReturnValue((_variantId, _quantity) => { - return Promise.resolve({}) - }), - confirmInventory: jest - .fn() - .mockImplementation((variantId, quantity, options) => { - return quantity < 10 - }), - adjustReservationsQuantityByLineItem: jest - .fn() - .mockImplementation((lineItem) => {}), - deleteReservationsByLineItem: jest.fn().mockImplementation((lineItem) => {}), - reserveQuantity: jest - .fn() - .mockImplementation((variantId, quantity, options) => {}), - validateInventoryAtLocation: jest - .fn() - .mockImplementation((items, locationId) => {}), - setVariantAvailability: jest - .fn() - .mockImplementation((variants, salesChannelId) => { - return variants - }), - setProductAvailability: jest - .fn() - .mockImplementation((products, salesChannelId) => { - return products - }), -} - -const mock = jest.fn().mockImplementation(() => { - return ProductVariantInventoryServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/product-variant.js b/packages/medusa/src/services/__mocks__/product-variant.js deleted file mode 100644 index 3d4d870d9f..0000000000 --- a/packages/medusa/src/services/__mocks__/product-variant.js +++ /dev/null @@ -1,328 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -const variant1 = { - id: "1", - title: "variant1", - options: [ - { - option_id: IdMap.getId("color_id"), - value: "blue", - }, - { - option_id: IdMap.getId("size_id"), - value: "160", - }, - ], -} - -const variant2 = { - id: "2", - title: "variant2", - options: [ - { - option_id: IdMap.getId("color_id"), - value: "black", - }, - { - option_id: IdMap.getId("size_id"), - value: "160", - }, - ], -} - -const variant3 = { - id: "3", - title: "variant3", - options: [ - { - option_id: IdMap.getId("color_id"), - value: "blue", - }, - { - option_id: IdMap.getId("size_id"), - value: "150", - }, - ], -} - -const variant4 = { - id: "4", - title: "variant4", - options: [ - { - option_id: IdMap.getId("color_id"), - value: "blue", - }, - { - option_id: IdMap.getId("size_id"), - value: "50", - }, - ], -} - -const variant5 = { - id: "5", - title: "Variant with valid id", - options: [ - { - option_id: IdMap.getId("color_id"), - value: "blue", - }, - { - option_id: IdMap.getId("size_id"), - value: "50", - }, - ], -} - -const invalidVariant = { - id: "invalid_option", - title: "variant3", - options: [ - { - option_id: "invalid_id", - value: "blue", - }, - { - option_id: IdMap.getId("size_id"), - value: "150", - }, - ], -} - -const variantWithPrices = { - id: "variant_with_prices", - title: "Variant with prices", - prices: [ - { - id: "price_1", - currency_code: "usd", - amount: 100, - price_list_id: null, - min_quantity: 1, - max_quantity: 10, - variant_id: "variant_with_prices", - region_id: null, - created_at: "2021-03-16T21:24:13.657Z", - updated_at: "2021-03-16T21:24:13.657Z", - deleted_at: null, - }, - { - id: "price_2", - currency_code: "dk", - amount: 100, - price_list_id: null, - min_quantity: 1, - max_quantity: 10, - variant_id: "variant_with_prices", - region_id: null, - created_at: "2021-03-16T21:24:13.657Z", - updated_at: "2021-03-16T21:24:13.657Z", - deleted_at: null, - }, - ], -} - -const testVariant = { - id: IdMap.getId("testVariant"), - title: "test variant", -} - -const emptyVariant = { - id: "empty_option", - title: "variant3", - options: [], -} - -const eur10us12 = { - id: IdMap.getId("eur-10-us-12"), - title: "EUR10US-12", -} - -const giftCardVar = { - id: IdMap.getId("giftCardVar"), - title: "100 USD", -} - -const outOfStockBackOrder = { - id: "bo", - title: "variant_popular", - inventory_quantity: 0, - allow_backorder: true, - manage_inventory: true, -} - -const outOfStockNoBackOrder = { - id: "no_bo", - title: "variant_popular", - inventory_quantity: 0, - allow_backorder: false, - manage_inventory: true, -} - -const outOfStockNoManage = { - id: "no_manage", - title: "variant_popular", - inventory_quantity: 0, - allow_backorder: false, - manage_inventory: false, -} - -const StockOf10Manage = { - id: "10_man", - title: "variant_popular", - inventory_quantity: 10, - allow_backorder: false, - manage_inventory: true, -} - -const StockOf1Manage = { - id: "1_man", - title: "variant_popular", - inventory_quantity: 1, - allow_backorder: false, - manage_inventory: true, -} - -export const variants = { - one: variant1, - two: variant2, - three: variant3, - four: variant4, - invalid_variant: invalidVariant, - empty_variant: emptyVariant, - eur10us12: eur10us12, - testVariant: testVariant, - giftCard: giftCardVar, - variantWithPrices: variantWithPrices, -} - -export const ProductVariantServiceMock = { - withTransaction: function() { - return this - }, - create: jest.fn().mockImplementation(data => { - return Promise.resolve(testVariant) - }), - publish: jest.fn().mockImplementation(_ => { - return Promise.resolve({ - id: IdMap.getId("publish"), - name: "Product Variant", - published: true, - }) - }), - retrieve: jest.fn().mockImplementation(variantId => { - if (variantId === IdMap.getId("giftCardVar")) { - return Promise.resolve(variants.giftCard) - } - if (variantId === "1") { - return Promise.resolve(variant1) - } - if (variantId === "2") { - return Promise.resolve(variant2) - } - if (variantId === "3") { - return Promise.resolve(variant3) - } - if (variantId === "4") { - return Promise.resolve(variant4) - } - if (variantId === "variant_with_prices") { - return Promise.resolve(variantWithPrices) - } - if (variantId === IdMap.getId("validId")) { - return Promise.resolve(variant5) - } - if (variantId === IdMap.getId("testVariant")) { - return Promise.resolve(testVariant) - } - if (variantId === "invalid_option") { - return Promise.resolve(invalidVariant) - } - if (variantId === "empty_option") { - return Promise.resolve(emptyVariant) - } - if (variantId === IdMap.getId("eur-10-us-12")) { - return Promise.resolve(eur10us12) - } - if (variantId === IdMap.getId("testVariant")) { - return Promise.resolve(testVariant) - } - if (variantId === "bo") { - return Promise.resolve(outOfStockBackOrder) - } - if (variantId === "no_bo") { - return Promise.resolve(outOfStockNoBackOrder) - } - if (variantId === "no_manage") { - return Promise.resolve(outOfStockNoManage) - } - if (variantId === "10_man") { - return Promise.resolve(StockOf10Manage) - } - if (variantId === "1_man") { - return Promise.resolve(StockOf1Manage) - } - }), - getRegionPrice: jest.fn().mockImplementation((variantId, regionId) => { - if (variantId === IdMap.getId("eur-10-us-12")) { - if (regionId === IdMap.getId("region-france")) { - return Promise.resolve(10) - } else { - return Promise.resolve(12) - } - } - - if (variantId === IdMap.getId("eur-8-us-10")) { - if (regionId === IdMap.getId("region-france")) { - return Promise.resolve(8) - } else { - return Promise.resolve(10) - } - } - - if (variantId === IdMap.getId("giftCardVar")) { - return Promise.resolve(100) - } - - return Promise.reject(new Error("Not found")) - }), - delete: jest.fn().mockReturnValue(Promise.resolve()), - update: jest.fn().mockReturnValue(Promise.resolve()), - updateVariantPrices: jest.fn().mockImplementation((variantId, prices) => { - return Promise.resolve({}) - }), - deleteVariantPrices: jest.fn().mockImplementation((variantId, priceIds) => { - return Promise.resolve({}) - }), - updateOptionValue: jest.fn().mockReturnValue(Promise.resolve()), - addOptionValue: jest.fn().mockImplementation((variantId, optionId, value) => { - return Promise.resolve({}) - }), - list: jest.fn().mockImplementation(data => { - return Promise.resolve([testVariant]) - }), - listAndCount: jest.fn().mockImplementation(({ product_id }) => { - if (product_id === IdMap.getId("product1")) { - return Promise.resolve( [ - [ - { id: IdMap.getId("1"), product_id: IdMap.getId("product1") }, - { id: IdMap.getId("2"), product_id: IdMap.getId("product1") } - ], - 2 - ], - ) - } - - return [] - }), - deleteOptionValue: jest.fn().mockImplementation((variantId, optionId) => { - return Promise.resolve({}) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return ProductVariantServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/product.js b/packages/medusa/src/services/__mocks__/product.js deleted file mode 100644 index a00b5b2ce5..0000000000 --- a/packages/medusa/src/services/__mocks__/product.js +++ /dev/null @@ -1,222 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const products = { - product1: { - id: IdMap.getId("product1"), - title: "Product 1", - }, - publishProduct: { - id: IdMap.getId("publish"), - title: "Product 1", - published: true, - }, - product2: { - id: IdMap.getId("product2"), - title: "Product 2", - }, - productWithOptions: { - id: IdMap.getId("productWithOptions"), - title: "Test", - variants: [IdMap.getId("variant1")], - options: [ - { - id: IdMap.getId("option1"), - title: "Test", - values: [IdMap.getId("optionValue1")], - }, - ], - }, - variantsWithPrices: { - id: IdMap.getId("variantsWithPrices"), - title: "Variant with prices", - variants: [ - { - id: IdMap.getId("variant_with_prices"), - title: "Variant with prices", - prices: [ - { - id: "price_1", - currency_code: "usd", - amount: 100, - sale_amount: null, - variant_id: "variant_with_prices", - region_id: null, - created_at: "2021-03-16T21:24:13.657Z", - updated_at: "2021-03-16T21:24:13.657Z", - deleted_at: null, - }, - { - id: "price_2", - currency_code: "dk", - amount: 100, - sale_amount: null, - variant_id: "variant_with_prices", - region_id: null, - created_at: "2021-03-16T21:24:13.657Z", - updated_at: "2021-03-16T21:24:13.657Z", - deleted_at: null, - }, - ], - }, - ], - }, - multipleVariants: { - id: IdMap.getId("multipleVariants"), - title: "Multiple Variants", - variants: [ - { - id: IdMap.getId("variant_1"), - title: "Variant 1", - }, - { - id: IdMap.getId("variant_2"), - title: "Variant 2", - }, - { - id: IdMap.getId("variant_3"), - title: "Variant 3", - }, - ], - }, -} - -export const ProductServiceMock = { - withTransaction: function () { - return this - }, - create: jest.fn().mockImplementation((data) => { - if (data.title === "Test Product") { - return Promise.resolve(products.product1) - } - if (data.title === "Test Product with variants") { - return Promise.resolve(products.productWithOptions) - } - return Promise.resolve({ ...data }) - }), - count: jest.fn().mockReturnValue(4), - publish: jest.fn().mockImplementation((_) => { - return Promise.resolve({ - id: IdMap.getId("publish"), - name: "Product 1", - published: true, - }) - }), - delete: jest.fn().mockImplementation((_) => { - return Promise.resolve() - }), - createVariant: jest.fn().mockImplementation((productId, value) => { - return Promise.resolve(products.productWithOptions) - }), - deleteVariant: jest.fn().mockImplementation((productId, variantId) => { - return Promise.resolve(products.productWithOptions) - }), - decorate: jest.fn().mockImplementation((product, fields) => { - product.decorated = true - return product - }), - addOption: jest.fn().mockImplementation((productId, optionTitle) => { - return Promise.resolve(products.productWithOptions) - }), - updateOption: jest - .fn() - .mockReturnValue(Promise.resolve(products.productWithOptions)), - updateOptionValue: jest.fn().mockReturnValue(Promise.resolve()), - deleteOption: jest - .fn() - .mockReturnValue(Promise.resolve(products.productWithOptions)), - updateshippingProfiles: jest.fn().mockReturnValue(Promise.resolve()), - retrieveVariants: jest.fn().mockImplementation((productId) => { - if (productId === IdMap.getId("product1")) { - return Promise.resolve([ - { id: IdMap.getId("1"), product_id: IdMap.getId("product1") }, - { id: IdMap.getId("2"), product_id: IdMap.getId("product1") }, - ]) - } - - return [] - }), - retrieve: jest.fn().mockImplementation((productId) => { - if (productId === IdMap.getId("product1")) { - return Promise.resolve(products.product1) - } - if (productId === IdMap.getId("product2")) { - return Promise.resolve(products.product2) - } - if (productId === IdMap.getId("validId")) { - return Promise.resolve({ id: IdMap.getId("validId") }) - } - if (productId === IdMap.getId("publish")) { - return Promise.resolve(products.publishProduct) - } - if (productId === IdMap.getId("productWithOptions")) { - return Promise.resolve(products.productWithOptions) - } - if (productId === IdMap.getId("variantsWithPrices")) { - return Promise.resolve(products.variantsWithPrices) - } - if (productId === IdMap.getId("multipleVariants")) { - return Promise.resolve(products.multipleVariants) - } - return Promise.resolve(undefined) - }), - update: jest.fn().mockImplementation((product, data) => { - return Promise.resolve(products.product1) - }), - listAndCount: jest.fn().mockImplementation((data) => { - if (data?.id?.includes("sales_channel_1_product_1")) { - return Promise.resolve([[{ id: "sales_channel_1_product_1" }], 1]) - } - return Promise.resolve([[products.product1, products.product2], 2]) - }), - list: jest.fn().mockImplementation((data) => { - // Used to retrieve a product based on a variant id see - // ProductVariantService.addOptionValue - if (data.variants === IdMap.getId("giftCardVar")) { - return Promise.resolve([ - { - id: IdMap.getId("giftCardProd"), - title: "Gift Card", - is_giftcard: true, - thumbnail: "1234", - }, - ]) - } - if (data.variants === IdMap.getId("testVariant")) { - return Promise.resolve([ - { - id: "1234", - title: "test", - options: [ - { - id: IdMap.getId("testOptionId"), - title: "testOption", - }, - ], - }, - ]) - } - if (data.variants === IdMap.getId("eur-10-us-12")) { - return Promise.resolve([ - { - id: "1234", - title: "test", - thumbnail: "test.1234", - }, - ]) - } - if (data.variants === IdMap.getId("failId")) { - return Promise.resolve([]) - } - - return Promise.resolve([ - { ...products.product1, decorated: true }, - { ...products.product2, decorated: true }, - ]) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return ProductServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/region.js b/packages/medusa/src/services/__mocks__/region.js deleted file mode 100644 index 41975e909e..0000000000 --- a/packages/medusa/src/services/__mocks__/region.js +++ /dev/null @@ -1,103 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const regions = { - testRegion: { - id: IdMap.getId("testRegion"), - name: "Test Region", - countries: ["DK", "US", "DE"], - tax_rate: 0.25, - payment_providers: ["default_provider", "unregistered"], - fulfillment_providers: ["test_shipper"], - currency_code: "usd", - }, - regionFrance: { - id: IdMap.getId("region-france"), - name: "France", - countries: ["FR"], - payment_providers: ["default_provider", "france-provider"], - fulfillment_providers: ["default_provider"], - currency_code: "eur", - tax_rate: 0.25, - }, - regionUs: { - id: IdMap.getId("region-us"), - tax_rate: 0.25, - name: "USA", - countries: ["US"], - currency_code: "usd", - }, - regionGermany: { - id: IdMap.getId("region-de"), - tax_rate: 0.25, - name: "Germany", - countries: ["DE"], - currency_code: "eur", - }, - regionSweden: { - id: IdMap.getId("region-se"), - tax_rate: 0.25, - name: "Sweden", - countries: ["SE"], - currency_code: "sek", - }, -} - -export const RegionServiceMock = { - withTransaction: function () { - return this - }, - retrieve: jest.fn().mockImplementation((regionId) => { - if (regionId === IdMap.getId("testRegion")) { - return Promise.resolve(regions.testRegion) - } - if (regionId === IdMap.getId("region-france")) { - return Promise.resolve(regions.regionFrance) - } - if (regionId === IdMap.getId("region-us")) { - return Promise.resolve(regions.regionUs) - } - if (regionId === IdMap.getId("region-de")) { - return Promise.resolve(regions.regionGermany) - } - if (regionId === IdMap.getId("region-se")) { - return Promise.resolve(regions.regionSweden) - } - return Promise.resolve(regions.testRegion) - }), - delete: jest.fn().mockImplementation((data) => Promise.resolve()), - create: jest - .fn() - .mockImplementation((data) => Promise.resolve({ id: "region" })), - addCountry: jest.fn().mockImplementation((data) => Promise.resolve()), - addFulfillmentProvider: jest - .fn() - .mockImplementation((data) => Promise.resolve()), - addPaymentProvider: jest.fn().mockImplementation((data) => Promise.resolve()), - removeCountry: jest.fn().mockImplementation((data) => Promise.resolve()), - removeFulfillmentProvider: jest - .fn() - .mockImplementation((data) => Promise.resolve()), - removePaymentProvider: jest - .fn() - .mockImplementation((data) => Promise.resolve()), - update: jest.fn().mockImplementation((data) => Promise.resolve()), - list: jest.fn().mockImplementation((data) => { - return Promise.resolve([ - regions.testRegion, - regions.regionFrance, - regions.regionUs, - ]) - }), - listAndCount: jest.fn().mockImplementation((data) => { - return Promise.resolve([ - [regions.testRegion, regions.regionFrance, regions.regionUs], - 3, - ]) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return RegionServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/return.js b/packages/medusa/src/services/__mocks__/return.js deleted file mode 100644 index 189adacfba..0000000000 --- a/packages/medusa/src/services/__mocks__/return.js +++ /dev/null @@ -1,23 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const ReturnService = { - withTransaction: function() { - return this - }, - create: jest.fn(() => Promise.resolve({ id: "return" })), - fulfill: jest.fn(), - update: jest.fn(), - receive: jest.fn(() => - Promise.resolve({ - id: IdMap.getId("test-return"), - order_id: IdMap.getId("test-order"), - }) - ), - retrieve: jest.fn(() => Promise.resolve("test-return")), -} - -const mock = jest.fn().mockImplementation(() => { - return ReturnService -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/sales-channel.js b/packages/medusa/src/services/__mocks__/sales-channel.js deleted file mode 100644 index bdb73be2a2..0000000000 --- a/packages/medusa/src/services/__mocks__/sales-channel.js +++ /dev/null @@ -1,74 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const SalesChannelServiceMock = { - withTransaction: function () { - return this - }, - - retrieve: jest.fn().mockImplementation((id, config) => { - return Promise.resolve({ - id: id, - name: "sales channel 1 name", - description: "sales channel 1 description", - is_disabled: false, - }) - }), - update: jest.fn().mockImplementation((id, data) => { - return Promise.resolve({ id, ...data }) - }), - - listAndCount: jest.fn().mockImplementation(() => { - return Promise.resolve([ - [ - { - id: IdMap.getId("sales_channel_1"), - name: "sales channel 1 name", - description: "sales channel 1 description", - is_disabled: false, - }, - ], - 1, - ]) - }), - - create: jest.fn().mockImplementation((data) => { - return Promise.resolve({ - id: id, - ...data, - }) - }), - - delete: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), - - createDefault: jest.fn().mockImplementation(() => { - return Promise.resolve({ - name: "sales channel 1 name", - description: "sales channel 1 description", - is_disabled: false, - }) - }), - - retrieveDefault: jest.fn().mockImplementation(() => { - return Promise.resolve({ - name: "sales channel 1 name", - description: "sales channel 1 description", - is_disabled: false, - }) - }), - - removeProducts: jest.fn().mockImplementation((id, productIds) => { - return Promise.resolve() - }), - - addProducts: jest.fn().mockImplementation((id, productIds) => { - return Promise.resolve() - }), -} - -const mock = jest.fn().mockImplementation(() => { - return SalesChannelServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/search.js b/packages/medusa/src/services/__mocks__/search.js deleted file mode 100644 index bf1fff131f..0000000000 --- a/packages/medusa/src/services/__mocks__/search.js +++ /dev/null @@ -1,9 +0,0 @@ -export const SearchServiceMock = { - search: jest.fn(() => Promise.resolve([])), -} - -const mock = jest.fn().mockImplementation(() => { - return SearchServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/shipping-option.js b/packages/medusa/src/services/__mocks__/shipping-option.js deleted file mode 100644 index c68d3658ad..0000000000 --- a/packages/medusa/src/services/__mocks__/shipping-option.js +++ /dev/null @@ -1,166 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const shippingOptions = { - returnShipping: { - _id: IdMap.getId("return-shipping"), - is_return: true, - name: "Return Shipping", - region_id: IdMap.getId("region-france"), - profile_id: IdMap.getId("default-profile"), - data: { - id: "return_shipment", - }, - price: { - type: "flat_rate", - amount: 20, - }, - provider_id: "default_provider", - }, - freeShipping: { - _id: IdMap.getId("freeShipping"), - name: "Free Shipping", - region_id: IdMap.getId("testRegion"), - profile_id: IdMap.getId("default-profile"), - data: { - id: "fs", - }, - price: { - type: "flat_rate", - amount: 10, - }, - provider_id: "test_shipper", - }, - expensiveShipping: { - _id: IdMap.getId("expensiveShipping"), - name: "Expensive Shipping", - profile_id: IdMap.getId("fragile-profile"), - region_id: IdMap.getId("testRegion"), - data: { - id: "es", - }, - price: { - type: "flat_rate", - amount: 100, - }, - provider_id: "test_shipper", - }, - franceShipping: { - _id: IdMap.getId("franceShipping"), - name: "FR Shipping", - profile_id: IdMap.getId("default-profile"), - region_id: IdMap.getId("region-france"), - data: { - id: "bonjour", - }, - price: { - type: "flat_rate", - amount: 20, - }, - provider_id: "test_shipper", - }, - shipping1: { - _id: IdMap.getId("shipping1"), - }, - validId: { - _id: IdMap.getId("validId"), - }, -} - -export const ShippingOptionServiceMock = { - withTransaction: function () { - return this - }, - retrieve: jest.fn().mockImplementation((optionId) => { - if (optionId === IdMap.getId("return-shipping")) { - return Promise.resolve(shippingOptions.returnShipping) - } - if (optionId === IdMap.getId("shipping1")) { - return Promise.resolve(shippingOptions.shipping1) - } - if (optionId === IdMap.getId("validId")) { - return Promise.resolve(shippingOptions.validId) - } - if (optionId === IdMap.getId("franceShipping")) { - return Promise.resolve(shippingOptions.franceShipping) - } - if (optionId === IdMap.getId("freeShipping")) { - return Promise.resolve(shippingOptions.freeShipping) - } - return Promise.resolve(undefined) - }), - update: jest.fn().mockReturnValue(Promise.resolve()), - updateShippingprofile: jest.fn().mockReturnValue(Promise.resolve()), - listAndCount: jest.fn().mockImplementation((data) => { - if (data.region_id === IdMap.getId("region-france")) { - return Promise.resolve([[shippingOptions.franceShipping], 1]) - } - if (data.region_id === IdMap.getId("testRegion")) { - return Promise.resolve([ - [shippingOptions.freeShipping, shippingOptions.expensiveShipping], - 2, - ]) - } - return Promise.resolve([[], 0]) - }), - list: jest.fn().mockImplementation((data) => { - if (!data) { - return Promise.resolve([]) - } - if (data.region_id === IdMap.getId("region-france")) { - return Promise.resolve([shippingOptions.franceShipping]) - } - if (data.region_id === IdMap.getId("testRegion")) { - return Promise.resolve([ - shippingOptions.freeShipping, - shippingOptions.expensiveShipping, - ]) - } - }), - create: jest.fn().mockImplementation((data) => { - return Promise.resolve(data) - }), - validateFulfillmentData: jest - .fn() - .mockImplementation((methodId, data, cart) => { - return Promise.resolve(data) - }), - validateCartOption: jest.fn().mockImplementation((methodId, cart) => { - if (methodId === IdMap.getId("freeShipping")) { - return Promise.resolve({ - _id: IdMap.getId("freeShipping"), - price: 0, - provider_id: "default_provider", - }) - } - if (methodId === IdMap.getId("additional")) { - return Promise.resolve({ - _id: IdMap.getId("additional"), - price: 0, - provider_id: "default_provider", - }) - } - if (methodId === IdMap.getId("fail")) { - return Promise.resolve({ - _id: IdMap.getId("fail"), - }) - } - return Promise.resolve({ _id: methodId }) - }), - delete: jest.fn().mockReturnValue(Promise.resolve()), - createShippingMethod: jest - .fn() - .mockImplementation((optionId, data, config) => { - return Promise.resolve({ - ...config, - id: "test-shipping-method", - shipping_option_id: optionId, - data, - }) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return ShippingOptionServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/shipping-profile.js b/packages/medusa/src/services/__mocks__/shipping-profile.js deleted file mode 100644 index 5245160459..0000000000 --- a/packages/medusa/src/services/__mocks__/shipping-profile.js +++ /dev/null @@ -1,152 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const profiles = { - default: { - id: IdMap.getId("default"), - name: "default_profile", - products: [IdMap.getId("product")], - shipping_options: [], - }, - other: { - id: IdMap.getId("profile1"), - name: "other_profile", - products: [IdMap.getId("product")], - shipping_options: [], - }, -} - -export const ShippingProfileServiceMock = { - withTransaction: function () { - return this - }, - update: jest.fn().mockImplementation((data) => { - return Promise.resolve() - }), - create: jest.fn().mockImplementation((data) => { - return Promise.resolve(data) - }), - createDefault: jest.fn().mockImplementation(() => { - return Promise.resolve() - }), - createGiftCardDefault: jest.fn().mockImplementation(() => { - return Promise.resolve() - }), - retrieve: jest.fn().mockImplementation((data) => { - if (data === IdMap.getId("default")) { - return Promise.resolve(profiles.default) - } - if (data === IdMap.getId("profile1")) { - return Promise.resolve(profiles.other) - } - return Promise.resolve(profiles.default) - }), - retrieveGiftCardDefault: jest.fn().mockImplementation((data) => { - return Promise.resolve({ id: IdMap.getId("giftCardProfile") }) - }), - retrieveDefault: jest.fn().mockImplementation((data) => { - return Promise.resolve({ id: IdMap.getId("default_shipping_profile") }) - }), - list: jest.fn().mockImplementation((selector) => { - if (!selector) { - return Promise.resolve([]) - } - if (selector.shipping_options === IdMap.getId("fail")) { - return Promise.resolve([]) - } - if (selector.shipping_options === IdMap.getId("freeShipping")) { - return Promise.resolve([{ id: IdMap.getId("default_profile") }]) - } - if (selector.shipping_options === IdMap.getId("additional")) { - return Promise.resolve([{ id: IdMap.getId("additional_profile") }]) - } - if ( - selector.products && - selector.products.$in.includes(IdMap.getId("product")) - ) { - return Promise.resolve([ - { - name: "default", - products: [IdMap.getId("product")], - shipping_options: [ - { - id: IdMap.getId("freeShipping"), - name: "Free Shipping", - region_id: IdMap.getId("testRegion"), - price: { - type: "flat_rate", - amount: 10, - }, - requirements: [{ type: "max_subtotal", value: 1000 }], - data: { - id: "fs", - }, - provider_id: "test_shipper", - }, - ], - }, - ]) - } - - if ( - selector.products && - selector.products.$in.includes(IdMap.getId("product1")) - ) { - return Promise.resolve([ - { - name: "default1", - products: [IdMap.getId("product1")], - shipping_options: [ - { - id: IdMap.getId("freeShipping"), - name: "Free Shipping", - region_id: IdMap.getId("testRegion"), - price: { - type: "flat_rate", - amount: 10, - }, - requirements: [{ type: "max_subtotal", value: 1000 }], - data: { - id: "fs", - }, - provider_id: "test_shipper", - }, - ], - }, - { - name: "default2", - products: [IdMap.getId("product2")], - shipping_options: [ - { - id: IdMap.getId("freeShipping"), - name: "Free French Shipping", - region_id: IdMap.getId("region-france"), - price: { - type: "flat_rate", - amount: 10, - }, - requirements: [{ type: "max_subtotal", value: 1000 }], - data: { - id: "fs", - }, - provider_id: "test_shipper", - }, - ], - }, - ]) - } - }), - decorate: jest.fn().mockImplementation((d) => Promise.resolve(d)), - addShippingOption: jest.fn().mockImplementation(() => Promise.resolve()), - removeShippingOption: jest.fn().mockImplementation(() => Promise.resolve()), - addProduct: jest.fn().mockImplementation(() => Promise.resolve()), - removeProduct: jest.fn().mockImplementation(() => Promise.resolve()), - fetchCartOptions: jest.fn().mockImplementation(() => { - return Promise.resolve([{ id: IdMap.getId("cartShippingOption") }]) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return ShippingProfileServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/staged-job.js b/packages/medusa/src/services/__mocks__/staged-job.js deleted file mode 100644 index e97d9b7206..0000000000 --- a/packages/medusa/src/services/__mocks__/staged-job.js +++ /dev/null @@ -1,25 +0,0 @@ -const job1 = { - event_name: "test", - data: { - id: "test", - }, -} - -const StagedJobServiceMock = { - withTransaction: function () { - return this - }, - create: jest.fn().mockImplementation((data) => { - return Promise.resolve(data) - }), - - list: jest.fn().mockImplementation((config) => { - return Promise.resolve([job1]) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return StagedJobServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/stock-location.js b/packages/medusa/src/services/__mocks__/stock-location.js deleted file mode 100644 index f0afe3746c..0000000000 --- a/packages/medusa/src/services/__mocks__/stock-location.js +++ /dev/null @@ -1,46 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const StockLocationServiceMock = { - withTransaction: function () { - return this - }, - - retrieve: jest.fn().mockImplementation((id, config) => { - return Promise.resolve({ - id: id, - name: "stock location 1 name", - }) - }), - update: jest.fn().mockImplementation((id, data) => { - return Promise.resolve({ id, ...data }) - }), - - listAndCount: jest.fn().mockImplementation(() => { - return Promise.resolve([ - [ - { - id: IdMap.getId("stock_location_1"), - name: "stock location 1 name", - }, - ], - 1, - ]) - }), - - create: jest.fn().mockImplementation((data) => { - return Promise.resolve({ - id: id, - ...data, - }) - }), - - delete: jest.fn().mockImplementation((id, config) => { - return Promise.resolve() - }), -} - -const mock = jest.fn().mockImplementation(() => { - return StockLocationServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/store.js b/packages/medusa/src/services/__mocks__/store.js deleted file mode 100644 index 39fa727ed0..0000000000 --- a/packages/medusa/src/services/__mocks__/store.js +++ /dev/null @@ -1,32 +0,0 @@ -export const store = { - id: "test-store", - name: "Test store", - currencies: ["DKK", "SEK", "GBP"], -} - -export const StoreServiceMock = { - withTransaction: function() { - return this - }, - create: jest.fn().mockImplementation((data) => { - return Promise.resolve(data) - }), - addCurrency: jest.fn().mockImplementation((data) => { - return Promise.resolve() - }), - removeCurrency: jest.fn().mockImplementation((data) => { - return Promise.resolve() - }), - update: jest.fn().mockImplementation((data) => { - return Promise.resolve() - }), - retrieve: jest.fn().mockImplementation((data) => { - return Promise.resolve(store) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return StoreServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/swap.js b/packages/medusa/src/services/__mocks__/swap.js deleted file mode 100644 index ec941ce632..0000000000 --- a/packages/medusa/src/services/__mocks__/swap.js +++ /dev/null @@ -1,49 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const SwapServiceMock = { - withTransaction: function () { - return this - }, - registerCartCompletion: jest.fn().mockImplementation((data) => { - return Promise.resolve({ id: "test-swap" }) - }), - create: jest.fn().mockImplementation((data) => { - return Promise.resolve() - }), - retrieve: jest.fn().mockImplementation((data) => { - switch (data) { - case IdMap.getId("test-swap"): - return Promise.resolve({ - id: "test-swap", - order_id: IdMap.getId("test-order"), - }) - default: - return Promise.resolve({ id: "test-swap" }) - } - }), - cancel: jest.fn().mockImplementation((f) => { - return Promise.resolve({ f }) - }), - - cancelFulfillment: jest.fn().mockImplementation((f) => { - return Promise.resolve({ id: IdMap.getId("test-swap") }) - }), - list: jest.fn().mockImplementation((...args) => { - return Promise.resolve([ - { id: IdMap.getId("test-swap") }, - { id: IdMap.getId("test-swap-1") }, - ]) - }), - listAndCount: jest.fn().mockImplementation((...args) => { - return Promise.resolve([ - [{ id: IdMap.getId("test-swap") }, { id: IdMap.getId("test-swap-1") }], - 2, - ]) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return SwapServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/tax-provider.js b/packages/medusa/src/services/__mocks__/tax-provider.js deleted file mode 100644 index c9581ff63c..0000000000 --- a/packages/medusa/src/services/__mocks__/tax-provider.js +++ /dev/null @@ -1,26 +0,0 @@ -export const taxProviderServiceMock = { - withTransaction: function () { - return this - }, - createTaxLines: jest.fn().mockImplementation((order, calculationContext) => { - return Promise.resolve() - }), - clearLineItemsTaxLines: jest.fn().mockImplementation((_) => { - return Promise.resolve() - }), - getTaxLines: jest.fn().mockImplementation((_) => { - return Promise.resolve([]) - }), - getTaxLinesMap: jest.fn().mockImplementation((_) => { - return Promise.resolve({ - lineItemsTaxLines: {}, - shippingMethodsTaxLines: {}, - }) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return taxProviderServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/test-pay.js b/packages/medusa/src/services/__mocks__/test-pay.js deleted file mode 100644 index 34017ceca0..0000000000 --- a/packages/medusa/src/services/__mocks__/test-pay.js +++ /dev/null @@ -1,43 +0,0 @@ -export const testPayServiceMock = { - identifier: "test-pay", - getIdentifier: "test-pay", - withTransaction: function () { - return this - }, - getStatus: jest.fn().mockResolvedValue(Promise.resolve("authorised")), - retrieveSavedMethods: jest.fn().mockResolvedValue(Promise.resolve([])), - getPaymentData: jest.fn().mockResolvedValue(Promise.resolve({})), - createPayment: jest.fn().mockImplementation(() => { - return {} - }), - retrievePayment: jest.fn().mockImplementation(() => { - return {} - }), - updatePayment: jest.fn().mockImplementation(() => { - return {} - }), - deletePayment: jest.fn().mockImplementation(() => { - return {} - }), - authorizePayment: jest.fn().mockImplementation(() => { - return {} - }), - updatePaymentData: jest.fn().mockImplementation(() => { - return {} - }), - cancelPayment: jest.fn().mockImplementation(() => { - return {} - }), - capturePayment: jest.fn().mockImplementation(() => { - return {} - }), - refundPayment: jest.fn().mockImplementation(() => { - return {} - }) -} - -const mock = jest.fn().mockImplementation(() => { - return testPayServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/totals.js b/packages/medusa/src/services/__mocks__/totals.js deleted file mode 100644 index 9fd2a265d6..0000000000 --- a/packages/medusa/src/services/__mocks__/totals.js +++ /dev/null @@ -1,49 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -export const TotalsServiceMock = { - withTransaction: function () { - return this - }, - getTotal: jest.fn().mockImplementation((cart) => { - if (cart.total) { - return cart.total - } - return 0 - }), - getGiftCardableAmount: jest.fn().mockImplementation((cart) => { - if (cart.subtotal) { - return cart.subtotal - } - return 0 - }), - getSubtotal: jest.fn().mockImplementation((cart) => { - if (cart.subtotal) { - return cart.subtotal - } - if (cart._id === IdMap.getId("discount-cart")) { - return 280 - } - return 0 - }), - getRefundTotal: jest.fn().mockImplementation((order, lineItems) => { - if (order._id === IdMap.getId("processed-order")) { - return 1230 - } - return 0 - }), - getRefundedTotal: jest.fn().mockImplementation((order, lineItems) => { - return Promise.resolve() - }), - getCalculationContext: jest.fn().mockImplementation((order, lineItems) => { - return Promise.resolve({}) - }), - getLineItemTotals: jest.fn().mockImplementation(() => { - return Promise.resolve({}) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return TotalsServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__mocks__/user.js b/packages/medusa/src/services/__mocks__/user.js deleted file mode 100644 index 9f3ac121c0..0000000000 --- a/packages/medusa/src/services/__mocks__/user.js +++ /dev/null @@ -1,111 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import Scrypt from "scrypt-kdf" - -export const users = { - testUser: { - id: IdMap.getId("test-user"), - email: "oliver@test.dk", - password_hash: "hashed123456789", - }, - vanDijk: { - id: IdMap.getId("vandijk"), - email: "vandijk@test.dk", - password_hash: "hashed123456789", - }, - jwtUser: { - id: "test-user-id", - email: "oliver@test.dk", - password_hash: "123456789hash", - }, - deleteUser: { - id: IdMap.getId("delete-user"), - email: "oliver@deletetest.dk", - password_hash: "hashed123456789", - }, -} - -export const UserServiceMock = { - withTransaction: function () { - return this - }, - create: jest.fn().mockImplementation((data) => { - if (data.email === "oliver@test.dk") { - return Promise.resolve(users.testUser) - } - return Promise.resolve(undefined) - }), - update: jest.fn().mockReturnValue(Promise.resolve()), - list: jest.fn().mockReturnValue(Promise.resolve([])), - listAndCount: jest.fn().mockReturnValue(Promise.resolve([[], 0])), - delete: jest.fn().mockImplementation((data) => { - if (data === IdMap.getId("delete-user")) { - return Promise.resolve({ - id: IdMap.getId("delete-user"), - object: "user", - deleted: true, - }) - } - return Promise.resolve(undefined) - }), - retrieve: jest.fn().mockImplementation((userId) => { - if (userId === IdMap.getId("test-user")) { - return Promise.resolve(users.testUser) - } - if (userId === IdMap.getId("vandijk")) { - return Promise.resolve(users.vanDijk) - } - // used for jwt token tests - if (userId === "test-user-id") { - return Promise.resolve(users.jwtUser) - } - return Promise.resolve(undefined) - }), - setPassword_: jest.fn().mockImplementation((userId) => { - if (userId === IdMap.getId("test-user")) { - return Promise.resolve(users.testUser) - } - if (userId === IdMap.getId("vandijk")) { - return Promise.resolve(users.vanDijk) - } - // used for jwt token tests - if (userId === "test-user-id") { - return Promise.resolve(users.jwtUser) - } - return Promise.resolve(undefined) - }), - decorate: jest.fn().mockImplementation((user, fields) => { - user.decorated = true - return user - }), - generateResetPasswordToken: jest - .fn() - .mockReturnValue(Promise.resolve("JSONWEBTOKEN")), - retrieveByApiToken: jest.fn().mockImplementation((token) => { - if (token === "123456789") { - return Promise.resolve(users.user1) - } - return Promise.resolve(undefined) - }), - retrieveByEmail: jest.fn().mockImplementation((email) => { - if (email === "vandijk@test.dk") { - return Promise.resolve({ - id: IdMap.getId("vandijk"), - email, - password_hash: "1234", - }) - } - if (email === "oliver@test.dk") { - return Scrypt.kdf("123456789", { logN: 1, r: 1, p: 1 }).then((hash) => ({ - email, - password_hash: hash.toString("base64"), - })) - } - return Promise.resolve(undefined) - }), -} - -const mock = jest.fn().mockImplementation(() => { - return UserServiceMock -}) - -export default mock diff --git a/packages/medusa/src/services/__tests__/auth.js b/packages/medusa/src/services/__tests__/auth.js deleted file mode 100644 index 556495900c..0000000000 --- a/packages/medusa/src/services/__tests__/auth.js +++ /dev/null @@ -1,81 +0,0 @@ -import AuthService from "../auth" -import { MockManager } from "medusa-test-utils" -import { users, UserServiceMock } from "../__mocks__/user" -import { CustomerServiceMock } from "../__mocks__/customer" - -const managerMock = MockManager - -describe("AuthService", () => { - const authService = new AuthService({ - manager: managerMock, - userService: UserServiceMock, - customerService: CustomerServiceMock, - }) - - describe("authenticate", () => { - beforeEach(() => { - jest.clearAllMocks() - }) - - it("returns success and user when passwords match", async () => { - const result = await authService.authenticate( - "oliver@test.dk", - "123456789" - ) - - expect(result.success).toEqual(true) - expect(result.user.email).toEqual("oliver@test.dk") - }) - - it("returns failure when passwords don't match", async () => { - const result = await authService.authenticate( - "oliver@test.dk", - "invalid-password" - ) - - expect(result.success).toEqual(false) - expect(result.error).toEqual("Invalid email or password") - expect(result.user).toEqual(undefined) - }) - }) - - describe("authenticateCustomer", () => { - beforeEach(() => { - jest.clearAllMocks() - }) - - it("returns success and user when passwords match", async () => { - const result = await authService.authenticateCustomer( - "oliver@test.dk", - "123456789" - ) - - expect(result.success).toEqual(true) - expect(result.customer.email).toEqual("oliver@test.dk") - }) - - it("returns failure when passwords don't match", async () => { - const result = await authService.authenticateCustomer( - "oliver@test.dk", - "invalid-password" - ) - - expect(result.success).toEqual(false) - expect(result.error).toEqual("Invalid email or password") - expect(result.customer).toEqual(undefined) - }) - }) - - describe("authenticateAPIToken", () => { - beforeEach(() => { - jest.clearAllMocks() - }) - - it("returns success and user when passwords match", async () => { - const result = await authService.authenticateAPIToken("123456789") - - expect(result.success).toEqual(true) - expect(result.user).toEqual(users.user1) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/batch-job.ts b/packages/medusa/src/services/__tests__/batch-job.ts deleted file mode 100644 index 1ff420cd54..0000000000 --- a/packages/medusa/src/services/__tests__/batch-job.ts +++ /dev/null @@ -1,224 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { BatchJob } from "../../models" -import { BatchJobStatus } from "../../types/batch-job" -import BatchJobService from "../batch-job" -import EventBusService from "../event-bus" - -const eventBusServiceMock = { - emit: jest.fn(), - withTransaction: function () { - return this - }, -} as unknown as EventBusService -const batchJobRepositoryMock = MockRepository({ - create: jest.fn().mockImplementation((data) => { - return Object.assign(new BatchJob(), data) - }), -}) - -describe("BatchJobService", () => { - const batchJobId_1 = IdMap.getId("batchJob_1") - const batchJobService = new BatchJobService({ - manager: MockManager, - eventBusService: eventBusServiceMock, - batchJobRepository: batchJobRepositoryMock, - } as any) - - afterEach(() => { - jest.clearAllMocks() - }) - - describe("update status", () => { - describe("confirm", () => { - it("should be able to confirm_processing a batch job to emit the processing event", async () => { - const batchJob = batchJobRepositoryMock.create({ - id: batchJobId_1, - dry_run: true, - status: BatchJobStatus.PRE_PROCESSED, - }) - - const updatedBatchJob = await batchJobService.confirm(batchJob) - expect(updatedBatchJob.processing_at).not.toBeTruthy() - expect(eventBusServiceMock.emit).toHaveBeenCalledWith( - BatchJobService.Events.CONFIRMED, - { id: batchJobId_1 } - ) - }) - - it("should not be able to confirm a batch job with the wrong status", async () => { - const batchJob = batchJobRepositoryMock.create({ - id: batchJobId_1, - dry_run: true, - status: BatchJobStatus.CREATED, - }) - - const err = await batchJobService.confirm(batchJob).catch((e) => e) - expect(err).toBeTruthy() - expect(err.message).toBe( - "Cannot confirm processing for a batch job that is not pre processed" - ) - expect(eventBusServiceMock.emit).toHaveBeenCalledTimes(0) - }) - }) - - describe("complete", () => { - it("should be able to complete a batch job", async () => { - const batchJob = batchJobRepositoryMock.create({ - id: batchJobId_1, - dry_run: true, - status: BatchJobStatus.PROCESSING, - }) - - const updatedBatchJob = await batchJobService.complete(batchJob) - expect(updatedBatchJob.completed_at).toBeTruthy() - expect(eventBusServiceMock.emit).toHaveBeenCalledWith( - BatchJobService.Events.COMPLETED, - { id: batchJobId_1 } - ) - - const batchJob2 = batchJobRepositoryMock.create({ - id: batchJobId_1, - dry_run: false, - status: BatchJobStatus.PROCESSING, - }) - - const updatedBatchJob2 = await batchJobService.complete(batchJob2) - expect(updatedBatchJob2.completed_at).toBeTruthy() - expect(eventBusServiceMock.emit).toHaveBeenCalledWith( - BatchJobService.Events.COMPLETED, - { id: batchJobId_1 } - ) - }) - - it("should not be able to complete a batch job with the wrong status", async () => { - const batchJob = batchJobRepositoryMock.create({ - id: batchJobId_1, - dry_run: true, - status: BatchJobStatus.CREATED, - }) - - const err = await batchJobService.complete(batchJob).catch((e) => e) - expect(err).toBeTruthy() - expect(err.message).toBe( - `Cannot complete a batch job with status "${batchJob.status}". The batch job must be processing` - ) - expect(eventBusServiceMock.emit).toHaveBeenCalledTimes(0) - - const batchJob2 = batchJobRepositoryMock.create({ - id: batchJobId_1, - dry_run: false, - status: BatchJobStatus.PRE_PROCESSED, - }) - - const err2 = await batchJobService.complete(batchJob2).catch((e) => e) - expect(err2).toBeTruthy() - expect(err2.message).toBe( - `Cannot complete a batch job with status "${batchJob2.status}". The batch job must be processing` - ) - expect(eventBusServiceMock.emit).toHaveBeenCalledTimes(0) - }) - }) - - describe("pre processed", () => { - it("should be able to mark as pre processed a batch job in dry_run", async () => { - const batchJob = batchJobRepositoryMock.create({ - id: batchJobId_1, - dry_run: true, - status: BatchJobStatus.CREATED, - }) - - const updatedBatchJob = await batchJobService.setPreProcessingDone( - batchJob - ) - expect(updatedBatchJob.pre_processed_at).toBeTruthy() - expect(eventBusServiceMock.emit).toHaveBeenCalledWith( - BatchJobService.Events.PRE_PROCESSED, - { id: batchJobId_1 } - ) - }) - - it("should be able to mark as completed a batch job that has been pre processed but not in dry_run", async () => { - const batchJob = batchJobRepositoryMock.create({ - id: batchJobId_1, - dry_run: false, - status: BatchJobStatus.CREATED, - }) - - const updatedBatchJob = await batchJobService.setPreProcessingDone( - batchJob - ) - expect(updatedBatchJob.pre_processed_at).toBeTruthy() - expect(updatedBatchJob.confirmed_at).toBeTruthy() - expect(eventBusServiceMock.emit).toHaveBeenCalledTimes(2) - expect(eventBusServiceMock.emit).toHaveBeenCalledWith( - BatchJobService.Events.PRE_PROCESSED, - { id: batchJobId_1 } - ) - expect(eventBusServiceMock.emit).toHaveBeenLastCalledWith( - BatchJobService.Events.CONFIRMED, - { id: batchJobId_1 } - ) - }) - }) - - describe("cancel", () => { - it("should be able to cancel a batch job", async () => { - const batchJob = batchJobRepositoryMock.create({ - id: batchJobId_1, - status: BatchJobStatus.CREATED, - }) - - const updatedBatchJob = await batchJobService.cancel(batchJob) - expect(updatedBatchJob.canceled_at).toBeTruthy() - expect(eventBusServiceMock.emit).toHaveBeenCalledWith( - BatchJobService.Events.CANCELED, - { id: batchJobId_1 } - ) - }) - - it("should not be able to cancel a batch job with the wrong status", async () => { - const batchJob = batchJobRepositoryMock.create({ - id: batchJobId_1, - status: BatchJobStatus.COMPLETED, - }) - - const err = await batchJobService.cancel(batchJob).catch((e) => e) - expect(err).toBeTruthy() - expect(err.message).toBe("Cannot cancel completed batch job") - expect(eventBusServiceMock.emit).toHaveBeenCalledTimes(0) - }) - }) - - describe("processing", () => { - it("should be able to mark as processing a batch job", async () => { - const batchJob = batchJobRepositoryMock.create({ - id: batchJobId_1, - status: BatchJobStatus.CONFIRMED, - }) - - const updatedBatchJob = await batchJobService.setProcessing(batchJob) - expect(updatedBatchJob.processing_at).toBeTruthy() - expect(eventBusServiceMock.emit).toHaveBeenCalledWith( - BatchJobService.Events.PROCESSING, - { id: batchJobId_1 } - ) - }) - - it("should not be able to mark as processing a batch job with the wrong status", async () => { - const batchJob = batchJobRepositoryMock.create({ - id: batchJobId_1, - status: BatchJobStatus.COMPLETED, - }) - - const err = await batchJobService - .setProcessing(batchJob) - .catch((e) => e) - expect(err).toBeTruthy() - expect(err.message).toBe( - "Cannot mark a batch job as processing if the status is different that confirmed" - ) - expect(eventBusServiceMock.emit).toHaveBeenCalledTimes(0) - }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/cart.js b/packages/medusa/src/services/__tests__/cart.js deleted file mode 100644 index 3026ae7953..0000000000 --- a/packages/medusa/src/services/__tests__/cart.js +++ /dev/null @@ -1,2710 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { IsNull, Not } from "typeorm" -import { NewTotalsService, PricingService, TaxProviderService } from "../index" -import { asClass, asValue, createContainer } from "awilix" - -import CartService from "../cart" -import { CustomerServiceMock } from "../__mocks__/customer" -import { EventBusServiceMock } from "../__mocks__/event-bus" -import { FlagRouter } from "@medusajs/utils" -import { LineItemAdjustmentServiceMock } from "../__mocks__/line-item-adjustment" -import { LineItemServiceMock } from "../__mocks__/line-item" -import { MedusaError } from "medusa-core-utils" -import { PaymentProviderServiceMock } from "../__mocks__/payment-provider" -import { PaymentSessionStatus } from "../../models" -import { ProductServiceMock } from "../__mocks__/product" -import { ProductVariantInventoryServiceMock } from "../__mocks__/product-variant-inventory" -import { ProductVariantServiceMock } from "../__mocks__/product-variant" -import { RegionServiceMock } from "../__mocks__/region" -import { ShippingOptionServiceMock } from "../__mocks__/shipping-option" -import { ShippingProfileServiceMock } from "../__mocks__/shipping-profile" -import SystemTaxService from "../system-tax" -import TaxCalculationStrategy from "../../strategies/tax-calculation" -import _ from "lodash" -import { cacheServiceMock } from "../__mocks__/cache" -import { newTotalsServiceMock } from "../__mocks__/new-totals" -import { taxProviderServiceMock } from "../__mocks__/tax-provider" - -const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - return this - }, -} - -describe("CartService", () => { - const totalsService = { - withTransaction: function () { - return this - }, - getShippingMethodTotals: (m) => { - return m - }, - getLineItemTotals: (i) => { - return i - }, - getCalculationContext: () => {}, - getTotal: (o) => { - return o.total || 0 - }, - getSubtotal: (o) => { - return o.subtotal || 0 - }, - getTaxTotal: (o) => { - return o.tax_total || 0 - }, - getDiscountTotal: (o) => { - return o.discount_total || 0 - }, - getShippingTotal: (o) => { - return o.shipping_total || 0 - }, - getGiftCardTotal: (o) => { - return o.gift_card_total || 0 - }, - } - - describe("retrieve", () => { - let result - const cartRepository = MockRepository({ - findOneWithRelations: () => - Promise.resolve({ id: IdMap.getId("emptyCart") }), - }) - beforeAll(async () => { - jest.clearAllMocks() - const cartService = new CartService({ - manager: MockManager, - totalsService, - cartRepository, - taxProviderService: taxProviderServiceMock, - newTotalsService: newTotalsServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - result = await cartService.retrieve(IdMap.getId("emptyCart")) - }) - - it("calls cart model functions", () => { - expect(cartRepository.findOneWithRelations).toHaveBeenCalledTimes(1) - expect(cartRepository.findOneWithRelations).toHaveBeenCalledWith( - {}, - { - where: { id: IdMap.getId("emptyCart") }, - select: undefined, - relations: undefined, - } - ) - }) - }) - - describe("setMetadata", () => { - const cartRepository = MockRepository({ - findOne: () => { - return Promise.resolve({ - metadata: { - existing: "something", - }, - }) - }, - }) - const cartService = new CartService({ - manager: MockManager, - totalsService, - cartRepository, - eventBusService, - taxProviderService: taxProviderServiceMock, - newTotalsService: newTotalsServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("calls updateOne with correct params", async () => { - const id = "testCart" - await cartService.setMetadata(id, "metadata", "testMetadata") - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(cartRepository.findOne).toBeCalledTimes(1) - expect(cartRepository.findOne).toBeCalledWith({ - where: { id }, - }) - - expect(cartRepository.save).toBeCalledTimes(1) - expect(cartRepository.save).toBeCalledWith({ - metadata: { - existing: "something", - metadata: "testMetadata", - }, - }) - }) - - it("throw error on invalid key type", async () => { - const id = "testCart" - try { - await cartService.setMetadata(id, 1234, "nono") - } catch (err) { - expect(err.message).toEqual( - "Key type is invalid. Metadata keys must be strings" - ) - } - }) - }) - - describe("create", () => { - const regionService = { - withTransaction: function () { - return this - }, - retrieve: () => { - return { - id: IdMap.getId("testRegion"), - countries: [{ iso_2: "us" }], - } - }, - } - - const addressRepository = MockRepository({ - create: (c) => c, - findOneWithRelations: (id) => { - return { - id, - first_name: "LeBron", - last_name: "James", - address_1: "Dunk St", - city: "Dunkville", - province: "CA", - postal_code: "12345", - country_code: "us", - } - }, - }) - const cartRepository = MockRepository() - const customerService = { - retrieveUnregisteredByEmail: jest.fn().mockReturnValue( - Promise.resolve({ - id: IdMap.getId("customer"), - email: "email@test.com", - has_account: false, - }) - ), - retrieveRegisteredByEmail: jest.fn().mockReturnValue( - Promise.resolve({ - id: IdMap.getId("customer"), - email: "email@test.com", - has_account: true, - }) - ), - withTransaction: function () { - return this - }, - } - const cartService = new CartService({ - manager: MockManager, - addressRepository, - totalsService, - cartRepository, - customerService, - newTotalsService: newTotalsServiceMock, - regionService, - eventBusService, - taxProviderService: taxProviderServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully creates a cart", async () => { - await cartService.create({ - region_id: IdMap.getId("testRegion"), - email: "email@test.com", - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.created", - expect.any(Object) - ) - - expect(addressRepository.create).toHaveBeenCalledTimes(1) - expect(addressRepository.create).toHaveBeenCalledWith({ - country_code: "us", - }) - - expect(cartRepository.create).toHaveBeenCalledTimes(1) - expect(cartRepository.create).toHaveBeenCalledWith({ - region_id: IdMap.getId("testRegion"), - shipping_address: { - country_code: "us", - }, - customer_id: IdMap.getId("customer"), - email: "email@test.com", - customer: expect.any(Object), - context: expect.any(Object), - }) - - expect(cartRepository.save).toHaveBeenCalledTimes(1) - }) - - it("should throw shipping country not in region", async () => { - const res = cartService.create({ - region_id: IdMap.getId("testRegion"), - shipping_address: { - first_name: "LeBron", - last_name: "James", - address_1: "Dunk St", - city: "Dunkville", - province: "CA", - postal_code: "12345", - country_code: "pt", - }, - }) - - await expect(res).rejects.toThrow("Shipping country not in region") - }) - - it("a cart with a prefilled shipping address", async () => { - await cartService.create({ - region_id: IdMap.getId("testRegion"), - shipping_address: { - first_name: "LeBron", - last_name: "James", - address_1: "Dunk St", - city: "Dunkville", - province: "CA", - postal_code: "12345", - country_code: "us", - }, - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.created", - expect.any(Object) - ) - - expect(cartRepository.create).toHaveBeenCalledTimes(1) - expect(cartRepository.create).toHaveBeenCalledWith({ - context: {}, - region_id: IdMap.getId("testRegion"), - shipping_address: { - first_name: "LeBron", - last_name: "James", - address_1: "Dunk St", - city: "Dunkville", - province: "CA", - postal_code: "12345", - country_code: "us", - }, - }) - - expect(cartRepository.save).toHaveBeenCalledTimes(1) - }) - }) - - describe("addLineItem", () => { - const lineItemService = { - update: jest.fn().mockImplementation(() => Promise.resolve()), - list: jest.fn().mockImplementation(() => Promise.resolve([])), - create: jest.fn(), - withTransaction: function () { - return this - }, - } - - const shippingOptionService = { - deleteShippingMethods: jest.fn(), - withTransaction: function () { - return this - }, - } - - const productVariantService = { - retrieve: jest.fn(), - withTransaction: function () { - return this - }, - } - - const productVariantInventoryService = { - ...ProductVariantInventoryServiceMock, - confirmInventory: jest - .fn() - .mockImplementation((variantId, _quantity, options) => { - if (variantId !== IdMap.getId("cannot-cover")) { - return true - } else { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Variant with id: ${variantId} does not have the required inventory` - ) - } - }), - } - - const cartRepository = MockRepository({ - findOneWithRelations: (rel, q) => { - if (q.where.id === IdMap.getId("cartWithLine")) { - return Promise.resolve({ - id: IdMap.getId("cartWithLine"), - items: [ - { - id: IdMap.getId("merger"), - title: "will merge", - variant_id: IdMap.getId("existing"), - should_merge: true, - quantity: 1, - }, - ], - }) - } - return Promise.resolve({ - id: IdMap.getId("emptyCart"), - shipping_methods: [ - { - shipping_option: { - profile_id: IdMap.getId("testProfile"), - }, - }, - ], - items: [], - }) - }, - }) - - const cartService = new CartService({ - manager: MockManager, - totalsService, - cartRepository, - lineItemService: { - ...lineItemService, - list: jest.fn().mockImplementation((where) => { - if ( - where.cart_id === IdMap.getId("cartWithLine") && - where.variant_id === IdMap.getId("existing") && - where.should_merge - ) { - return Promise.resolve([ - { - ...where, - id: IdMap.getId("merger"), - quantity: 1, - metadata: {}, - }, - ]) - } - - return Promise.resolve([]) - }), - }, - lineItemRepository: MockRepository(), - newTotalsService: newTotalsServiceMock, - eventBusService, - shippingOptionService, - productVariantInventoryService, - productVariantService, - lineItemAdjustmentService: LineItemAdjustmentServiceMock, - taxProviderService: taxProviderServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("creates a new line item and emits a created event", async () => { - const lineItem = { - title: "New Line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - variant_id: IdMap.getId("can-cover"), - unit_price: 123, - quantity: 10, - } - await cartService.addLineItem(IdMap.getId("emptyCart"), _.clone(lineItem)) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(lineItemService.create).toHaveBeenCalledTimes(1) - expect(lineItemService.create).toHaveBeenCalledWith({ - ...lineItem, - has_shipping: false, - cart_id: IdMap.getId("emptyCart"), - }) - - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledWith( - expect.objectContaining({ id: IdMap.getId("emptyCart") }) - ) - }) - - it("successfully creates new line item with shipping", async () => { - const lineItem = { - title: "New Line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - should_merge: true, - variant_id: IdMap.getId("can-cover"), - variant: { - product: { - profile_id: IdMap.getId("testProfile"), - }, - }, - unit_price: 123, - quantity: 10, - } - - await cartService.addLineItem(IdMap.getId("emptyCart"), _.clone(lineItem)) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(lineItemService.create).toHaveBeenCalledTimes(1) - expect(lineItemService.create).toHaveBeenCalledWith({ - ...lineItem, - has_shipping: false, - cart_id: IdMap.getId("emptyCart"), - }) - - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledWith( - expect.objectContaining({ id: IdMap.getId("emptyCart") }) - ) - }) - - it("successfully merges existing line item", async () => { - const lineItem = { - title: "merge line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - unit_price: 123, - variant_id: IdMap.getId("existing"), - should_merge: true, - quantity: 1, - metadata: {}, - } - - await cartService.addLineItem(IdMap.getId("cartWithLine"), lineItem) - - expect(lineItemService.update).toHaveBeenCalledTimes(2) - expect(lineItemService.update).toHaveBeenNthCalledWith( - 1, - IdMap.getId("merger"), - { - quantity: 2, - } - ) - - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1) - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({ - item_id: [IdMap.getId("merger")], - discount_id: expect.objectContaining(Not(IsNull())), - }) - - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledWith( - expect.objectContaining({ id: IdMap.getId("cartWithLine") }) - ) - }) - - it("throws if inventory isn't covered", async () => { - const lineItem = { - title: "merge line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - quantity: 1, - variant_id: IdMap.getId("cannot-cover"), - } - - await expect( - cartService.addLineItem(IdMap.getId("cartWithLine"), lineItem) - ).rejects.toThrow( - `Variant with id: ${IdMap.getId( - "cannot-cover" - )} does not have the required inventory` - ) - }) - }) - - describe("addLineItem w. SalesChannel", () => { - const lineItemService = { - update: jest.fn().mockImplementation(() => Promise.resolve()), - create: jest.fn(), - list: jest.fn().mockImplementation(() => Promise.resolve([])), - withTransaction: function () { - return this - }, - } - - const shippingOptionService = { - deleteShippingMethods: jest.fn(), - withTransaction: function () { - return this - }, - } - - const productVariantService = { - retrieve: jest.fn(), - withTransaction: function () { - return this - }, - } - - const productVariantInventoryService = { - ...ProductVariantInventoryServiceMock, - confirmInventory: jest.fn().mockImplementation((variantId, _quantity) => { - if (variantId !== IdMap.getId("cannot-cover")) { - return true - } else { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Variant with id: ${variantId} does not have the required inventory` - ) - } - }), - } - - const cartRepository = MockRepository({ - findOneWithRelations: (rel, q) => { - if (q.where.id === IdMap.getId("cartWithLine")) { - return Promise.resolve({ - id: IdMap.getId("cartWithLine"), - items: [ - { - id: IdMap.getId("merger"), - title: "will merge", - variant_id: IdMap.getId("existing"), - should_merge: true, - quantity: 1, - }, - ], - }) - } - return Promise.resolve({ - id: IdMap.getId("emptyCart"), - shipping_methods: [ - { - shipping_option: { - profile_id: IdMap.getId("testProfile"), - }, - }, - ], - items: [], - }) - }, - }) - - const cartService = new CartService({ - manager: MockManager, - totalsService, - cartRepository, - lineItemService, - lineItemRepository: MockRepository(), - newTotalsService: newTotalsServiceMock, - eventBusService, - shippingOptionService, - productVariantInventoryService, - productVariantService, - lineItemAdjustmentService: LineItemAdjustmentServiceMock, - taxProviderService: taxProviderServiceMock, - featureFlagRouter: new FlagRouter({ sales_channels: true }), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("validates if cart and variant's product belong to the same sales channel if flag is passed", async () => { - const validateSpy = jest - .spyOn(cartService, "validateLineItem") - .mockImplementation(() => Promise.resolve(true)) - - const lineItem = { - title: "New Line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - variant_id: IdMap.getId("can-cover"), - unit_price: 123, - quantity: 10, - } - - await cartService.addLineItem(IdMap.getId("cartWithLine"), lineItem, { - validateSalesChannels: false, - }) - - expect(cartService.validateLineItem).not.toHaveBeenCalled() - - await cartService.addLineItem(IdMap.getId("cartWithLine"), lineItem) - - expect(cartService.validateLineItem).toHaveBeenCalledTimes(1) - - validateSpy.mockClear() - }) - }) - - describe("removeLineItem", () => { - const lineItemService = { - delete: jest.fn(), - update: jest.fn(), - withTransaction: function () { - return this - }, - } - const cartRepository = MockRepository({ - findOneWithRelations: (rel, q) => { - if (q.where.id === IdMap.getId("withShipping")) { - return Promise.resolve({ - shipping_methods: [ - { - id: IdMap.getId("ship-method"), - shipping_option: { - profile_id: IdMap.getId("prevPro"), - }, - }, - ], - items: [ - { - id: IdMap.getId("itemToRemove"), - variant_id: IdMap.getId("existing"), - variant: { - product: { - profile_id: IdMap.getId("prevPro"), - }, - }, - }, - ], - }) - } - return Promise.resolve({ - shipping_methods: [], - items: [ - { - id: IdMap.getId("itemToRemove"), - }, - ], - }) - }, - }) - - const shippingOptionService = { - deleteShippingMethods: jest.fn(), - withTransaction: function () { - return this - }, - } - - const cartService = new CartService({ - manager: MockManager, - totalsService, - cartRepository, - lineItemService, - lineItemRepository: MockRepository(), - newTotalsService: newTotalsServiceMock, - shippingOptionService, - eventBusService, - lineItemAdjustmentService: LineItemAdjustmentServiceMock, - taxProviderService: taxProviderServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully removes a line item", async () => { - await cartService.removeLineItem( - IdMap.getId("cartWithLine"), - IdMap.getId("itemToRemove") - ) - - expect(lineItemService.delete).toHaveBeenCalledTimes(1) - expect(lineItemService.delete).toHaveBeenCalledWith([ - IdMap.getId("itemToRemove"), - ]) - - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1) - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({ - item_id: [IdMap.getId("itemToRemove")], - discount_id: expect.objectContaining(Not(IsNull())), - }) - - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledWith( - expect.objectContaining({ - items: [{ id: IdMap.getId("itemToRemove") }], - }) - ) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - }) - - it("removes shipping method if not necessary", async () => { - await cartService.removeLineItem( - IdMap.getId("withShipping"), - IdMap.getId("itemToRemove") - ) - - expect(shippingOptionService.deleteShippingMethods).toHaveBeenCalledTimes( - 1 - ) - expect(shippingOptionService.deleteShippingMethods).toHaveBeenCalledWith([ - { - id: IdMap.getId("ship-method"), - shipping_option: { - profile_id: IdMap.getId("prevPro"), - }, - }, - ]) - - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1) - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({ - item_id: [IdMap.getId("itemToRemove")], - discount_id: expect.objectContaining(Not(IsNull())), - }) - - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledWith( - expect.objectContaining({ - items: [expect.objectContaining({ id: IdMap.getId("itemToRemove") })], - }) - ) - }) - - it("resolves if line item is not in cart", async () => { - await cartService.removeLineItem( - IdMap.getId("cartWithLine"), - IdMap.getId("nonExisting") - ) - - expect(lineItemService.delete).toHaveBeenCalledTimes(0) - }) - }) - - describe("update", () => { - const cartRepository = MockRepository({ - findOneWithRelations: (rel, q) => { - if (q.where.id === "withpays") { - return Promise.resolve({ - payment_sessions: [ - { - id: "test", - }, - ], - }) - } - }, - }) - - const cartService = new CartService({ - manager: MockManager, - cartRepository, - totalsService, - eventBusService, - taxProviderService: taxProviderServiceMock, - newTotalsService: newTotalsServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("retrieves correctly", async () => { - cartService.setPaymentSessions = jest.fn() - await cartService.update("withpays", {}) - - expect(cartRepository.findOneWithRelations).toHaveBeenCalledWith( - expect.objectContaining({ - billing_address: true, - customer: true, - discounts: { - rule: true, - }, - gift_cards: true, - items: { - variant: { - product: { - profiles: true, - }, - }, - }, - payment_sessions: true, - region: { countries: true }, - shipping_address: true, - shipping_methods: { - shipping_option: true, - }, - }), - expect.objectContaining({ - select: undefined, - where: { - id: "withpays", - }, - }) - ) - }) - }) - - describe("updateLineItem", () => { - const lineItemService = { - update: jest.fn().mockImplementation(() => - Promise.resolve({ - id: IdMap.getId("existing"), - variant_id: IdMap.getId("good"), - quantity: 1, - }) - ), - retrieve: jest.fn().mockImplementation((lineItemId) => { - if (lineItemId === IdMap.getId("existing")) { - return Promise.resolve({ - id: lineItemId, - cart_id: IdMap.getId("cannot"), - variant_id: IdMap.getId("cannot-cover"), - }) - } - return Promise.resolve({ - id: lineItemId, - cart_id: IdMap.getId("cartWithLine"), - is_return: false, - }) - }), - withTransaction: function () { - return this - }, - } - const productVariantInventoryService = { - ...ProductVariantInventoryServiceMock, - confirmInventory: jest - .fn() - .mockImplementation((id) => id !== IdMap.getId("cannot-cover")), - } - - const cartRepository = MockRepository({ - findOneWithRelations: (rel, q) => { - if (q.where.id === IdMap.getId("cannot")) { - return Promise.resolve({ - items: [ - { - id: IdMap.getId("existing"), - variant_id: IdMap.getId("cannot-cover"), - quantity: 1, - }, - ], - }) - } - return Promise.resolve({ - id: IdMap.getId("cartWithLine"), - total: 100, - items: [ - { - id: IdMap.getId("existingUpdate"), - variant_id: IdMap.getId("good"), - subtotal: 100, - quantity: 1, - }, - ], - }) - }, - }) - const cartService = new CartService({ - manager: MockManager, - totalsService, - cartRepository, - lineItemService, - eventBusService, - newTotalsService: newTotalsServiceMock, - productVariantInventoryService, - lineItemAdjustmentService: LineItemAdjustmentServiceMock, - taxProviderService: taxProviderServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully updates existing line item", async () => { - await cartService.updateLineItem( - IdMap.getId("cartWithLine"), - IdMap.getId("existingUpdate"), - { quantity: 2 } - ) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(lineItemService.update).toHaveBeenCalledTimes(1) - expect(lineItemService.update).toHaveBeenCalledWith( - IdMap.getId("existingUpdate"), - { quantity: 2 } - ) - - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1) - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({ - item_id: [IdMap.getId("existingUpdate")], - discount_id: expect.objectContaining(Not(IsNull())), - }) - - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledWith( - expect.objectContaining({ id: IdMap.getId("cartWithLine") }) - ) - }) - - it("throws if inventory isn't covered", async () => { - await expect( - cartService.updateLineItem( - IdMap.getId("cannot"), - IdMap.getId("existing"), - { quantity: 2 } - ) - ).rejects.toThrow(`Inventory doesn't cover the desired quantity`) - }) - }) - - describe("updateEmail", () => { - const customerService = { - retrieveUnregisteredByEmail: jest.fn().mockImplementation((email) => { - if (email === "no@mail.com") { - return Promise.reject() - } - return Promise.resolve({ - id: IdMap.getId("existing"), - has_account: false, - email, - }) - }), - create: jest.fn().mockImplementation((data) => - Promise.resolve({ - id: IdMap.getId("newCus"), - email: data.email, - }) - ), - withTransaction: function () { - return this - }, - } - const cartRepository = MockRepository({ - findOneWithRelations: () => Promise.resolve({}), - }) - const cartService = new CartService({ - manager: MockManager, - totalsService, - cartRepository, - eventBusService, - customerService, - newTotalsService: newTotalsServiceMock, - taxProviderService: taxProviderServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully updates an email", async () => { - await cartService.update(IdMap.getId("emptyCart"), { - email: "test@testDom.com", - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(2) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(cartRepository.save).toHaveBeenCalledTimes(1) - expect(cartRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - customer_id: IdMap.getId("existing"), - customer: { - id: IdMap.getId("existing"), - email: "test@testdom.com", - has_account: false, - }, - email: "test@testdom.com", - }) - ) - }) - - it("creates a new customer", async () => { - await cartService.update(IdMap.getId("emptyCart"), { - email: "no@Mail.com", - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(2) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(cartRepository.save).toHaveBeenCalledTimes(1) - expect(cartRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - customer_id: IdMap.getId("newCus"), - customer: { id: IdMap.getId("newCus"), email: "no@mail.com" }, - email: "no@mail.com", - }) - ) - }) - - it("throws on invalid email", async () => { - await expect( - cartService.update(IdMap.getId("emptyCart"), { email: "test@test" }) - ).rejects.toThrow("The email is not valid") - }) - }) - - describe("updateBillingAddress", () => { - const cartRepository = MockRepository({ - findOneWithRelations: () => - Promise.resolve({ - region: { countries: [{ iso_2: "us" }] }, - }), - }) - - const addressRepository = MockRepository({ create: (c) => c }) - - const cartService = new CartService({ - manager: MockManager, - totalsService, - cartRepository, - addressRepository, - eventBusService, - newTotalsService: newTotalsServiceMock, - taxProviderService: taxProviderServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully updates billing address", async () => { - const address = { - first_name: "LeBron", - last_name: "James", - address_1: "24 Dunks Drive", - city: "Los Angeles", - country_code: "us", - province: "CA", - postal_code: "93011", - phone: "+1 (222) 333 4444", - } - - await cartService.update(IdMap.getId("emptyCart"), { - billing_address: address, - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(addressRepository.create).toHaveBeenCalledTimes(1) - expect(addressRepository.create).toHaveBeenCalledWith({ - ...address, - country_code: "us", - }) - - expect(cartRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - region: { countries: [{ iso_2: "us" }] }, - billing_address: address, - }) - ) - }) - }) - - describe("updateShippingAddress", () => { - const cartRepository = MockRepository({ - findOneWithRelations: () => - Promise.resolve({ - region: { countries: [{ iso_2: "us" }] }, - }), - }) - const addressRepository = MockRepository({ create: (c) => c }) - - const cartService = new CartService({ - manager: MockManager, - addressRepository, - totalsService, - cartRepository, - eventBusService, - newTotalsService: newTotalsServiceMock, - taxProviderService: taxProviderServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully updates shipping address", async () => { - const address = { - first_name: "LeBron", - last_name: "James", - address_1: "24 Dunks Drive", - city: "Los Angeles", - country_code: "us", - province: "CA", - postal_code: "93011", - phone: "+1 (222) 333 4444", - } - - await cartService.update(IdMap.getId("emptyCart"), { - shipping_address: address, - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(addressRepository.create).toHaveBeenCalledTimes(1) - expect(addressRepository.create).toHaveBeenCalledWith({ - ...address, - }) - - expect(cartRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - region: { countries: [{ iso_2: "us" }] }, - shipping_address: address, - }) - ) - }) - - it("throws if country not in region", async () => { - const address = { - first_name: "LeBron", - last_name: "James", - address_1: "24 Dunks Drive", - city: "Los Angeles", - country_code: "ru", - province: "CA", - postal_code: "93011", - phone: "+1 (222) 333 4444", - } - - await expect( - cartService.update(IdMap.getId("emptyCart"), { - shipping_address: address, - }) - ).rejects.toThrow("Shipping country must be in the cart region") - }) - }) - - describe("setRegion", () => { - const lineItemService = { - update: jest.fn((id) => ({ id })), - delete: jest.fn(), - retrieve: jest.fn().mockImplementation((lineItemId) => { - if (lineItemId === IdMap.getId("existing")) { - return Promise.resolve({ - id: lineItemId, - }) - } - return Promise.resolve({ - id: lineItemId, - }) - }), - list: jest.fn().mockImplementation(async (selector) => { - return selector.id.map((id) => { - return { id } - }) - }), - withTransaction: function () { - return this - }, - } - const addressRepository = MockRepository({ create: (c) => c }) - const productVariantService = { - getRegionPrice: jest.fn().mockImplementation((id) => { - if (id === IdMap.getId("fail")) { - return Promise.reject() - } - return Promise.resolve(100) - }), - } - const regionService = { - retrieve: jest.fn().mockReturnValue( - Promise.resolve({ - id: "region", - countries: [{ iso_2: "us" }], - }) - ), - withTransaction: function () { - return this - }, - } - - const discountService = { - list: jest.fn().mockReturnValue( - Promise.resolve([ - { - id: IdMap.getId("stays"), - regions: [{ id: IdMap.getId("region-us") }], - }, - { - id: IdMap.getId("removes"), - regions: [], - }, - ]) - ), - withTransaction: function () { - return this - }, - } - - const cartRepository = MockRepository({ - findOneWithRelations: () => - Promise.resolve({ - items: [ - { - id: IdMap.getId("testitem"), - variant_id: IdMap.getId("good"), - }, - { - id: IdMap.getId("fail"), - variant_id: IdMap.getId("fail"), - }, - ], - payment_sessions: [{ id: IdMap.getId("removes") }], - discounts: [ - { - id: IdMap.getId("stays"), - regions: [{ id: IdMap.getId("region-us") }], - }, - { - id: IdMap.getId("removes"), - regions: [], - }, - ], - }), - }) - const paymentProviderService = { - deleteSession: jest.fn(), - updateSession: jest.fn(), - createSession: jest.fn(), - withTransaction: function () { - return this - }, - } - - const priceSelectionStrat = { - withTransaction: function () { - return this - }, - calculateVariantPrice: async ([{ variantId }], context) => { - if (variantId === IdMap.getId("fail")) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Money amount for variant with id ${variantId} in region ${context.region_id} does not exist` - ) - } else { - return new Map([[variantId, { calculatedPrice: 100 }]]) - } - }, - } - const cartService = new CartService({ - manager: MockManager, - paymentProviderService, - addressRepository, - discountService, - totalsService, - cartRepository, - newTotalsService: newTotalsServiceMock, - regionService, - lineItemService, - lineItemAdjustmentService: LineItemAdjustmentServiceMock, - productVariantService, - eventBusService, - paymentSessionRepository: MockRepository(), - priceSelectionStrategy: priceSelectionStrat, - taxProviderService: taxProviderServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully set new region", async () => { - await cartService.update(IdMap.getId("fr-cart"), { - region_id: IdMap.getId("region-us"), - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(lineItemService.delete).toHaveBeenCalledTimes(1) - expect(lineItemService.delete).toHaveBeenCalledWith(IdMap.getId("fail")) - - expect(lineItemService.update).toHaveBeenCalledTimes(1) - expect(lineItemService.update).toHaveBeenCalledWith( - IdMap.getId("testitem"), - { - unit_price: 100, - has_shipping: false, - } - ) - - expect(cartRepository.save).toHaveBeenCalledTimes(1) - expect(cartRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - region_id: "region", - region: { - id: "region", - countries: [{ iso_2: "us" }], - }, - shipping_address: { - country_code: "us", - }, - items: [ - { - id: IdMap.getId("testitem"), - }, - ], - payment_session: null, - payment_sessions: [], - gift_cards: [], - discounts: [ - { - id: IdMap.getId("stays"), - regions: [{ id: IdMap.getId("region-us") }], - }, - ], - }) - ) - }) - }) - - describe("setPaymentSession", () => { - const cartRepository = MockRepository({ - findOneWithRelations: (rel, q) => { - if (q.where.id === IdMap.getId("cartWithLine")) { - return Promise.resolve({ - total: 100, - customer: {}, - region: { - currency_code: "usd", - payment_providers: [ - { - id: "test-provider", - }, - ], - }, - items: [], - shipping_methods: [], - payment_sessions: [ - { - id: IdMap.getId("test-session"), - provider_id: "test-provider", - }, - ], - }) - } else if (q.where.id === IdMap.getId("cartWithLine2")) { - return Promise.resolve({ - total: 100, - customer: {}, - region: { - currency_code: "usd", - payment_providers: [ - { - id: "test-provider", - }, - ], - }, - items: [], - shipping_methods: [], - payment_sessions: [ - { - id: IdMap.getId("test-session"), - provider_id: "test-provider", - is_initiated: true, - }, - ], - }) - } - }, - }) - - const paymentSessionRepository = MockRepository({}) - - const paymentProviderService = { - deleteSession: jest.fn(), - updateSession: jest.fn(), - createSession: jest.fn().mockImplementation(() => { - return { id: IdMap.getId("test-session") } - }), - withTransaction: function () { - return this - }, - } - - const cartService = new CartService({ - manager: MockManager, - paymentSessionRepository, - paymentProviderService, - totalsService, - cartRepository, - eventBusService, - taxProviderService: taxProviderServiceMock, - newTotalsService: newTotalsServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully sets a payment method and create it remotely", async () => { - const providerId = "test-provider" - - await cartService.setPaymentSession( - IdMap.getId("cartWithLine"), - providerId - ) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - CartService.Events.UPDATED, - expect.any(Object) - ) - - expect(paymentProviderService.createSession).toHaveBeenCalledWith({ - cart: expect.any(Object), - customer: expect.any(Object), - amount: expect.any(Number), - currency_code: expect.any(String), - provider_id: providerId, - payment_session_id: IdMap.getId("test-session"), - }) - expect(paymentSessionRepository.update).toHaveBeenCalledWith( - IdMap.getId("test-session"), - { - is_selected: true, - is_initiated: true, - } - ) - }) - - it("successfully sets a payment method and update it remotely", async () => { - const providerId = "test-provider" - - await cartService.setPaymentSession( - IdMap.getId("cartWithLine2"), - providerId - ) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - CartService.Events.UPDATED, - expect.any(Object) - ) - - expect(paymentProviderService.updateSession).toHaveBeenCalledWith( - expect.objectContaining({ - id: IdMap.getId("test-session"), - }), - { - cart: expect.any(Object), - customer: expect.any(Object), - amount: expect.any(Number), - currency_code: expect.any(String), - provider_id: providerId, - payment_session_id: IdMap.getId("test-session"), - } - ) - }) - - it("fails if the region does not contain the provider_id", async () => { - await expect( - cartService.setPaymentSession(IdMap.getId("cartWithLine"), "unknown") - ).rejects.toThrow(`The payment method is not available in this region`) - }) - }) - - describe("setPaymentSessions", () => { - const provider1Id = "provider_1" - const provider2Id = "provider_2" - - const cart1 = { - total: 100, - items: [{ subtotal: 100 }], - shipping_methods: [], - payment_sessions: [], - region: { - payment_providers: [{ id: provider1Id }, { id: provider2Id }], - }, - } - - const cart2 = { - total: 100, - items: [], - shipping_methods: [], - payment_sessions: [{ provider_id: provider1Id }], - region: { - payment_providers: [{ id: provider1Id }, { id: provider2Id }], - }, - } - - const cart3 = { - total: 100, - items: [{ subtotal: 100 }], - shipping_methods: [{ subtotal: 100 }], - payment_sessions: [ - { provider_id: provider1Id }, - { provider_id: "not_in_region" }, - ], - region: { - payment_providers: [{ id: provider1Id }, { id: provider2Id }], - }, - } - - const cart4 = { - total: 0, - items: [{ total: 0 }], - shipping_methods: [], - payment_sessions: [ - { provider_id: provider1Id }, - { provider_id: provider2Id }, - ], - region: { - payment_providers: [{ id: provider1Id }, { id: provider2Id }], - }, - } - - const cart5 = { - total: 100, - items: [{ subtotal: 100 }], - shipping_methods: [], - payment_sessions: [ - { provider_id: provider1Id, is_initiated: true }, - { provider_id: provider2Id, is_selected: true, is_initiated: true }, - ], - region: { - payment_providers: [{ id: provider1Id }, { id: provider2Id }], - }, - } - - const cartRepository = MockRepository({ - findOneWithRelations: (rel, q) => { - if (q.where.id === IdMap.getId("cart-to-filter")) { - return Promise.resolve({ - id: IdMap.getId("cart-to-filter"), - ...cart3, - }) - } - if (q.where.id === IdMap.getId("cart-with-session")) { - return Promise.resolve({ - id: IdMap.getId("cart-with-session"), - ...cart2, - }) - } - if (q.where.id === IdMap.getId("cart-remove")) { - return Promise.resolve({ id: IdMap.getId("cart-remove"), ...cart4 }) - } - if (q.where.id === IdMap.getId("cart-negative")) { - return Promise.resolve({ id: IdMap.getId("cart-negative"), ...cart4 }) - } - if ( - q.where.id === IdMap.getId("cartWithMixedSelectedInitiatedSessions") - ) { - return Promise.resolve({ - id: IdMap.getId("cartWithMixedSelectedInitiatedSessions"), - ...cart5, - }) - } - return Promise.resolve({ id: q.where.id, ...cart1 }) - }, - }) - - const paymentProviderService = { - deleteSession: jest.fn(), - updateSession: jest.fn(), - createSession: jest.fn(), - withTransaction: function () { - return this - }, - } - - const paymentSessionRepositoryMock = MockRepository({}) - - const cartService = new CartService({ - manager: MockManager, - paymentSessionRepository: paymentSessionRepositoryMock, - totalsService, - cartRepository, - paymentProviderService, - eventBusService, - taxProviderService: taxProviderServiceMock, - newTotalsService: newTotalsServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("initializes payment sessions for each of the providers", async () => { - await cartService.setPaymentSessions(IdMap.getId("cartWithLine")) - - expect(paymentSessionRepositoryMock.create).toHaveBeenCalledTimes(2) - expect(paymentSessionRepositoryMock.save).toHaveBeenCalledTimes(2) - - expect(paymentSessionRepositoryMock.create).toHaveBeenCalledWith({ - cart_id: IdMap.getId("cartWithLine"), - status: PaymentSessionStatus.PENDING, - amount: cart1.total, - provider_id: provider1Id, - data: {}, - }) - - expect(paymentSessionRepositoryMock.create).toHaveBeenCalledWith({ - cart_id: IdMap.getId("cartWithLine"), - status: PaymentSessionStatus.PENDING, - amount: cart1.total, - provider_id: provider2Id, - data: {}, - }) - }) - - it("delete or update payment sessions remotely depending if they are selected and/or initiated", async () => { - await cartService.setPaymentSessions( - IdMap.getId("cartWithMixedSelectedInitiatedSessions") - ) - - // Selected, update - expect(paymentProviderService.updateSession).toHaveBeenCalledTimes(1) - expect(paymentProviderService.updateSession).toHaveBeenCalledWith( - expect.any(Object), - expect.objectContaining({ - provider_id: provider2Id, - }) - ) - - // Not selected, but initiated, delete - expect(paymentProviderService.deleteSession).toHaveBeenCalledTimes(1) - expect(paymentProviderService.deleteSession).toHaveBeenCalledWith( - expect.objectContaining({ - provider_id: provider1Id, - }) - ) - - expect(paymentSessionRepositoryMock.save).toHaveBeenCalledTimes(1) - }) - - it("filters sessions not available in the region", async () => { - await cartService.setPaymentSessions(IdMap.getId("cart-to-filter")) - - expect(paymentSessionRepositoryMock.create).toHaveBeenCalledTimes(1) - expect(paymentSessionRepositoryMock.save).toHaveBeenCalledTimes(2) // create and update - expect(paymentSessionRepositoryMock.remove).toHaveBeenCalledTimes(1) - expect(paymentSessionRepositoryMock.remove).toHaveBeenCalledWith({ - provider_id: "not_in_region", - }) - }) - - it("removes if cart total === 0", async () => { - await cartService.setPaymentSessions(IdMap.getId("cart-remove")) - - expect(paymentSessionRepositoryMock.remove).toHaveBeenCalledTimes(2) - - expect(paymentSessionRepositoryMock.remove).toHaveBeenCalledWith({ - provider_id: provider1Id, - }) - expect(paymentSessionRepositoryMock.remove).toHaveBeenCalledWith({ - provider_id: provider2Id, - }) - }) - - it("removes if cart total < 0", async () => { - await cartService.setPaymentSessions(IdMap.getId("cart-negative")) - - expect(paymentSessionRepositoryMock.remove).toHaveBeenCalledTimes(2) - - expect(paymentSessionRepositoryMock.remove).toHaveBeenCalledWith({ - provider_id: provider1Id, - }) - expect(paymentSessionRepositoryMock.remove).toHaveBeenCalledWith({ - provider_id: provider2Id, - }) - }) - }) - - describe("findCustomShippingOption", () => { - beforeEach(() => { - jest.clearAllMocks() - }) - - const cartService = new CartService({}) - - it("given a cart with custom shipping options and a shipping option id corresponding to a custom shipping option, then it should return a custom shipping option", async () => { - const cartCSO = [ - { id: "cso-test", shipping_option_id: "test-so", price: 20 }, - ] - const result = cartService.findCustomShippingOption(cartCSO, "test-so") - - expect(result).toEqual({ - id: "cso-test", - shipping_option_id: "test-so", - price: 20, - }) - }) - - it("given a cart with empty custom shipping options and shipping option id, then it should return undefined", async () => { - const cartCSO = [] - - const result = cartService.findCustomShippingOption(cartCSO, "test-so") - - expect(result).toBeUndefined() - }) - - it("given a cart with custom shipping options and a shipping option id that does not belong to the cart, then it should throw an invalid error", async () => { - const cartCSO = [ - { id: "cso-test", shipping_option_id: "test-so", price: 500 }, - ] - - expect(() => { - cartService.findCustomShippingOption(cartCSO, "some-other-so") - }).toThrow(Error) - }) - }) - - describe("addShippingMethod", () => { - const buildCart = (id, config = {}) => { - return { - id: IdMap.getId(id), - items: (config.items || []).map((i) => ({ - id: IdMap.getId(i.id), - variant: { - product: { - profile_id: IdMap.getId(i.profile), - }, - }, - })), - shipping_methods: (config.shipping_methods || []).map((m) => ({ - id: IdMap.getId(m.id), - shipping_option: { - profile_id: IdMap.getId(m.profile), - }, - })), - discounts: [], - } - } - - const cart1 = buildCart("cart") - const cart2 = buildCart("existing", { - shipping_methods: [{ id: "ship1", profile: "profile1" }], - }) - const cart3 = buildCart("lines", { - items: [{ id: "line", profile: "profile1", subtotal: 100 }], - }) - const cartWithCustomSO = buildCart("cart-with-custom-so") - - const cartRepository = MockRepository({ - findOneWithRelations: (rel, q) => { - switch (q.where.id) { - case IdMap.getId("lines"): - return Promise.resolve(cart3) - case IdMap.getId("existing"): - return Promise.resolve(cart2) - case IdMap.getId("cart-with-custom-so"): - return Promise.resolve(cartWithCustomSO) - default: - return Promise.resolve(cart1) - } - }, - }) - - const lineItemService = { - update: jest.fn(), - withTransaction: function () { - return this - }, - } - const shippingOptionService = { - createShippingMethod: jest.fn().mockImplementation((id) => { - return Promise.resolve({ - shipping_option: { - profile_id: id, - }, - }) - }), - deleteShippingMethods: jest.fn(), - withTransaction: function () { - return this - }, - } - - const customShippingOptionService = { - withTransaction: function () { - return this - }, - list: jest.fn().mockImplementation(({ cart_id }) => { - if (cart_id === IdMap.getId("cart-with-custom-so")) { - return [ - { - id: "cso-test", - shipping_profile_id: "test-so", - cart_id: IdMap.getId("cart-with-custom-so"), - }, - ] - } - }), - } - - const cartService = new CartService({ - manager: MockManager, - totalsService, - cartRepository, - shippingOptionService, - lineItemService, - eventBusService, - customShippingOptionService, - newTotalsService: newTotalsServiceMock, - taxProviderService: taxProviderServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully adds the shipping method", async () => { - const data = { - id: "test", - extra: "yes", - } - - await cartService.addShippingMethod( - IdMap.getId("cart"), - IdMap.getId("option"), - data - ) - expect(shippingOptionService.createShippingMethod).toHaveBeenCalledWith( - IdMap.getId("option"), - data, - { cart: cart1 } - ) - }) - - it("successfully overrides existing profile shipping method", async () => { - const data = { - id: "testshipperid", - } - await cartService.addShippingMethod( - IdMap.getId("existing"), - IdMap.getId("profile1"), - data - ) - expect(shippingOptionService.createShippingMethod).toHaveBeenCalledWith( - IdMap.getId("profile1"), - data, - { cart: cart2 } - ) - expect(shippingOptionService.deleteShippingMethods).toHaveBeenCalledWith({ - id: IdMap.getId("ship1"), - shipping_option: { - profile_id: IdMap.getId("profile1"), - }, - }) - }) - - it("successfully adds additional shipping method", async () => { - const data = { - id: "additional_shipper_id", - } - - await cartService.addShippingMethod( - IdMap.getId("existing"), - IdMap.getId("additional"), - data - ) - - expect(shippingOptionService.deleteShippingMethods).toHaveBeenCalledTimes( - 0 - ) - expect(shippingOptionService.createShippingMethod).toHaveBeenCalledTimes( - 1 - ) - expect(shippingOptionService.createShippingMethod).toHaveBeenCalledWith( - IdMap.getId("additional"), - data, - { cart: cart2 } - ) - }) - - it("updates item shipping", async () => { - const data = { - id: "shipper", - } - - await cartService.addShippingMethod( - IdMap.getId("lines"), - IdMap.getId("profile1"), - data - ) - - expect(shippingOptionService.deleteShippingMethods).toHaveBeenCalledTimes( - 0 - ) - expect(shippingOptionService.createShippingMethod).toHaveBeenCalledTimes( - 1 - ) - expect(shippingOptionService.createShippingMethod).toHaveBeenCalledWith( - IdMap.getId("profile1"), - data, - { cart: cart3 } - ) - - expect(lineItemService.update).toHaveBeenCalledTimes(1) - expect(lineItemService.update).toHaveBeenCalledWith(IdMap.getId("line"), { - has_shipping: true, - }) - }) - - it("successfully adds a shipping method from a custom shipping option and custom price", async () => { - const data = { - id: "test", - extra: "yes", - } - - cartService.findCustomShippingOption = jest - .fn() - .mockImplementation((cartCustomShippingOptions) => { - return { - price: 0, - } - }) - - await cartService.addShippingMethod( - IdMap.getId("cart-with-custom-so"), - IdMap.getId("test-so"), - data - ) - expect(shippingOptionService.createShippingMethod).toHaveBeenCalledWith( - IdMap.getId("test-so"), - data, - { - cart_id: IdMap.getId("cart-with-custom-so"), - price: 0, - } - ) - }) - }) - - describe("applyDiscount", () => { - const getOffsetDate = (offset) => { - const date = new Date() - date.setDate(date.getDate() + offset) - return date - } - - const cartRepository = MockRepository({ - findOneWithRelations: (rel, q) => { - if (q.where.id === IdMap.getId("with-d")) { - return Promise.resolve({ - id: IdMap.getId("cart"), - discounts: [ - { - code: "1234", - rule: { - type: "fixed", - }, - }, - { - code: "FS1234", - rule: { - type: "free_shipping", - }, - }, - ], - region_id: IdMap.getId("good"), - items: [ - { - id: "li1", - quantity: 2, - unit_price: 1000, - }, - { - id: "li2", - quantity: 1, - unit_price: 500, - }, - ], - }) - } - if (q.where.id === "with-d-and-customer") { - return Promise.resolve({ - id: "with-d-and-customer", - discounts: [ - { - code: "ApplicableForCustomer", - rule: { - type: "fixed", - }, - }, - ], - region_id: IdMap.getId("good"), - }) - } - return Promise.resolve({ - id: IdMap.getId("cart"), - discounts: [], - region_id: IdMap.getId("good"), - items: [ - { - id: "li1", - quantity: 2, - unit_price: 1000, - }, - { - id: "li2", - quantity: 1, - unit_price: 500, - }, - ], - }) - }, - }) - - const discountService = { - withTransaction: function () { - return this - }, - listByCodes: jest.fn().mockImplementation((code) => { - const codes = Array.isArray(code) ? code : [code] - - const data = [] - - for (const code of codes) { - if (code === "US10") { - data.push({ - regions: [{ id: IdMap.getId("bad") }], - }) - } - if (code === "limit-reached") { - data.push({ - id: IdMap.getId("limit-reached"), - code: "limit-reached", - regions: [{ id: IdMap.getId("good") }], - rule: {}, - usage_count: 2, - usage_limit: 2, - }) - } - if (code === "null-count") { - data.push({ - id: IdMap.getId("null-count"), - code: "null-count", - regions: [{ id: IdMap.getId("good") }], - rule: {}, - usage_count: null, - usage_limit: 2, - }) - } - if (code === "FREESHIPPING") { - data.push({ - id: IdMap.getId("freeship"), - code: "FREESHIPPING", - regions: [{ id: IdMap.getId("good") }], - rule: { - type: "free_shipping", - }, - }) - } - if (code === "EarlyDiscount") { - data.push({ - id: IdMap.getId("10off"), - code: "10%OFF", - regions: [{ id: IdMap.getId("good") }], - rule: { - type: "percentage", - }, - starts_at: getOffsetDate(1), - ends_at: getOffsetDate(10), - }) - } - if (code === "ExpiredDiscount") { - data.push({ - id: IdMap.getId("10off"), - code: "10%OFF", - regions: [{ id: IdMap.getId("good") }], - rule: { - type: "percentage", - }, - ends_at: getOffsetDate(-1), - starts_at: getOffsetDate(-10), - }) - } - if (code === "ExpiredDynamicDiscount") { - data.push({ - id: IdMap.getId("10off"), - code: "10%OFF", - is_dynamic: true, - regions: [{ id: IdMap.getId("good") }], - rule: { - type: "percentage", - }, - starts_at: getOffsetDate(-10), - ends_at: getOffsetDate(-1), - }) - } - if (code === "ExpiredDynamicDiscountEndDate") { - data.push({ - id: IdMap.getId("10off"), - is_dynamic: true, - code: "10%OFF", - regions: [{ id: IdMap.getId("good") }], - rule: { - type: "percentage", - }, - starts_at: getOffsetDate(-10), - ends_at: getOffsetDate(-3), - valid_duration: "P0Y0M1D", - }) - } - if (code === "ValidDiscount") { - data.push({ - id: IdMap.getId("10off"), - code: "10%OFF", - regions: [{ id: IdMap.getId("good") }], - rule: { - type: "percentage", - }, - starts_at: getOffsetDate(-10), - ends_at: getOffsetDate(10), - }) - } - if (code === "ApplicableForCustomer") { - data.push({ - id: "ApplicableForCustomer", - code: "ApplicableForCustomer", - regions: [{ id: IdMap.getId("good") }], - rule: { - id: "test-rule", - type: "percentage", - }, - starts_at: getOffsetDate(-10), - ends_at: getOffsetDate(10), - }) - } - - if (!data.length) { - data.push({ - id: IdMap.getId("10off"), - code: "10%OFF", - regions: [{ id: IdMap.getId("good") }], - rule: { - type: "percentage", - }, - }) - } - } - - if (Array.isArray(code)) { - return Promise.resolve(data) - } - - return Promise.resolve(data[0]) - }), - canApplyForCustomer: jest - .fn() - .mockImplementation((ruleId, customerId) => { - if (ruleId === "test-rule") { - return Promise.resolve(true) - } - if (!customerId) { - return Promise.resolve(false) - } - return Promise.resolve(false) - }), - validateDiscountForCartOrThrow: jest - .fn() - .mockImplementation((cart, discount) => { - return Promise.resolve({ hasErrors: () => false }) - }), - } - - const cartService = new CartService({ - manager: MockManager, - totalsService, - cartRepository, - discountService, - eventBusService, - lineItemAdjustmentService: LineItemAdjustmentServiceMock, - taxProviderService: taxProviderServiceMock, - newTotalsService: newTotalsServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully applies discount to cart", async () => { - await cartService.update(IdMap.getId("fr-cart"), { - discounts: [ - { - code: "10%OFF", - }, - ], - }) - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(cartRepository.save).toHaveBeenCalledTimes(1) - expect(cartRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - id: IdMap.getId("cart"), - region_id: IdMap.getId("good"), - items: [ - { - id: "li1", - quantity: 2, - unit_price: 1000, - }, - { - id: "li2", - quantity: 1, - unit_price: 500, - }, - ], - discounts: [ - { - id: IdMap.getId("10off"), - code: "10%OFF", - regions: [{ id: IdMap.getId("good") }], - rule: { - type: "percentage", - }, - }, - ], - }) - ) - - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1) - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({ - item_id: ["li1", "li2"], - discount_id: expect.objectContaining(Not(IsNull())), - }) - - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledWith( - expect.objectContaining({ id: IdMap.getId("cart") }) - ) - }) - - it("successfully applies discount to cart and removes old one", async () => { - await cartService.update(IdMap.getId("with-d"), { - discounts: [{ code: "10%OFF" }], - }) - - expect(cartRepository.save).toHaveBeenCalledTimes(1) - expect(cartRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - id: IdMap.getId("cart"), - region_id: IdMap.getId("good"), - items: [ - { - id: "li1", - quantity: 2, - unit_price: 1000, - }, - { - id: "li2", - quantity: 1, - unit_price: 500, - }, - ], - discounts: [ - { - id: IdMap.getId("10off"), - code: "10%OFF", - regions: [{ id: IdMap.getId("good") }], - rule: { - type: "percentage", - }, - }, - ], - }) - ) - - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1) - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({ - item_id: ["li1", "li2"], - discount_id: expect.objectContaining(Not(IsNull())), - }) - - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledWith( - expect.objectContaining({ id: IdMap.getId("cart") }) - ) - }) - - it("successfully applies free shipping", async () => { - await cartService.update(IdMap.getId("with-d"), { - discounts: [{ code: "10%OFF" }, { code: "FREESHIPPING" }], - }) - - expect(discountService.listByCodes).toHaveBeenCalledTimes(1) - expect(cartRepository.save).toHaveBeenCalledTimes(1) - expect(cartRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - id: IdMap.getId("cart"), - discounts: [ - { - id: IdMap.getId("10off"), - code: "10%OFF", - regions: [{ id: IdMap.getId("good") }], - rule: { - type: "percentage", - }, - }, - { - id: IdMap.getId("freeship"), - code: "FREESHIPPING", - regions: [{ id: IdMap.getId("good") }], - rule: { - type: "free_shipping", - }, - }, - ], - items: [ - { - id: "li1", - quantity: 2, - unit_price: 1000, - }, - { - id: "li2", - quantity: 1, - unit_price: 500, - }, - ], - region_id: IdMap.getId("good"), - }) - ) - - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1) - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledWith({ - item_id: ["li1", "li2"], - discount_id: expect.objectContaining(Not(IsNull())), - }) - - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledWith( - expect.objectContaining({ id: IdMap.getId("cart") }) - ) - }) - - it("successfully applies discount with a check for customer applicableness", async () => { - await cartService.update("with-d-and-customer", { - discounts: [ - { - code: "ApplicableForCustomer", - }, - ], - }) - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(cartRepository.save).toHaveBeenCalledTimes(1) - expect(cartRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - id: "with-d-and-customer", - region_id: IdMap.getId("good"), - discounts: [ - { - id: "ApplicableForCustomer", - code: "ApplicableForCustomer", - regions: [{ id: IdMap.getId("good") }], - rule: { - id: "test-rule", - type: "percentage", - }, - starts_at: expect.any(Date), - ends_at: expect.any(Date), - }, - ], - }) - ) - }) - - it("successfully remove all discounts that have been applied", async () => { - await cartService.update(IdMap.getId("with-d"), { - discounts: [], - }) - - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledTimes(1) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(cartRepository.save).toHaveBeenCalledTimes(1) - expect(cartRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - id: IdMap.getId("cart"), - region_id: IdMap.getId("good"), - items: [ - { - id: "li1", - quantity: 2, - unit_price: 1000, - }, - { - id: "li2", - quantity: 1, - unit_price: 500, - }, - ], - discounts: [], - }) - ) - }) - }) - - describe("removeDiscount", () => { - const cartRepository = MockRepository({ - findOneWithRelations: (rel, q) => { - return Promise.resolve({ - id: IdMap.getId("cart"), - discounts: [ - { - code: "1234", - rule: { - type: "fixed", - }, - }, - { - code: "FS1234", - rule: { - type: "free_shipping", - }, - }, - ], - items: [], - region_id: IdMap.getId("good"), - }) - }, - }) - - const cartService = new CartService({ - manager: MockManager, - totalsService, - cartRepository, - eventBusService, - lineItemAdjustmentService: LineItemAdjustmentServiceMock, - taxProviderService: taxProviderServiceMock, - newTotalsService: newTotalsServiceMock, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully removes discount", async () => { - await cartService.removeDiscount(IdMap.getId("fr-cart"), "1234") - - expect(LineItemAdjustmentServiceMock.delete).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledTimes(1) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "cart.updated", - expect.any(Object) - ) - - expect(cartRepository.save).toHaveBeenCalledTimes(1) - expect(cartRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("cart"), - region_id: IdMap.getId("good"), - items: [], - discounts: [ - { - code: "FS1234", - rule: { - type: "free_shipping", - }, - }, - ], - }) - }) - }) - - describe("decorateTotals integration", () => { - const legacyTotalServiceMock = { - ...totalsService, - getCalculationContext: () => ({ - shipping_methods: [], - region: { - tax_rate: 10, - currency_code: "eur", - }, - allocation_map: {}, - }), - } - // TODO: extract that to a fixture to be used in this file in the rest of the tests. Needs some update on the registration - // as it is for now adapted to this case - const container = createContainer() - container - .register("manager", asValue(MockManager)) - .register("paymentSessionRepository", asValue(MockRepository({}))) - .register("addressRepository", asValue(MockRepository({}))) - .register("cartRepository", asValue(MockRepository({}))) - .register("lineItemRepository", asValue(MockRepository({}))) - .register("shippingMethodRepository", asValue(MockRepository({}))) - .register("paymentProviderService", asValue(PaymentProviderServiceMock)) - .register("productService", asValue(ProductServiceMock)) - .register("productVariantService", asValue(ProductVariantServiceMock)) - .register("regionService", asValue(RegionServiceMock)) - .register("lineItemService", asValue(LineItemServiceMock)) - .register("shippingOptionService", asValue(ShippingOptionServiceMock)) - .register("shippingProfileService", asValue(ShippingProfileServiceMock)) - .register("customerService", asValue(CustomerServiceMock)) - .register("discountService", asValue({})) - .register("giftCardService", asValue({})) - .register("totalsService", asValue(legacyTotalServiceMock)) - .register("customShippingOptionService", asValue({})) - .register("lineItemAdjustmentService", asValue({})) - .register("priceSelectionStrategy", asValue({})) - .register("productVariantInventoryService", asValue({})) - .register("salesChannelService", asValue({})) - .register("storeService", asValue({})) - .register("featureFlagRouter", asValue(new FlagRouter({}))) - .register("taxRateService", asValue({})) - .register("systemTaxService", asValue(new SystemTaxService())) - .register("tp_test", asValue("good")) - .register("cacheService", asValue(cacheServiceMock)) - .register("taxProviderRepository", asValue(MockRepository)) - .register( - "lineItemTaxLineRepository", - asValue(MockRepository({ create: (d) => d })) - ) - .register("shippingMethodTaxLineRepository", asValue(MockRepository)) - .register("eventBusService", asValue(EventBusServiceMock)) - // Register the real class for the service below to do the integration tests - .register("taxCalculationStrategy", asClass(TaxCalculationStrategy)) - .register("taxProviderService", asClass(TaxProviderService)) - .register("newTotalsService", asClass(NewTotalsService)) - .register("cartService", asClass(CartService)) - .register("remoteQuery", asValue(null)) - .register("remoteLink", asValue(null)) - .register("pricingModuleService", asValue(undefined)) - .register("pricingService", asClass(PricingService)) - - const cartService = container.resolve("cartService") - - it("should decorate totals with a cart containing custom items", async () => { - const cart = { - id: IdMap.getId("cartWithPaySessions"), - region_id: IdMap.getId("testRegion"), - items: [ - { - id: IdMap.getId("existingLine"), - title: "merge line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - variant_id: null, - unit_price: 100, - quantity: 10, - }, - ], - shipping_address: {}, - billing_address: {}, - discounts: [], - region: { - tax_rate: 10, - currency_code: "eur", - }, - gift_cards: [], - } - - const totals = await cartService.decorateTotals(cart, { - force_taxes: true, - }) - - expect(totals.total).toEqual(1000) - expect(totals.subtotal).toEqual(1000) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/claim-item.js b/packages/medusa/src/services/__tests__/claim-item.js deleted file mode 100644 index 982db3d365..0000000000 --- a/packages/medusa/src/services/__tests__/claim-item.js +++ /dev/null @@ -1,138 +0,0 @@ -import _ from "lodash" -import { IdMap, MockRepository, MockManager } from "medusa-test-utils" -import ClaimItemService from "../claim-item" - -const withTransactionMock = jest.fn() -const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - withTransactionMock("eventBus") - return this - }, -} - -describe("ClaimItemService", () => { - describe("create", () => { - const testItem = { - claim_order_id: "claim_13", - item_id: "itm_1", - tags: ["fluff"], - reason: "production_failure", - note: "Details", - quantity: 1, - images: ["url.com/1234"], - } - - const claimTagRepo = MockRepository({ - findOne: () => Promise.resolve(), - create: (d) => d, - }) - - const claimImgRepo = MockRepository({ - findOne: () => Promise.resolve(), - create: (d) => d, - }) - - const claimItemRepo = MockRepository({ - create: (d) => ({ id: "ci_1234", ...d }), - }) - - const lineItemService = { - withTransaction: function () { - withTransactionMock("lineItem") - return this - }, - } - - const claimItemService = new ClaimItemService({ - manager: MockManager, - lineItemService, - claimTagRepository: claimTagRepo, - claimItemRepository: claimItemRepo, - claimImageRepository: claimImgRepo, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully creates a claim item", async () => { - lineItemService.retrieve = jest.fn(() => - Promise.resolve({ - variant_id: "var_1", - fulfilled_quantity: 1, - }) - ) - await claimItemService.create(testItem) - - expect(withTransactionMock).toHaveBeenCalledWith("lineItem") - expect(lineItemService.retrieve).toHaveBeenCalledTimes(1) - - expect(claimTagRepo.findOne).toHaveBeenCalledTimes(1) - expect(claimTagRepo.findOne).toHaveBeenCalledWith({ - where: { value: "fluff" }, - }) - - expect(claimTagRepo.create).toHaveBeenCalledTimes(1) - expect(claimTagRepo.create).toHaveBeenCalledWith({ - value: "fluff", - }) - - expect(claimItemRepo.create).toHaveBeenCalledTimes(1) - expect(claimItemRepo.create).toHaveBeenCalledWith({ - claim_order_id: "claim_13", - item_id: "itm_1", - variant_id: "var_1", - reason: "production_failure", - note: "Details", - quantity: 1, - tags: [{ value: "fluff" }], - images: [{ url: "url.com/1234" }], - }) - }) - - it("normalizes claim tag value", async () => { - lineItemService.retrieve = jest.fn(() => - Promise.resolve({ - variant_id: "var_1", - fulfilled_quantity: 1, - }) - ) - await claimItemService.create({ - ...testItem, - tags: [" FLUFF "], - }) - expect(claimTagRepo.findOne).toHaveBeenCalledTimes(1) - expect(claimTagRepo.findOne).toHaveBeenCalledWith({ - where: { value: "fluff" }, - }) - }) - - it("fails if fulfilled_quantity < quantity", async () => { - lineItemService.retrieve = jest.fn(() => - Promise.resolve({ - variant_id: "var_1", - fulfilled_quantity: 0, - }) - ) - await expect(claimItemService.create(testItem)).rejects.toThrow( - "Cannot claim more of an item than has been fulfilled" - ) - }) - - it("fails if reason is unknown", async () => { - lineItemService.retrieve = jest.fn(() => - Promise.resolve({ fulfilled_quantity: 1 }) - ) - await expect( - claimItemService.create({ - ...testItem, - reason: "unknown", - }) - ).rejects.toThrow( - `Claim Item reason must be one of "missing_item", "wrong_item", "production_failure" or "other".` - ) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/claim.js b/packages/medusa/src/services/__tests__/claim.js deleted file mode 100644 index a10027e86e..0000000000 --- a/packages/medusa/src/services/__tests__/claim.js +++ /dev/null @@ -1,921 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import ClaimService from "../claim" -import { ProductVariantInventoryServiceMock } from "../__mocks__/product-variant-inventory" - -const withTransactionMock = jest.fn() -const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - withTransactionMock("eventBus") - return this - }, -} - -const totalsService = { - getCalculationContext: jest.fn(() => {}), - getRefundTotal: jest.fn(() => 1000), - getLineItemRefund: jest.fn(() => 8000), -} - -describe("ClaimService", () => { - describe("create", () => { - const testClaim = { - type: "refund", - order: { - id: "1234", - region_id: "order_region", - no_notification: true, - items: [ - { - id: "itm_1", - unit_price: 8000, - shipped_quantity: 1, - }, - ], - }, - claim_items: [ - { - item_id: "itm_1", - tags: ["fluff"], - reason: "production_failure", - note: "Details", - quantity: 1, - images: ["url.com/1234"], - }, - ], - return_shipping: { - option_id: "opt_13", - price: 0, - }, - additional_items: [ - { - variant_id: "var_123", - quantity: 1, - }, - ], - shipping_address_id: "adr_1234", - } - - const claimRepo = MockRepository({ - create: (d) => ({ id: "claim_134", ...d }), - }) - - const lineItemRepository = MockRepository({ - create: (d) => ({ id: "claim_item_134", ...d }), - }) - - const taxProviderService = { - createTaxLines: jest.fn(), - withTransaction: function () { - withTransactionMock("return") - return this - }, - } - - const returnService = { - create: jest.fn(), - withTransaction: function () { - withTransactionMock("return") - return this - }, - } - - const lineItemService = { - generate: jest.fn((d, _, q) => ({ - id: "test_item", - variant_id: d, - quantity: q, - })), - retrieve: () => Promise.resolve({}), - list: () => Promise.resolve([{}]), - withTransaction: function () { - withTransactionMock("lineItem") - return this - }, - } - - const productVariantInventoryService = { - ...ProductVariantInventoryServiceMock, - withTransaction: function () { - withTransactionMock("inventory") - return this - }, - } - - const claimItemService = { - create: jest.fn(), - withTransaction: function () { - withTransactionMock("claimItem") - return this - }, - } - - const claimService = new ClaimService({ - manager: MockManager, - claimRepository: claimRepo, - lineItemRepository: lineItemRepository, - taxProviderService, - totalsService, - returnService, - lineItemService, - claimItemService, - productVariantInventoryService, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully creates a claim", async () => { - await claimService.create(testClaim) - - expect(withTransactionMock).toHaveBeenCalledWith("return") - - expect(returnService.create).toHaveBeenCalledTimes(1) - expect(returnService.create).toHaveBeenCalledWith({ - order_id: "1234", - claim_order_id: "claim_134", - refund_amount: 8000, - shipping_method: { - option_id: "opt_13", - price: 0, - }, - items: [ - { - item_id: "itm_1", - quantity: 1, - }, - ], - no_notification: true, - }) - - expect(withTransactionMock).toHaveBeenCalledWith("lineItem") - expect(lineItemService.generate).toHaveBeenCalledTimes(1) - expect(lineItemService.generate).toHaveBeenCalledWith( - "var_123", - "order_region", - 1 - ) - - expect( - productVariantInventoryService.reserveQuantity - ).toHaveBeenCalledTimes(1) - expect( - productVariantInventoryService.reserveQuantity - ).toHaveBeenCalledWith("var_123", 1, { - lineItemId: "test_item", - salesChannelId: undefined, - }) - - expect(withTransactionMock).toHaveBeenCalledWith("claimItem") - expect(claimItemService.create).toHaveBeenCalledTimes(1) - expect(claimItemService.create).toHaveBeenCalledWith({ - claim_order_id: "claim_134", - item_id: "itm_1", - tags: ["fluff"], - reason: "production_failure", - note: "Details", - quantity: 1, - images: ["url.com/1234"], - }) - - expect(claimRepo.create).toHaveBeenCalledTimes(1) - expect(claimRepo.create).toHaveBeenCalledWith({ - payment_status: "not_refunded", - no_notification: true, - refund_amount: 8000, - type: "refund", - order_id: "1234", - additional_items: [ - { - id: "test_item", - variant_id: "var_123", - quantity: 1, - }, - ], - shipping_address_id: "adr_1234", - }) - - expect(claimRepo.save).toHaveBeenCalledTimes(1) - - expect(withTransactionMock).toHaveBeenCalledWith("eventBus") - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith("claim.created", { - id: "claim_134", - no_notification: true, - }) - }) - - it("return only created when return shipping provided", async () => { - await claimService.create({ - ...testClaim, - return_shipping: null, - }) - expect(returnService.create).toHaveBeenCalledTimes(0) - }) - - it("fails if replace and no additional items", async () => { - await expect( - claimService.create({ - ...testClaim, - type: "replace", - additional_items: null, - }) - ).rejects.toThrow( - `Claims with type "replace" must have at least one additional item.` - ) - }) - - it("fails if replace and refund amount", async () => { - await expect( - claimService.create({ - ...testClaim, - type: "replace", - refund_amount: 102, - }) - ).rejects.toThrow( - `Claim has type "replace" but must be type "refund" to have a refund_amount.` - ) - }) - - it("fails if type is unknown", async () => { - await expect( - claimService.create({ - ...testClaim, - type: "unknown", - }) - ).rejects.toThrow(`Claim type must be one of "refund" or "replace".`) - }) - - it("fails if no claim items", async () => { - await expect( - claimService.create({ - ...testClaim, - claim_items: [], - }) - ).rejects.toThrow(`Claims must have at least one claim item.`) - }) - - it("fails if additional items are not in stock", async () => { - try { - const res = await claimService.create({ - ...testClaim, - additional_items: [ - { - variant_id: "var_123", - quantity: 25, - }, - ], - }) - } catch (e) { - expect(e.message).toEqual( - `Variant with id: var_123 does not have the required inventory` - ) - } - }) - it.each( - [ - [false, false], - [undefined, true], - ], - "passes correct no_notification status to event bus", - async (input, expected) => { - await claimService.create({ - ...testClaim, - no_notification: input, - }) - - expect(eventBusService.emit).toHaveBeenCalledWith(expect.any(String), { - id: expect.any(String), - no_notification: expected, - }) - } - ) - }) - - describe("getRefundTotalForClaimLinesOnOrder", () => { - const testOrder = (items = [], swaps = [], claims = []) => ({ - id: "1234", - region_id: "order_region", - no_notification: true, - items: [ - { - id: "itm_1", - unit_price: 8000, - shipped_quantity: 1, - }, - ...items, - ], - ...swaps, - ...claims, - }) - - const claimRepo = MockRepository({}) - - const claimService = new ClaimService({ - manager: MockManager, - claimRepository: claimRepo, - totalsService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("calculates refund total for claim with one shipped item", async () => { - const order = testOrder([ - { - id: "itm_1", - unit_price: 8000, - shipped_quantity: 1, - }, - ]) - - const refund = await claimService.getRefundTotalForClaimLinesOnOrder( - order, - [ - { - item_id: "itm_1", - quantity: 1, - }, - ] - ) - - expect(totalsService.getLineItemRefund).toHaveBeenCalledTimes(1) - expect(totalsService.getLineItemRefund).toHaveBeenCalledWith(order, { - id: "itm_1", - unit_price: 8000, - quantity: 1, - shipped_quantity: 1, - }) - - expect(refund).toEqual(8000) - }) - - it("calculates refund total for claim with one shipped + one pending item", async () => { - const order = testOrder([{ id: "itm_2", shipped_quantity: 0 }]) - - const refund = await claimService.getRefundTotalForClaimLinesOnOrder( - order, - [ - { - item_id: "itm_1", - quantity: 1, - }, - ] - ) - - expect(totalsService.getLineItemRefund).toHaveBeenCalledTimes(1) - expect(totalsService.getLineItemRefund).toHaveBeenCalledWith(order, { - id: "itm_1", - unit_price: 8000, - quantity: 1, - shipped_quantity: 1, - }) - - expect(refund).toEqual(8000) - }) - - it("calculates refund total for claim with two shipped + one pending item", async () => { - const order = testOrder([ - { id: "itm_2", shipped_quantity: 0 }, - { id: "itm_3", shipped_quantity: 1, unit_price: 5000 }, - ]) - - const refund = await claimService.getRefundTotalForClaimLinesOnOrder( - order, - [ - { - item_id: "itm_1", - quantity: 1, - }, - { item_id: "itm_3", quantity: 1 }, - ] - ) - - expect(totalsService.getLineItemRefund).toHaveBeenCalledTimes(2) - expect(totalsService.getLineItemRefund.mock.calls).toEqual([ - [ - order, - { - id: "itm_1", - unit_price: 8000, - quantity: 1, - shipped_quantity: 1, - }, - ], - [ - order, - { - id: "itm_3", - unit_price: 5000, - quantity: 1, - shipped_quantity: 1, - }, - ], - ]) - - expect(refund).toEqual(16000) - }) - - it("calculates refund total for claim on swap items", async () => { - const order = testOrder([], [[{ id: "itm_1", shipped_quantity: 1 }]]) - - const refund = await claimService.getRefundTotalForClaimLinesOnOrder( - order, - [ - { - item_id: "itm_1", - quantity: 1, - }, - ] - ) - - expect(totalsService.getLineItemRefund).toHaveBeenCalledTimes(1) - expect(totalsService.getLineItemRefund.mock.calls).toEqual([ - [ - order, - { - id: "itm_1", - unit_price: 8000, - quantity: 1, - shipped_quantity: 1, - }, - ], - ]) - - expect(refund).toEqual(8000) - }) - - it("calculates refund total for claim on claim items", async () => { - const order = testOrder([], [], [{ id: "itm_1", shipped_quantity: 1 }]) - - const refund = await claimService.getRefundTotalForClaimLinesOnOrder( - order, - [ - { - item_id: "itm_1", - quantity: 1, - }, - ] - ) - - expect(totalsService.getLineItemRefund).toHaveBeenCalledTimes(1) - expect(totalsService.getLineItemRefund.mock.calls).toEqual([ - [ - order, - { - id: "itm_1", - unit_price: 8000, - quantity: 1, - shipped_quantity: 1, - }, - ], - ]) - - expect(refund).toEqual(8000) - }) - - it("return 0 when claim lines cannot be found", async () => { - const order = testOrder([ - { id: "itm_2", shipped_quantity: 0 }, - { id: "itm_3", shipped_quantity: 1, unit_price: 5000 }, - ]) - - const refund = await claimService.getRefundTotalForClaimLinesOnOrder( - order, - [{ item_id: "itm_10", quantity: 1 }] - ) - - expect(totalsService.getLineItemRefund).toHaveBeenCalledTimes(0) - - expect(refund).toEqual(0) - }) - }) - - describe("retrieve", () => { - const claimRepo = MockRepository() - const claimService = new ClaimService({ - manager: MockManager, - claimRepository: claimRepo, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully creates a claim", async () => { - claimRepo.setFindOne(() => Promise.resolve({ id: "claim_id" })) - await claimService.retrieve("claim_id", { - relations: ["order"], - }) - - expect(claimRepo.findOne).toHaveBeenCalledWith({ - where: { id: "claim_id" }, - relations: { order: true }, - }) - }) - }) - - describe("createFulfillment", () => { - const fulfillmentService = { - createFulfillment: jest.fn((_, items) => - Promise.resolve([{ id: "ful", items }]) - ), - withTransaction: function () { - withTransactionMock("fulfillment") - return this - }, - } - - const order = { - email: "hi@123", - discounts: [ - { - id: "disc_1234", - }, - ], - payments: [{ id: "pay_test" }], - currency_code: "dkk", - tax_rate: 25, - region_id: "test_region", - display_id: 112345, - billing_address: { first_name: "hi" }, - } - - const claim = { - type: "replace", - fulfillment_status: "not_fulfilled", - order, - additional_items: [{ id: "item_test", quantity: 1 }], - shipping_methods: [{ id: "method_test" }], - } - - const claimRepo = MockRepository({ - findOne: () => Promise.resolve({ ...claim }), - }) - - const lineItemService = { - update: jest.fn(), - retrieve: () => Promise.resolve({}), - withTransaction: function () { - withTransactionMock("lineItem") - return this - }, - } - - const claimService = new ClaimService({ - manager: MockManager, - claimRepository: claimRepo, - fulfillmentService, - lineItemService, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully creates fulfillment", async () => { - await claimService.createFulfillment("claim_id", { - metadata: { meta: "data" }, - }) - - expect(withTransactionMock).toHaveBeenCalledTimes(3) - expect(withTransactionMock).toHaveBeenCalledWith("eventBus") - - expect(withTransactionMock).toHaveBeenCalledWith("fulfillment") - expect(fulfillmentService.createFulfillment).toHaveBeenCalledTimes(1) - expect(fulfillmentService.createFulfillment).toHaveBeenCalledWith( - { - ...claim, - payments: order.payments, - email: order.email, - discounts: order.discounts, - currency_code: order.currency_code, - tax_rate: order.tax_rate, - region_id: order.region_id, - display_id: order.display_id, - billing_address: order.billing_address, - items: claim.additional_items, - shipping_methods: claim.shipping_methods, - is_claim: true, - }, - [ - { - item_id: "item_test", - quantity: 1, - }, - ], - { claim_order_id: "claim_id", metadata: { meta: "data" } } - ) - - expect(withTransactionMock).toHaveBeenCalledWith("lineItem") - expect(lineItemService.update).toHaveBeenCalledTimes(1) - expect(lineItemService.update).toHaveBeenCalledWith("item_test", { - fulfilled_quantity: 1, - }) - }) - - it("fails if no shipping_methods", async () => { - claimRepo.setFindOne(() => - Promise.resolve({ ...claim, shipping_methods: [] }) - ) - - await expect( - claimService.createFulfillment("claim_id", { meta: "data" }) - ).rejects.toThrow(`Cannot fulfill a claim without a shipping method.`) - }) - - it("fails if claim is canceled", async () => { - claimRepo.setFindOne(() => - Promise.resolve({ ...claim, canceled_at: new Date() }) - ) - - await expect( - claimService.createFulfillment("claim_id", {}) - ).rejects.toThrow("Canceled claim cannot be fulfilled") - }) - - it("fails if already fulfilled", async () => { - claimRepo.setFindOne(() => - Promise.resolve({ ...claim, fulfillment_status: "fulfilled" }) - ) - - await expect( - claimService.createFulfillment("claim_id", { meta: "data" }) - ).rejects.toThrow(`The claim has already been fulfilled.`) - }) - - it("fails if type is refund", async () => { - claimRepo.setFindOne(() => Promise.resolve({ ...claim, type: "refund" })) - - await expect( - claimService.createFulfillment("claim_id", { meta: "data" }) - ).rejects.toThrow(`Claims with the type "refund" can not be fulfilled`) - }) - }) - - describe("cancelFulfillment", () => { - const claimRepo = MockRepository({ - findOne: () => Promise.resolve({}), - save: (f) => Promise.resolve(f), - }) - - const fulfillmentService = { - cancelFulfillment: jest.fn().mockImplementation((f) => { - switch (f) { - case IdMap.getId("no-claim"): - return Promise.resolve({}) - default: - return Promise.resolve({ - claim_order_id: IdMap.getId("claim-id"), - }) - } - }), - withTransaction: function () { - return this - }, - } - - const claimService = new ClaimService({ - manager: MockManager, - claimRepository: claimRepo, - fulfillmentService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully cancels fulfillment and corrects claim status", async () => { - await claimService.cancelFulfillment(IdMap.getId("claim")) - - expect(fulfillmentService.cancelFulfillment).toHaveBeenCalledTimes(1) - expect(fulfillmentService.cancelFulfillment).toHaveBeenCalledWith( - IdMap.getId("claim") - ) - - expect(claimRepo.save).toHaveBeenCalledTimes(1) - expect(claimRepo.save).toHaveBeenCalledWith({ - fulfillment_status: "canceled", - }) - }) - - it("fails to cancel fulfillment when not related to a claim", async () => { - await expect( - claimService.cancelFulfillment(IdMap.getId("no-claim")) - ).rejects.toThrow(`Fufillment not related to a claim`) - }) - }) - - describe("processRefund", () => { - const claimRepo = MockRepository({ - findOne: () => Promise.resolve({ canceled_at: new Date() }), - }) - - const claimService = new ClaimService({ - manager: MockManager, - claimRepository: claimRepo, - }) - - it("fails when claim is canceled", async () => { - await expect( - claimService.processRefund(IdMap.getId("claim-id")) - ).rejects.toThrow("Canceled claim cannot be processed") - }) - }) - - describe("createShipment", () => { - const fulfillmentService = { - createShipment: jest.fn(() => { - return Promise.resolve({ - items: [ - { - item_id: "item_1", - quantity: 1, - }, - ], - }) - }), - withTransaction: function () { - withTransactionMock("fulfillment") - return this - }, - } - - const lineItemService = { - update: jest.fn(), - retrieve: () => Promise.resolve({}), - withTransaction: function () { - withTransactionMock("lineItem") - return this - }, - } - - const claimRepo = MockRepository() - - const claimService = new ClaimService({ - manager: MockManager, - claimRepository: claimRepo, - fulfillmentService, - lineItemService, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("calls fulfillment service", async () => { - claimRepo.setFindOne(() => - Promise.resolve({ - additional_items: [ - { - id: "item_1", - shippied_quantity: 1, - }, - ], - }) - ) - - await claimService.createShipment("claim", "ful_123", ["track1234"], { - metadata: { - meta: "data", - }, - no_notification: false, - }) - - expect(withTransactionMock).toHaveBeenCalledTimes(3) - expect(withTransactionMock).toHaveBeenCalledWith("fulfillment") - expect(withTransactionMock).toHaveBeenCalledWith("lineItem") - expect(withTransactionMock).toHaveBeenCalledWith("eventBus") - - expect(fulfillmentService.createShipment).toHaveBeenCalledTimes(1) - expect(fulfillmentService.createShipment).toHaveBeenCalledWith( - "ful_123", - ["track1234"], - { - metadata: { - meta: "data", - }, - no_notification: false, - } - ) - - expect(lineItemService.update).toHaveBeenCalledTimes(1) - expect(lineItemService.update).toHaveBeenCalledWith("item_1", { - shipped_quantity: 1, - }) - }) - - it("fails if claim is canceled", async () => { - claimRepo.setFindOne(() => Promise.resolve({ canceled_at: new Date() })) - - await expect( - claimService.createShipment("claim", "ful_123", ["track1234"], {}) - ).rejects.toThrow("Canceled claim cannot be fulfilled as shipped") - }) - }) - - describe("update", () => { - const claimRepo = MockRepository({ - findOne: () => Promise.resolve({ canceled_at: new Date() }), - }) - - const claimService = new ClaimService({ - manager: MockManager, - claimRepository: claimRepo, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("fails when claim is canceled", async () => { - await expect( - claimService.update(IdMap.getId("claim-id")) - ).rejects.toThrow("Canceled claim cannot be updated") - }) - }) - - describe("cancel", () => { - const fulfillmentService = { - cancelFulfillment: jest.fn(), - withTransaction: function () { - withTransactionMock("fulfillment") - return this - }, - } - - const returnService = { - cancel: jest.fn(), - withTransaction: function () { - withTransactionMock("return") - return this - }, - } - - const now = new Date() - const ret_order = { id: "ret", status: "canceled" } - const fulfillment = { id: "ful_21", canceled_at: now } - - const claimRepo = MockRepository({ - findOne: (q) => { - const claim = { - return_order: { ...ret_order }, - fulfillments: [{ ...fulfillment }], - } - switch (q.where.id) { - case IdMap.getId("fail-fulfillment"): - claim.fulfillments[0].canceled_at = undefined - return Promise.resolve(claim) - case IdMap.getId("fail-return"): - claim.return_order.status = "requested" - return Promise.resolve(claim) - case IdMap.getId("fail-refund"): - claim.refund_amount = 123 - return Promise.resolve(claim) - default: - return Promise.resolve(claim) - } - }, - }) - - const claimService = new ClaimService({ - manager: MockManager, - claimRepository: claimRepo, - fulfillmentService, - eventBusService, - returnService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("fails if fulfillment isn't canceled", async () => { - await expect( - claimService.cancel(IdMap.getId("fail-fulfillment")) - ).rejects.toThrow( - "All fulfillments must be canceled before the claim can be canceled" - ) - }) - - it("fails if return isn't canceled", async () => { - await expect( - claimService.cancel(IdMap.getId("fail-return")) - ).rejects.toThrow( - "Return must be canceled before the claim can be canceled" - ) - }) - - it("fails if associated with a refund", async () => { - await expect( - claimService.cancel(IdMap.getId("fail-refund")) - ).rejects.toThrow("Claim with a refund cannot be canceled") - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/csv-parser.js b/packages/medusa/src/services/__tests__/csv-parser.js deleted file mode 100644 index 84190db258..0000000000 --- a/packages/medusa/src/services/__tests__/csv-parser.js +++ /dev/null @@ -1,403 +0,0 @@ -import { createContainer } from "awilix" -import { Readable } from "stream" -import { AbstractCsvValidator } from "../../interfaces/csv-parser" -import CsvParser from "../csv-parser" -import { currencies } from "../../utils/currencies" - -describe("CsvParser", () => { - describe("parse", () => { - const csvParser = new CsvParser({ - columns: [], - }) - - let csvContent = - 'title,subtitle\n"T-shirt","summer tee"\n"Sunglasses","Red sunglasses"' - - let expectedProducts = [ - { - title: "T-shirt", - subtitle: "summer tee", - }, - { - title: "Sunglasses", - subtitle: "Red sunglasses", - }, - ] - - afterEach(() => { - jest.clearAllMocks() - }) - - it("given a readable stream, can parse the stream content", async () => { - const stream = Readable.from(csvContent) - const content = await csvParser.parse(stream) - - expect(content).toEqual(expectedProducts) - }) - }) - - describe("buildData", () => { - describe("schema validation", () => { - class TitleValidator extends AbstractCsvValidator { - async validate(builtLine) { - if (/\d/.test(builtLine["title"])) { - throw new Error("title should not contain a number") - } - return true - } - } - - const schema = { - columns: [ - { - name: "title", - validator: new TitleValidator(createContainer()), - }, - { - name: "size", - }, - { - name: "height", - }, - ], - } - - const csvParser = new CsvParser(schema) - - it("given a line containing a column which is not defined in the schema, then validation should fail", async () => { - try { - await csvParser.buildData([ - { - title: "sunglasses", - size: "M", - height: "100", - first_name: "lebron", - }, - ]) - } catch (err) { - expect(err.message).toEqual( - "Unable to treat column first_name from the csv file. No target column found in the provided schema" - ) - } - }) - - it("given a line containing a column which does not pass a validation constraint, then validation should fail", async () => { - try { - await csvParser.buildData([ - { title: "contains a number 1", size: "M", height: "100" }, - ]) - } catch (err) { - expect(err.message).toEqual("title should not contain a number") - } - }) - - it("given a line which passes all validation constraints, then should returned validated content", async () => { - const content = await csvParser.buildData([ - { title: "great product", size: "M", height: "100" }, - ]) - - expect(content).toEqual([ - { - title: "great product", - size: "M", - height: "100", - }, - ]) - }) - - it("given a line which does not provide a value for a required column, then should throw an error", async () => { - try { - await csvParser.buildData([{ size: "S", height: "100" }]) - } catch (err) { - expect(err.message).toEqual( - `Missing column(s) "title" from the given csv file` - ) - } - }) - - it("given a line which does not provide a value for multiple required columns, then should throw an error", async () => { - try { - await csvParser.buildData([{ size: "S" }]) - } catch (err) { - expect(err.message).toEqual( - `Missing column(s) "title", "height" from the given csv file` - ) - } - }) - - it("given a line which does not provide a value for a required column, then should throw an error", async () => { - try { - await csvParser.buildData([ - { title: "t-shirt", height: "100", size: "" }, - ]) - } catch (err) { - expect(err.message).toEqual( - `No value found for target column "size" in line 1 of the given csv file` - ) - } - }) - }) - - describe("mapTo", () => { - const csvParser = new CsvParser({ - columns: [ - { - name: "title", - mapTo: "product_title", - }, - ], - }) - - it("given a mapTo field for a column, when building data including that column, should rename the column name to what mapTo refers to", async () => { - const content = await csvParser.buildData([{ title: "a product" }]) - - expect(content).toEqual([ - { - product_title: "a product", - }, - ]) - }) - }) - - describe("transformer", () => { - const csvParser = new CsvParser({ - columns: [ - { - name: "title", - }, - { - name: "price usd", - transform: (value) => Math.round(Number(value) * 100), - }, - ], - }) - - it("given a transformer function for a column, when building data, should transform that column's value according to the transformation function", async () => { - const content = await csvParser.buildData([ - { title: "medusa t-shirt", "price usd": "19.99" }, - ]) - - expect(content).toEqual([ - { - title: "medusa t-shirt", - "price usd": 1999, - }, - ]) - }) - }) - - describe("match", () => { - describe("regex", () => { - const csvParser = new CsvParser({ - columns: [ - { - name: "title", - }, - { - name: "prices", - match: /.*Variant Price.*/i, - transform: (value) => Math.round(Number(value) * 100), - }, - ], - }) - - it("given a column with the match property as regex and a transformer, when building data, should resolve that column for all entries in the line that match the regex", async () => { - const content = await csvParser.buildData([ - { - title: "medusa t-shirt", - "variant price usd": "19.99", - "variant price cad": "26.79", - "variant price dkk": "1389", - }, - { - title: "medusa sunglasses", - "variant price usd": "9.99", - "variant price cad": "16.79", - "variant price dkk": "389", - }, - ]) - - expect(content).toEqual([ - { - title: "medusa t-shirt", - "variant price usd": 1999, - "variant price cad": 2679, - "variant price dkk": 138900, - }, - { - title: "medusa sunglasses", - "variant price usd": 999, - "variant price cad": 1679, - "variant price dkk": 38900, - }, - ]) - }) - }) - - describe("reducer", () => { - const schema = { - columns: [ - { - name: "title", - }, - { - name: "prices", - match: /.*Variant Price ([a-z]+).*/i, - reducer: (builtLine, key, value) => { - const [, currency_code] = key.match( - /.*Variant Price ([a-z]+).*/i - ) - const existingPrices = builtLine.prices ?? [] - const price = { - amount: Math.round(Number(value) * 100), - currency_code, - } - return { - ...builtLine, - prices: [...existingPrices, price], - } - }, - validator: { - validate: (builtLine) => { - const unexistingCurrency = builtLine.prices?.find( - (price) => !currencies[price.currency_code.toUpperCase()] - ) - if (unexistingCurrency) { - throw new Error( - `wrong currency: ${unexistingCurrency.currency_code}` - ) - } - return true - }, - }, - }, - ], - } - const csvParser = new CsvParser(schema) - - it("given a column with match and reducer properties, when building data, should return the result of the reducer function", async () => { - const content = await csvParser.buildData([ - { - title: "medusa t-shirt", - "variant price usd": "19.99", - "variant price cad": "26.79", - "variant price dkk": "1389", - }, - { - title: "medusa sunglasses", - "variant price usd": "9.99", - "variant price cad": "16.79", - "variant price dkk": "389", - }, - ]) - - expect(content).toEqual([ - { - title: "medusa t-shirt", - prices: [ - { - currency_code: "usd", - amount: 1999, - }, - { - currency_code: "cad", - amount: 2679, - }, - { - currency_code: "dkk", - amount: 138900, - }, - ], - }, - { - title: "medusa sunglasses", - prices: [ - { - currency_code: "usd", - amount: 999, - }, - { - currency_code: "cad", - amount: 1679, - }, - { - currency_code: "dkk", - amount: 38900, - }, - ], - }, - ]) - }) - - it("given a column with match and reducer properties, when building data, should run validation on the built data", async () => { - try { - await csvParser.buildData([ - { - title: "medusa t-shirt", - "variant price usd": "19.99", - "variant price cad": "26.79", - "variant price grp": "1389", - }, - { - title: "medusa sunglasses", - "variant price usd": "9.99", - "variant price cad": "16.79", - "variant price grp": "389", - }, - ]) - } catch (err) { - expect(err.message).toEqual("wrong currency: grp") - } - }) - - describe("invalid column properties", () => { - const schema = { - columns: [ - { - name: "title", - }, - { - name: "variants", - match: /.*Variant Price ([a-z]+).*/i, - mapTo: "prices", - }, - ], - } - const csvParser = new CsvParser(schema) - - it("given a column with match and mapTo property, when building data, then the mapTo property should be ignored", async () => { - const content = await csvParser.buildData([ - { - title: "medusa t-shirt", - "variant price usd": "19.99", - "variant price cad": "26.79", - "variant price dkk": "1389", - }, - { - title: "medusa sunglasses", - "variant price usd": "9.99", - "variant price cad": "16.79", - "variant price dkk": "389", - }, - ]) - - expect(content).toEqual([ - { - title: "medusa t-shirt", - "variant price usd": "19.99", - "variant price cad": "26.79", - "variant price dkk": "1389", - }, - { - title: "medusa sunglasses", - "variant price usd": "9.99", - "variant price cad": "16.79", - "variant price dkk": "389", - }, - ]) - }) - }) - }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/currency.ts b/packages/medusa/src/services/__tests__/currency.ts deleted file mode 100644 index 1ccbbc40af..0000000000 --- a/packages/medusa/src/services/__tests__/currency.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import TaxInclusivePricingFeatureFlag from "../../loaders/feature-flags/tax-inclusive-pricing" -import { Currency } from "../../models" -import CurrencyService from "../currency" -import EventBusService from "../event-bus" - -const currencyCode = IdMap.getId("currency-1") -const eventBusServiceMock = { - emit: jest.fn(), - withTransaction: function () { - return this - }, -} as unknown as EventBusService -const currencyRepositoryMock = MockRepository({ - findOne: jest.fn().mockImplementation(() => { - return { - code: currencyCode, - } - }), - save: jest.fn().mockImplementation((data) => { - return Object.assign(new Currency(), data) - }), -}) - -describe("CurrencyService", () => { - const currencyService = new CurrencyService({ - manager: MockManager, - currencyRepository: currencyRepositoryMock, - eventBusService: eventBusServiceMock, - featureFlagRouter: new FlagRouter({ - [TaxInclusivePricingFeatureFlag.key]: true, - }), - }) - - afterEach(() => { - jest.clearAllMocks() - }) - - it("should retrieve the currency by calling the repository findOne method", async () => { - await currencyService.retrieveByCode(currencyCode) - expect(currencyRepositoryMock.findOne).toHaveBeenCalledWith({ - where: { code: currencyCode.toLowerCase() }, - }) - }) - - it("should update the currency by calling the save method", async () => { - await currencyService.update(currencyCode, { - includes_tax: true, - }) - expect(currencyRepositoryMock.findOne).toHaveBeenCalledWith({ - where: { code: currencyCode.toLowerCase() }, - }) - expect(currencyRepositoryMock.save).toHaveBeenCalledWith({ - code: currencyCode, - includes_tax: true, - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/custom-shipping-option.js b/packages/medusa/src/services/__tests__/custom-shipping-option.js deleted file mode 100644 index 39b77d9873..0000000000 --- a/packages/medusa/src/services/__tests__/custom-shipping-option.js +++ /dev/null @@ -1,135 +0,0 @@ -import { MockManager, MockRepository } from "medusa-test-utils" -import CustomShippingOptionService from "../custom-shipping-option" - -describe("CustomShippingOptionService", () => { - describe("list", () => { - const customShippingOptionRepository = MockRepository({ - find: (q) => { - return Promise.resolve([ - { - id: "cso-test", - shipping_option_id: "test-so", - price: 0, - cart_id: "test-cso-cart", - }, - ]) - }, - }) - - const customShippingOptionService = new CustomShippingOptionService({ - manager: MockManager, - customShippingOptionRepository, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls customShippingOptionRepository find method", async () => { - await customShippingOptionService.list( - { cart_id: "test-cso-cart" }, - { - relations: ["shipping_option"], - } - ) - expect(customShippingOptionRepository.find).toHaveBeenCalledTimes(1) - expect(customShippingOptionRepository.find).toHaveBeenCalledWith({ - where: { - cart_id: "test-cso-cart", - }, - relations: { - shipping_option: true, - }, - }) - }) - }) - - describe("retrieve", () => { - const customShippingOptionRepository = MockRepository({ - findOne: (q) => { - if (q.where.id === "cso-test") { - return Promise.resolve({ - id: "cso-test", - shipping_option_id: "test-so", - price: 0, - cart_id: "test-cso-cart", - }) - } - }, - }) - - const customShippingOptionService = new CustomShippingOptionService({ - manager: MockManager, - customShippingOptionRepository, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls customShippingOptionRepository findOne method", async () => { - await customShippingOptionService.retrieve("cso-test", { - relations: ["shipping_option", "cart"], - }) - - expect(customShippingOptionRepository.findOne).toHaveBeenCalledTimes(1) - expect(customShippingOptionRepository.findOne).toHaveBeenCalledWith({ - where: { id: "cso-test" }, - relations: { - shipping_option: true, - cart: true, - }, - }) - }) - - it("fails when custom shipping option is not found", async () => { - expect(customShippingOptionService.retrieve("bad-cso")).rejects.toThrow( - `Custom shipping option with id: bad-cso was not found.` - ) - }) - }) - - describe("create", () => { - const customShippingOptionRepository = MockRepository({ - create: jest.fn().mockImplementation((f) => ({ id: "test-cso", ...f })), - save: jest.fn().mockImplementation((f) => Promise.resolve(f)), - }) - - const customShippingOptionService = new CustomShippingOptionService({ - manager: MockManager, - customShippingOptionRepository, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls customShippingOptionRepository create method", async () => { - const customShippingOption = { - cart_id: "test-cso-cart", - shipping_option_id: "test-so", - price: 30, - } - await customShippingOptionService.create(customShippingOption) - - expect(customShippingOptionRepository.create).toHaveBeenCalledTimes(1) - expect(customShippingOptionRepository.create).toHaveBeenCalledWith([ - { - cart_id: "test-cso-cart", - shipping_option_id: "test-so", - price: 30, - }, - ]) - - expect(customShippingOptionRepository.save).toHaveBeenCalledTimes(1) - expect(customShippingOptionRepository.save).toHaveBeenCalledWith({ - 0: { - cart_id: "test-cso-cart", - shipping_option_id: "test-so", - price: 30, - }, - id: "test-cso", - }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/customer.js b/packages/medusa/src/services/__tests__/customer.js deleted file mode 100644 index 9bf4bbd1e7..0000000000 --- a/packages/medusa/src/services/__tests__/customer.js +++ /dev/null @@ -1,458 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import CustomerService from "../customer" - -const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - return this - }, -} - -const customerGroupService = { - withTransaction: function () { - return this - }, - list: jest.fn().mockImplementation(() => Promise.resolve()), -} - -describe("CustomerService", () => { - describe("retrieve", () => { - const customerRepository = MockRepository({ - findOne: () => Promise.resolve({ id: IdMap.getId("ironman") }), - }) - const customerService = new CustomerService({ - manager: MockManager, - customerRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully retrieves a customer", async () => { - const result = await customerService.retrieve(IdMap.getId("ironman")) - - expect(customerRepository.findOne).toHaveBeenCalledTimes(1) - expect(customerRepository.findOne).toHaveBeenCalledWith({ - where: { id: IdMap.getId("ironman") }, - }) - - expect(result.id).toEqual(IdMap.getId("ironman")) - }) - }) - - describe("retrieveByEmail", () => { - const customerRepository = MockRepository({ - findOne: () => Promise.resolve({ id: IdMap.getId("ironman") }), - }) - const customerService = new CustomerService({ - manager: MockManager, - customerRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully retrieves a customer by email", async () => { - const result = await customerService.retrieveByEmail("tony@stark.com") - - expect(customerRepository.findOne).toHaveBeenCalledTimes(1) - expect(customerRepository.findOne).toHaveBeenCalledWith({ - where: { email: "tony@stark.com" }, - }) - - expect(result.id).toEqual(IdMap.getId("ironman")) - }) - - it("successfully retrieves a guest customer by email", async () => { - const result = await customerService.retrieveUnregisteredByEmail( - "tony@stark.com" - ) - - expect(customerRepository.findOne).toHaveBeenCalledTimes(1) - expect(customerRepository.findOne).toHaveBeenCalledWith({ - where: { email: "tony@stark.com", has_account: false }, - }) - - expect(result.id).toEqual(IdMap.getId("ironman")) - }) - - it("successfully retrieves a registered customer by email", async () => { - const result = await customerService.retrieveRegisteredByEmail( - "tony@stark.com" - ) - - expect(customerRepository.findOne).toHaveBeenCalledTimes(1) - expect(customerRepository.findOne).toHaveBeenCalledWith({ - where: { email: "tony@stark.com", has_account: true }, - }) - - expect(result.id).toEqual(IdMap.getId("ironman")) - }) - }) - - describe("retrieveByPhone", () => { - const customerRepository = MockRepository({ - findOne: () => Promise.resolve({ id: IdMap.getId("ironman") }), - }) - const customerService = new CustomerService({ - manager: MockManager, - customerRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully retrieves a customer by email", async () => { - const result = await customerService.retrieveByPhone("12341234") - - expect(customerRepository.findOne).toHaveBeenCalledTimes(1) - expect(customerRepository.findOne).toHaveBeenCalledWith({ - where: { phone: "12341234" }, - }) - - expect(result.id).toEqual(IdMap.getId("ironman")) - }) - }) - - describe("create", () => { - const customerRepository = { - ...MockRepository({ - findOne: (query) => { - if (query.where.email === "tony@stark.com") { - return Promise.resolve({ - id: IdMap.getId("exists"), - has_account: true, - password_hash: "test", - }) - } - return undefined - }, - }), - listAndCount: jest.fn().mockImplementation((query, q) => { - if (query.where.email === "tony@stark.com") { - return Promise.resolve([ - [ - { - id: IdMap.getId("exists"), - has_account: true, - password_hash: "test", - }, - ], - 0, - ]) - } - return Promise.resolve([[], 0]) - }), - } - - const configModule = { - projectConfig: { - jwt_secret: "test", - }, - } - const customerService = new CustomerService({ - manager: MockManager, - customerRepository, - eventBusService, - configModule, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully creates a customer with password", async () => { - await customerService.create({ - email: "john@doe.com", - first_name: "John", - last_name: "Doe", - password: "test", - }) - - expect(customerRepository.create).toBeCalledTimes(1) - expect(customerRepository.create).toBeCalledWith({ - email: "john@doe.com", - first_name: "John", - last_name: "Doe", - has_account: true, - password_hash: expect.anything(), - }) - }) - - it("calls listAndCount with email", async () => { - await customerService.create({ - email: "john@doe.com", - first_name: "John", - last_name: "Doe", - password: "test", - }) - - expect(customerRepository.listAndCount).toHaveBeenCalledWith( - { - relations: {}, - skip: 0, - take: 2, - where: { - email: "john@doe.com", - }, - }, - undefined - ) - }) - - it("successfully creates a one time customer", async () => { - await customerService.create({ - email: "john@doe.com", - first_name: "John", - last_name: "Doe", - }) - - expect(customerRepository.create).toBeCalledTimes(1) - expect(customerRepository.create).toBeCalledWith({ - email: "john@doe.com", - first_name: "John", - last_name: "Doe", - }) - }) - - it("Fails to create a customer with an existing account", async () => { - expect.assertions(1) - await customerService - .create({ - email: "tony@stark.com", - password: "stark123", - }) - .catch((err) => { - expect(err.message).toEqual( - "A customer with the given email already has an account. Log in instead" - ) - }) - }) - }) - - describe("update", () => { - const customerRepository = MockRepository({ - findOne: (query) => { - return Promise.resolve({ id: IdMap.getId("ironman") }) - }, - }) - - const addressRepository = MockRepository({ - create: (data) => data, - save: (data) => Promise.resolve(data), - }) - - const customerService = new CustomerService({ - manager: MockManager, - addressRepository, - customerRepository, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully updates a customer", async () => { - await customerService.update(IdMap.getId("ironman"), { - first_name: "Olli", - last_name: "Test", - }) - - expect(customerRepository.save).toBeCalledTimes(1) - expect(customerRepository.save).toBeCalledWith({ - id: IdMap.getId("ironman"), - first_name: "Olli", - last_name: "Test", - }) - }) - - it("successfully updates customer metadata", async () => { - await customerService.update(IdMap.getId("ironman"), { - metadata: { - some: "test", - }, - }) - - expect(customerRepository.save).toBeCalledTimes(1) - expect(customerRepository.save).toBeCalledWith({ - id: IdMap.getId("ironman"), - metadata: { - some: "test", - }, - }) - }) - - it("successfully updates with billing address", async () => { - await customerService.update(IdMap.getId("ironman"), { - first_name: "Olli", - last_name: "Test", - billing_address: { - first_name: "Olli", - last_name: "Juhl", - address_1: "Laksegade", - city: "Copenhagen", - country_code: "DK", - postal_code: "2100", - phone: "+1 (222) 333 4444", - }, - }) - - expect(customerRepository.save).toBeCalledTimes(1) - expect(customerRepository.save).toBeCalledWith({ - id: IdMap.getId("ironman"), - first_name: "Olli", - last_name: "Test", - billing_address: { - first_name: "Olli", - last_name: "Juhl", - address_1: "Laksegade", - city: "Copenhagen", - country_code: "dk", - postal_code: "2100", - phone: "+1 (222) 333 4444", - }, - }) - }) - }) - - describe("update customer groups", () => { - const customerRepository = MockRepository({ - findOne: (query) => { - return Promise.resolve({ id: IdMap.getId("ironman") }) - }, - }) - - const addressRepository = MockRepository({ - create: (data) => data, - save: (data) => Promise.resolve(data), - }) - - const customerGroupRepository = MockRepository({ - findByIds: jest.fn().mockImplementation(() => Promise.resolve()), - }) - - const customerService = new CustomerService({ - manager: MockManager, - addressRepository, - customerRepository, - customerGroupRepository, - customerGroupService, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - describe("updateAddress", () => { - const addressRepository = MockRepository({ - findOne: (query) => { - return Promise.resolve({ - id: IdMap.getId("hollywood-boulevard"), - address_1: "Hollywood Boulevard 2", - }) - }, - }) - - const customerService = new CustomerService({ - manager: MockManager, - addressRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully updates address", async () => { - await customerService.updateAddress( - IdMap.getId("ironman"), - IdMap.getId("hollywood-boulevard"), - { - first_name: "Tony", - last_name: "Stark", - address_1: "Hollywood Boulevard 1", - city: "Los Angeles", - country_code: "us", - postal_code: "90046", - phone: "+1 (222) 333 4444", - } - ) - - expect(addressRepository.save).toBeCalledTimes(1) - expect(addressRepository.save).toBeCalledWith({ - id: IdMap.getId("hollywood-boulevard"), - first_name: "Tony", - last_name: "Stark", - address_1: "Hollywood Boulevard 1", - city: "Los Angeles", - country_code: "us", - postal_code: "90046", - phone: "+1 (222) 333 4444", - }) - }) - }) - - describe("removeAddress", () => { - const addressRepository = MockRepository({ - findOne: (query) => { - return Promise.resolve({ - id: IdMap.getId("hollywood-boulevard"), - address_1: "Hollywood Boulevard 2", - }) - }, - }) - - const customerService = new CustomerService({ - manager: MockManager, - addressRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully deletes address", async () => { - await customerService.removeAddress( - IdMap.getId("ironman"), - IdMap.getId("hollywood-boulevard") - ) - - expect(addressRepository.softRemove).toBeCalledTimes(1) - expect(addressRepository.softRemove).toBeCalledWith({ - id: IdMap.getId("hollywood-boulevard"), - address_1: "Hollywood Boulevard 2", - }) - }) - }) - - describe("delete", () => { - const customerRepository = MockRepository({ - findOne: (query) => { - return Promise.resolve({ id: IdMap.getId("ironman") }) - }, - }) - - const customerService = new CustomerService({ - manager: MockManager, - customerRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully deletes customer", async () => { - await customerService.delete(IdMap.getId("ironman")) - - expect(customerRepository.softRemove).toBeCalledTimes(1) - expect(customerRepository.softRemove).toBeCalledWith({ - id: IdMap.getId("ironman"), - }) - }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/discount.js b/packages/medusa/src/services/__tests__/discount.js deleted file mode 100644 index 107028d836..0000000000 --- a/packages/medusa/src/services/__tests__/discount.js +++ /dev/null @@ -1,1348 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { FlagRouter } from "@medusajs/utils" -import DiscountService from "../discount" -import { TotalsServiceMock } from "../__mocks__/totals" -import { newTotalsServiceMock } from "../__mocks__/new-totals" -import { In } from "typeorm" - -const featureFlagRouter = new FlagRouter({}) - -const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - return this - }, -} - -describe("DiscountService", () => { - describe("create", () => { - const discountRepository = MockRepository({}) - const discountRuleRepository = MockRepository({}) - - const regionService = { - retrieve: () => { - return { - id: IdMap.getId("france"), - } - }, - withTransaction: function () { - return this - }, - } - - const discountService = new DiscountService({ - manager: MockManager, - discountRepository, - discountRuleRepository, - regionService, - featureFlagRouter, - eventBusService - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("fails to create a fixed discount with multiple regions", async () => { - expect.assertions(3) - try { - await discountService.create({ - code: "test", - rule: { - type: "fixed", - allocation: "total", - value: 20, - }, - regions: [IdMap.getId("france"), IdMap.getId("Italy")], - }) - } catch (err) { - expect(err.type).toEqual("invalid_data") - expect(err.message).toEqual("Fixed discounts can have one region") - expect(discountRepository.create).toHaveBeenCalledTimes(0) - } - }) - - it("fails to create a discount without regions", async () => { - const err = await discountService - .create({ - code: "test", - rule: { - type: "fixed", - allocation: "total", - value: 20, - }, - }) - .catch((e) => e) - - expect(err.type).toEqual("invalid_data") - expect(err.message).toEqual("Discount must have at least 1 region") - expect(discountRepository.create).toHaveBeenCalledTimes(0) - }) - - it("successfully creates discount", async () => { - await discountService.create({ - code: "test", - rule: { - type: "percentage", - allocation: "total", - value: 20, - }, - regions: [IdMap.getId("france")], - }) - - expect(discountRuleRepository.create).toHaveBeenCalledTimes(1) - expect(discountRuleRepository.create).toHaveBeenCalledWith({ - type: "percentage", - allocation: "total", - value: 20, - }) - - expect(discountRuleRepository.save).toHaveBeenCalledTimes(1) - - expect(discountRepository.create).toHaveBeenCalledTimes(1) - expect(discountRepository.create).toHaveBeenCalledWith({ - code: "test", - rule: expect.anything(), - regions: [{ id: IdMap.getId("france") }], - }) - - expect(discountRepository.save).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith(DiscountService.Events.CREATED, {id: undefined}) - }) - - it("successfully creates discount with start and end dates", async () => { - await discountService.create({ - code: "test", - rule: { - type: "percentage", - allocation: "total", - value: 20, - }, - starts_at: new Date("03/14/2021"), - ends_at: new Date("03/15/2021"), - regions: [IdMap.getId("france")], - }) - - expect(discountRuleRepository.create).toHaveBeenCalledTimes(1) - expect(discountRuleRepository.create).toHaveBeenCalledWith({ - type: "percentage", - allocation: "total", - value: 20, - }) - - expect(discountRuleRepository.save).toHaveBeenCalledTimes(1) - - expect(discountRepository.create).toHaveBeenCalledTimes(1) - expect(discountRepository.create).toHaveBeenCalledWith({ - code: "test", - rule: expect.anything(), - regions: [{ id: IdMap.getId("france") }], - starts_at: new Date("03/14/2021"), - ends_at: new Date("03/15/2021"), - }) - - expect(discountRepository.save).toHaveBeenCalledTimes(1) - }) - - it("successfully creates discount with start date and a valid duration", async () => { - await discountService.create({ - code: "test", - rule: { - type: "percentage", - allocation: "total", - value: 20, - }, - starts_at: new Date("03/14/2021"), - valid_duration: "P0Y0M1D", - regions: [IdMap.getId("france")], - }) - - expect(discountRuleRepository.create).toHaveBeenCalledTimes(1) - expect(discountRuleRepository.create).toHaveBeenCalledWith({ - type: "percentage", - allocation: "total", - value: 20, - }) - - expect(discountRuleRepository.save).toHaveBeenCalledTimes(1) - - expect(discountRepository.create).toHaveBeenCalledTimes(1) - expect(discountRepository.create).toHaveBeenCalledWith({ - code: "test", - rule: expect.anything(), - regions: [{ id: IdMap.getId("france") }], - starts_at: new Date("03/14/2021"), - valid_duration: "P0Y0M1D", - }) - - expect(discountRepository.save).toHaveBeenCalledTimes(1) - }) - }) - - describe("retrieve", () => { - const discountRepository = MockRepository({ - findOne: (query) => { - if (query.where.id) { - return Promise.resolve({ id: IdMap.getId("total10") }) - } - return Promise.resolve(undefined) - }, - }) - - const discountService = new DiscountService({ - manager: MockManager, - discountRepository, - featureFlagRouter, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully retrieves discount", async () => { - await discountService.retrieve(IdMap.getId("total10")) - expect(discountRepository.findOne).toHaveBeenCalledTimes(1) - expect(discountRepository.findOne).toHaveBeenCalledWith({ - where: { - id: IdMap.getId("total10"), - }, - }) - }) - - it("throws on invalid discount id", async () => { - try { - await discountService.retrieve(IdMap.getId("invalid")) - } catch (error) { - expect(error.message).toBe( - `Discount with ${IdMap.getId("invalid")} was not found` - ) - } - }) - }) - - describe("retrieveByCode", () => { - const discountRepository = MockRepository({ - findOne: (query) => { - if (query.where.code === "10%OFF") { - return Promise.resolve({ id: IdMap.getId("total10"), code: "10%OFF" }) - } - if (query.where.code === "DYNAMIC") { - return Promise.resolve({ id: IdMap.getId("total10"), code: "10%OFF" }) - } - return Promise.resolve(undefined) - }, - }) - - const discountService = new DiscountService({ - manager: MockManager, - discountRepository, - featureFlagRouter, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully finds discount by code", async () => { - await discountService.retrieveByCode("10%OFF") - expect(discountRepository.findOne).toHaveBeenCalledTimes(1) - expect(discountRepository.findOne).toHaveBeenCalledWith({ - where: { - code: "10%OFF", - }, - }) - }) - - it("successfully trims, uppdercases, and finds discount by code", async () => { - await discountService.retrieveByCode(" 10%Off ") - expect(discountRepository.findOne).toHaveBeenCalledTimes(1) - expect(discountRepository.findOne).toHaveBeenCalledWith({ - where: { - code: "10%OFF", - }, - }) - }) - }) - - describe("listByCodes", () => { - const discountRepository = MockRepository({ - find: (query) => { - if (query.where.code.value.includes("10%OFF")) { - return Promise.resolve([ - { id: IdMap.getId("total10"), code: "10%OFF" }, - ]) - } - if (query.where.code.value.includes("DYNAMIC")) { - return Promise.resolve([ - { id: IdMap.getId("total10"), code: "10%OFF" }, - ]) - } - return Promise.resolve([]) - }, - }) - - const discountService = new DiscountService({ - manager: MockManager, - discountRepository, - featureFlagRouter, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully finds discount by code", async () => { - await discountService.listByCodes(["10%OFF"]) - expect(discountRepository.find).toHaveBeenCalledTimes(1) - expect(discountRepository.find).toHaveBeenCalledWith({ - where: { - code: In(["10%OFF"]), - }, - }) - }) - - it("successfully trims, uppdercases, and finds discount by code", async () => { - await discountService.listByCodes([" 10%Off "]) - expect(discountRepository.find).toHaveBeenCalledTimes(1) - expect(discountRepository.find).toHaveBeenCalledWith({ - where: { - code: In(["10%OFF"]), - }, - }) - }) - }) - - describe("update", () => { - const discountRepository = MockRepository({ - findOne: () => - Promise.resolve({ - id: IdMap.getId("total10"), - code: "10%OFF", - rule: { type: "fixed" }, - }), - }) - - const discountRuleRepository = MockRepository({ - create: (values) => values, - }) - - const regionService = { - retrieve: () => { - return { - id: IdMap.getId("france"), - } - }, - } - - const discountService = new DiscountService({ - manager: MockManager, - discountRepository, - discountRuleRepository, - regionService, - featureFlagRouter, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("fails to update a fixed discount with multiple regions", async () => { - expect.assertions(3) - try { - await discountService.update(IdMap.getId("total10"), { - code: "test", - regions: [IdMap.getId("france"), IdMap.getId("Italy")], - }) - } catch (err) { - expect(err.type).toEqual("invalid_data") - expect(err.message).toEqual("Fixed discounts can have one region") - expect(discountRepository.create).toHaveBeenCalledTimes(0) - } - }) - - it("successfully updates discount", async () => { - await discountService.update(IdMap.getId("total10"), { - code: "test", - regions: [IdMap.getId("france")], - }) - expect(discountRepository.save).toHaveBeenCalledTimes(1) - expect(discountRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("total10"), - code: "TEST", - rule: { type: "fixed" }, - regions: [{ id: IdMap.getId("france") }], - }) - }) - - it("successfully updates discount rule", async () => { - await discountService.update(IdMap.getId("total10"), { - rule: { type: "fixed", value: 10, allocation: "total" }, - }) - expect(discountRepository.save).toHaveBeenCalledTimes(1) - expect(discountRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("total10"), - code: "10%OFF", - rule: { type: "fixed", value: 10, allocation: "total" }, - }) - }) - - it("successfully updates metadata", async () => { - await discountService.update(IdMap.getId("total10"), { - metadata: { testKey: "testValue" }, - }) - expect(discountRepository.save).toHaveBeenCalledTimes(1) - expect(discountRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("total10"), - rule: { type: "fixed" }, - code: "10%OFF", - metadata: { testKey: "testValue" }, - }) - }) - }) - - describe("addRegion", () => { - const discountRepository = MockRepository({ - findOne: (q) => { - if (q.where.id === "fixed") { - return Promise.resolve({ - id: IdMap.getId("total10"), - regions: [{ id: IdMap.getId("test-region") }], - rule: { - type: "fixed", - }, - }) - } - return Promise.resolve({ - id: IdMap.getId("total10"), - regions: [{ id: IdMap.getId("test-region") }], - rule: { - type: "percentage", - }, - }) - }, - }) - - const discountRuleRepository = MockRepository({}) - - const regionService = { - retrieve: () => { - return { - id: IdMap.getId("test-region-2"), - } - }, - } - - const discountService = new DiscountService({ - manager: MockManager, - discountRepository, - discountRuleRepository, - regionService, - featureFlagRouter, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("fails to add a region to a fixed discount with an existing region", async () => { - expect.assertions(3) - try { - await discountService.addRegion("fixed", IdMap.getId("test-region-2")) - } catch (err) { - expect(err.type).toEqual("invalid_data") - expect(err.message).toEqual("Fixed discounts can have one region") - expect(discountRepository.save).toHaveBeenCalledTimes(0) - } - }) - - it("successfully adds a region", async () => { - await discountService.addRegion( - IdMap.getId("total10"), - IdMap.getId("test-region-2") - ) - - expect(discountRepository.save).toHaveBeenCalledTimes(1) - expect(discountRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("total10"), - regions: [ - { id: IdMap.getId("test-region") }, - { id: IdMap.getId("test-region-2") }, - ], - rule: { - type: "percentage", - }, - }) - }) - - it("successfully resolves if region already exists", async () => { - await discountService.addRegion( - IdMap.getId("total10"), - IdMap.getId("test-region") - ) - - expect(discountRepository.save).toHaveBeenCalledTimes(0) - }) - }) - - describe("createDynamicDiscount", () => { - const discountRepository = MockRepository({ - create: (d) => d, - findOne: () => - Promise.resolve({ - id: "parent", - is_dynamic: true, - rule_id: "parent_rule", - valid_duration: "P1Y", - }), - }) - - const discountRuleRepository = MockRepository({}) - - const regionService = { - retrieve: () => { - return { - id: IdMap.getId("test-region"), - } - }, - } - - const discountService = new DiscountService({ - manager: MockManager, - discountRepository, - discountRuleRepository, - regionService, - featureFlagRouter, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully removes a region", async () => { - await discountService.createDynamicCode("former", { - code: "hi", - }) - - expect(discountRepository.save).toHaveBeenCalledTimes(1) - expect(discountRepository.save).toHaveBeenCalledWith({ - is_dynamic: true, - is_disabled: false, - rule_id: "parent_rule", - parent_discount_id: "parent", - code: "HI", - usage_limit: undefined, - ends_at: expect.any(Date), - }) - }) - }) - - describe("removeRegion", () => { - const discountRepository = MockRepository({ - findOne: () => - Promise.resolve({ - id: IdMap.getId("total10"), - regions: [{ id: IdMap.getId("test-region") }], - }), - }) - - const discountRuleRepository = MockRepository({}) - - const regionService = { - retrieve: () => { - return { - id: IdMap.getId("test-region"), - } - }, - } - - const discountService = new DiscountService({ - manager: MockManager, - discountRepository, - discountRuleRepository, - regionService, - featureFlagRouter, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully removes a region", async () => { - await discountService.removeRegion( - IdMap.getId("total10"), - IdMap.getId("test-region") - ) - - expect(discountRepository.save).toHaveBeenCalledTimes(1) - expect(discountRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("total10"), - regions: [], - }) - }) - - it("successfully resolve if region does not exist", async () => { - await discountService.removeRegion( - IdMap.getId("total10"), - IdMap.getId("test-region-2") - ) - - expect(discountRepository.save).toHaveBeenCalledTimes(0) - }) - }) - - describe("listAndCount", () => { - const discountRepository = MockRepository({ - findAndCount: () => - Promise.resolve([ - { - id: IdMap.getId("total10"), - code: "OLITEST", - }, - ]), - }) - - const discountService = new DiscountService({ - manager: MockManager, - discountRepository, - featureFlagRouter, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("calls repository function with query and default config", async () => { - await discountService.listAndCount({ q: "OLI" }) - - expect(discountRepository.findAndCount).toHaveBeenCalledTimes(1) - expect(discountRepository.findAndCount).toHaveBeenCalledWith({ - where: expect.anything(), - skip: 0, - take: 20, - order: { created_at: "DESC" }, - }) - }) - - it("calls repository function specified query", async () => { - await discountService.listAndCount( - {}, - { skip: 50, take: 50, order: { created_at: "ASC" } } - ) - - expect(discountRepository.findAndCount).toHaveBeenCalledTimes(1) - expect(discountRepository.findAndCount).toHaveBeenCalledWith({ - where: {}, - skip: 50, - take: 50, - order: { created_at: "ASC" }, - }) - }) - }) - - describe("calculateDiscountForLineItem", () => { - const discountRepository = MockRepository({ - findOne: ({ where }) => { - if (where.id === "disc_percentage") { - return Promise.resolve({ - code: "MEDUSA", - rule: { - type: "percentage", - allocation: "total", - value: 15, - }, - }) - } - if (where.id === "disc_fixed_total") { - return Promise.resolve({ - code: "MEDUSA", - rule: { - type: "fixed", - allocation: "total", - value: 400, - }, - }) - } - return Promise.resolve({ - id: "disc_fixed", - code: "MEDUSA", - rule: { - type: "fixed", - allocation: "item", - value: 200, - }, - }) - }, - }) - - const totalsService = { - ...TotalsServiceMock, - getSubtotal: async () => { - return 1100 - }, - } - - const newTotalsService = { - ...newTotalsServiceMock, - getLineItemTotals: async () => { - return [ - { - subtotal: 1100, - }, - ] - }, - } - - const discountService = new DiscountService({ - manager: MockManager, - discountRepository, - totalsService, - newTotalsService, - featureFlagRouter, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("correctly calculates fixed + item discount", async () => { - const adjustment = await discountService.calculateDiscountForLineItem( - "disc_fixed", - { - unit_price: 300, - quantity: 2, - allow_discounts: true, - } - ) - - expect(adjustment).toBe(400) - }) - - it("correctly calculates fixed + total discount", async () => { - let item = { - unit_price: 400, - quantity: 2, - allow_discounts: true, - } - - const adjustment1 = await discountService.calculateDiscountForLineItem( - "disc_fixed_total", - item, - { - items: [item], - } - ) - - item = { - unit_price: 300, - quantity: 1, - allow_discounts: true, - } - - const adjustment2 = await discountService.calculateDiscountForLineItem( - "disc_fixed_total", - item, - { - items: [item], - } - ) - - // 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 () => { - const adjustment = await discountService.calculateDiscountForLineItem( - "disc_fixed", - { - unit_price: 100, - quantity: 1, - allow_discounts: true, - } - ) - - expect(adjustment).toBe(100) - }) - - it("correctly calculates percentage discount", async () => { - const adjustment = await discountService.calculateDiscountForLineItem( - "disc_percentage", - { - unit_price: 400, - quantity: 2, - allow_discounts: true, - } - ) - - expect(adjustment).toBe(120) - }) - - it("returns full amount if exceeds total line item amount", async () => { - const adjustment = await discountService.calculateDiscountForLineItem( - "disc_fixed", - { - unit_price: 50, - quantity: 2, - allow_discounts: true, - } - ) - - expect(adjustment).toBe(100) - }) - - it("returns early if discounts are not allowed", async () => { - const adjustment = await discountService.calculateDiscountForLineItem( - "disc_percentage", - { - unit_price: 400, - quantity: 2, - allow_discounts: false, - } - ) - - expect(adjustment).toBe(0) - }) - }) - - describe("validateDiscountForCartOrThrow", () => { - const discount = { code: "TEST" } - const getCart = (id) => { - if (id === "with-d") { - return { - id: "cart", - discounts: [ - { - code: "1234", - rule: { - type: "fixed", - }, - }, - { - code: "FS1234", - rule: { - type: "free_shipping", - }, - }, - ], - region_id: "good", - items: [ - { - id: "li1", - quantity: 2, - unit_price: 1000, - }, - { - id: "li2", - quantity: 1, - unit_price: 500, - }, - ], - } - } - if (id === "with-d-and-customer") { - return { - id: "with-d-and-customer", - discounts: [ - { - code: "ApplicableForCustomer", - rule: { - type: "fixed", - }, - }, - ], - region_id: "good", - customer_id: "test-customer", - } - } - return { - id: "cart", - discounts: [ - { - code: "CODE", - rule: { - type: "percentage", - }, - }, - ], - region_id: "good", - items: [ - { - id: "li1", - quantity: 2, - unit_price: 1000, - }, - { - id: "li2", - quantity: 1, - unit_price: 500, - }, - ], - } - } - - let discountService - - beforeEach(async () => { - discountService = new DiscountService({ - manager: MockManager, - featureFlagRouter, - }) - const hasReachedLimitMock = jest.fn().mockImplementation(() => false) - const isDisabledMock = jest.fn().mockImplementation(() => false) - const isValidForRegionMock = jest - .fn() - .mockImplementation(() => Promise.resolve(true)) - const canApplyForCustomerMock = jest.fn().mockImplementation(() => { - return Promise.resolve(true) - }) - discountService.hasReachedLimit = hasReachedLimitMock - discountService.isDisabled = isDisabledMock - discountService.canApplyForCustomer = canApplyForCustomerMock - discountService.isValidForRegion = isValidForRegionMock - }) - - it("calls all validation methods when cart includes a customer_id and doesn't throw", async () => { - const discount = { - id: "10off", - code: "10%OFF", - regions: [{ id: "good" }], - rule: { - id: "10off-rule", - type: "percentage", - }, - } - const cart = getCart("with-d-and-customer") - const result = await discountService.validateDiscountForCartOrThrow( - cart, - discount - ) - expect(result).toBeUndefined() - - expect(discountService.hasReachedLimit).toHaveBeenCalledTimes(1) - expect(discountService.hasReachedLimit).toHaveBeenCalledWith(discount) - - expect(discountService.isDisabled).toHaveBeenCalledTimes(1) - expect(discountService.isDisabled).toHaveBeenCalledWith(discount) - - expect(discountService.isValidForRegion).toHaveBeenCalledTimes(1) - expect(discountService.isValidForRegion).toHaveBeenCalledWith( - discount, - cart.region_id - ) - - expect(discountService.canApplyForCustomer).toHaveBeenCalledTimes(1) - expect(discountService.canApplyForCustomer).toHaveBeenCalledWith( - discount.rule.id, - cart.customer_id - ) - }) - - it("throws when hasReachedLimit returns true", async () => { - const cart = getCart("with-d-and-customer") - discountService.hasReachedLimit = jest.fn().mockImplementation(() => true) - - expect( - discountService.validateDiscountForCartOrThrow(cart, discount) - ).rejects.toThrow({ - message: `Discount ${discount.code} has been used maximum allowed times`, - }) - }) - - it("throws when hasNotStarted returns true", async () => { - const cart = getCart("with-d-and-customer") - discountService.hasNotStarted = jest.fn().mockImplementation(() => true) - - expect( - discountService.validateDiscountForCartOrThrow(cart, discount) - ).rejects.toThrow({ - message: `Discount ${discount.code} is not valid yet`, - }) - }) - - it("throws when hasExpired returns true", async () => { - const cart = getCart("with-d-and-customer") - discountService.hasExpired = jest.fn().mockImplementation(() => true) - - expect( - discountService.validateDiscountForCartOrThrow(cart, discount) - ).rejects.toThrow({ - message: `Discount ${discount.code} is expired`, - }) - }) - - it("throws when isDisabled returns true", async () => { - const cart = getCart("with-d-and-customer") - discountService.isDisabled = jest.fn().mockImplementation(() => true) - - expect( - discountService.validateDiscountForCartOrThrow(cart, discount) - ).rejects.toThrow({ - message: `The discount code ${discount.code} is disabled`, - }) - }) - - it("throws when isValidForRegion returns false", async () => { - const discount = {} - const cart = getCart("with-d-and-customer") - discountService.isValidForRegion = jest - .fn() - .mockImplementation(() => Promise.resolve(false)) - - expect( - discountService.validateDiscountForCartOrThrow(cart, discount) - ).rejects.toThrow({ - message: "The discount is not available in current region", - }) - }) - - it("throws when canApplyForCustomer returns false", async () => { - const discount_ = { code: discount.code, rule: { id: "" } } - const cart = getCart("with-d-and-customer") - discountService.canApplyForCustomer = jest - .fn() - .mockImplementation(() => Promise.resolve(false)) - - expect( - discountService.validateDiscountForCartOrThrow(cart, discount_) - ).rejects.toThrow({ - message: `Discount ${discount.code} is not valid for customer`, - }) - }) - }) - - describe("hasReachedLimit", () => { - const discountService = new DiscountService({ - featureFlagRouter, - }) - - it("returns true if discount limit is reached", () => { - const discount = { - id: "limit-reached", - code: "limit-reached", - regions: [{ id: "good" }], - rule: {}, - usage_count: 2, - usage_limit: 2, - } - const hasReachedLimit = discountService.hasReachedLimit(discount) - expect(hasReachedLimit).toBe(true) - }) - - it("returns false if discount limit is not reached", () => { - const discount = { - id: "limit-reached", - code: "limit-reached", - regions: [{ id: "good" }], - rule: {}, - usage_count: 1, - usage_limit: 100, - } - - const hasReachedLimit = discountService.hasReachedLimit(discount) - expect(hasReachedLimit).toBe(false) - }) - - it("returns false if discount limit is not set", () => { - const discount = { - id: "limit-reached", - code: "limit-reached", - regions: [{ id: "good" }], - rule: {}, - usage_count: 1, - } - - const hasReachedLimit = discountService.hasReachedLimit(discount) - expect(hasReachedLimit).toBe(false) - }) - }) - - describe("isDisabled", () => { - const discountService = new DiscountService({ - featureFlagRouter, - }) - - it("returns false if discount not disabled", async () => { - const discount = { - id: "10off", - code: "10%OFF", - regions: [{ id: "good" }], - rule: { - id: "10off-rule", - type: "percentage", - }, - is_disabled: false, - } - - const isDisabled = discountService.isDisabled(discount) - expect(isDisabled).toBe(false) - }) - - it("returns true if discount is disabled", async () => { - const discount = { - id: "10off", - code: "10%OFF", - regions: [{ id: "good" }], - rule: { - id: "10off-rule", - type: "percentage", - }, - is_disabled: true, - } - - const isDisabled = discountService.isDisabled(discount) - expect(isDisabled).toBe(true) - }) - }) - - describe("hasNotStarted", () => { - const discountService = new DiscountService({ - featureFlagRouter, - }) - - it("returns true if discount has a future starts_at date", async () => { - const discount = { - id: "10off", - code: "10%OFF", - regions: [{ id: "good" }], - rule: { - type: "percentage", - }, - starts_at: getOffsetDate(1), - ends_at: getOffsetDate(10), - } - - const hasNotStarted = discountService.hasNotStarted(discount) - expect(hasNotStarted).toBe(true) - }) - - it("returns false if discount has a past starts_at date", async () => { - const discount = { - id: "10off", - code: "10%OFF", - regions: [{ id: "good" }], - rule: { - type: "percentage", - }, - starts_at: getOffsetDate(-2), - ends_at: getOffsetDate(10), - } - - const hasNotStarted = discountService.hasNotStarted(discount) - expect(hasNotStarted).toBe(false) - }) - }) - - describe("hasExpired", () => { - const discountService = new DiscountService({ - featureFlagRouter, - }) - - it("returns false if discount has a future ends_at date", async () => { - const discount = { - id: "10off", - code: "10%OFF", - regions: [{ id: "good" }], - rule: { - type: "percentage", - }, - ends_at: getOffsetDate(10), - starts_at: getOffsetDate(-1), - } - - const hasExpired = discountService.hasExpired(discount) - expect(hasExpired).toBe(false) - }) - - it("returns true if discount has a past ends_at date", async () => { - const discount = { - id: "10off", - code: "10%OFF", - regions: [{ id: "good" }], - rule: { - type: "percentage", - }, - starts_at: getOffsetDate(-10), - ends_at: getOffsetDate(-1), - } - - const hasExpired = discountService.hasExpired(discount) - expect(hasExpired).toBe(true) - }) - }) - - describe("isValidForRegion", () => { - const retrieveMock = jest.fn().mockImplementation((id) => { - if (id === "parent-discount-us") { - return Promise.resolve({ - id, - regions: [{ id: "us" }], - rule: { - id: "10off-rule", - type: "percentage", - }, - }) - } else if (id === "parent-discount-dk") { - return Promise.resolve({ - id, - regions: [{ id: "dk" }], - rule: { - id: "10off-rule", - type: "percentage", - }, - }) - } - }) - - const discountService = new DiscountService({ - manager: MockManager, - featureFlagRouter, - }) - discountService.retrieve = retrieveMock - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("returns false if discount is not available in a given region", async () => { - const discount = { - id: "10off", - code: "10%OFF", - regions: [{ id: "us" }], - rule: { - id: "10off-rule", - type: "percentage", - }, - } - - const isValidForRegion = await discountService.isValidForRegion( - discount, - "dk" - ) - - expect(retrieveMock).toBeCalledTimes(0) - expect(isValidForRegion).toBe(false) - }) - - it("returns true if discount is available in a given region", async () => { - const discount = { - id: "10off", - code: "10%OFF", - regions: [{ id: "us" }], - rule: { - id: "10off-rule", - type: "percentage", - }, - } - - const isValidForRegion = await discountService.isValidForRegion( - discount, - "us" - ) - - expect(retrieveMock).toBeCalledTimes(0) - expect(isValidForRegion).toBe(true) - }) - - it("returns false if discount has a parent discount and is not available in region", async () => { - const discount = { - id: "10off", - code: "10%OFF", - parent_discount_id: "parent-discount-us", - } - - const isValidForRegion = await discountService.isValidForRegion( - discount, - "dk" - ) - - expect(retrieveMock).toBeCalledTimes(1) - expect(retrieveMock).toBeCalledWith(discount.parent_discount_id, { - relations: ["rule", "regions"], - }) - expect(isValidForRegion).toBe(false) - }) - - it("returns true if discount has a parent discount and is available in region", async () => { - const discount = { - id: "10off", - code: "10%OFF", - parent_discount_id: "parent-discount-dk", - } - - const isValidForRegion = await discountService.isValidForRegion( - discount, - "dk" - ) - expect(retrieveMock).toBeCalledTimes(1) - expect(retrieveMock).toBeCalledWith(discount.parent_discount_id, { - relations: ["rule", "regions"], - }) - expect(isValidForRegion).toBe(true) - }) - }) - - describe("canApplyForCustomer", () => { - const discountConditionRepository = { - canApplyForCustomer: jest - .fn() - .mockImplementation(() => Promise.resolve(true)), - } - - const customerService = { - withTransaction: function () { - return this - }, - retrieve: jest.fn().mockImplementation((id) => { - if (id === "customer-no-groups") { - return Promise.resolve({ id: "customer-no-groups" }) - } - if (id === "customer-with-groups") { - return Promise.resolve({ - id: "customer-with-groups", - groups: [{ id: "group-1" }], - }) - } - }), - } - - const discountService = new DiscountService({ - manager: MockManager, - discountConditionRepository, - customerService, - featureFlagRouter, - }) - - it("returns false on undefined customer id", async () => { - const res = await discountService.canApplyForCustomer("rule-1") - - expect(res).toBe(false) - - expect( - discountConditionRepository.canApplyForCustomer - ).toHaveBeenCalledTimes(0) - }) - - it("returns true on customer with groups", async () => { - const res = await discountService.canApplyForCustomer( - "rule-1", - "customer-with-groups" - ) - - expect(res).toBe(true) - - expect( - discountConditionRepository.canApplyForCustomer - ).toHaveBeenCalledTimes(1) - expect( - discountConditionRepository.canApplyForCustomer - ).toHaveBeenCalledWith("rule-1", "customer-with-groups") - }) - }) -}) - -const getOffsetDate = (offset) => { - const date = new Date() - date.setDate(date.getDate() + offset) - return date -} diff --git a/packages/medusa/src/services/__tests__/draft-order.js b/packages/medusa/src/services/__tests__/draft-order.js deleted file mode 100644 index 90424698d9..0000000000 --- a/packages/medusa/src/services/__tests__/draft-order.js +++ /dev/null @@ -1,370 +0,0 @@ -import { MockManager, MockRepository } from "medusa-test-utils" -import { EventBusServiceMock } from "../__mocks__/event-bus" -import DraftOrderService from "../draft-order" -import { LineItemAdjustmentServiceMock } from "../__mocks__/line-item-adjustment" - -const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - return this - }, -} - -describe("DraftOrderService", () => { - describe("create", () => { - const regionService = { - retrieve: () => - Promise.resolve({ id: "test-region", countries: [{ iso_2: "dk" }] }), - withTransaction: function () { - return this - }, - } - - const shippingOptionService = { - createShippingMethod: jest.fn().mockImplementation(() => - Promise.resolve({ - shipping_option: { - profile_id: "test-profile", - }, - }) - ), - withTransaction: function () { - return this - }, - } - - const lineItemService = { - generate: jest.fn().mockImplementation(() => - Promise.resolve([ - { - title: "test-item", - variant_id: "test-variant", - }, - ]) - ), - create: jest.fn().mockImplementation((data) => data), - withTransaction: function () { - return this - }, - } - - const productVariantService = { - retrieve: () => - Promise.resolve({ - id: "test-variant", - product: { - profile_id: "test-profile", - }, - }), - withTransaction: function () { - return this - }, - } - - const testOrder = { - region_id: "test-region", - shipping_address_id: "test-shipping", - billing_address_id: "test-billing", - customer_id: "test-customer", - items: [ - { id: "test", variant_id: "test-variant", quantity: 2, metadata: {} }, - ], - shipping_methods: [ - { - option_id: "test-option", - data: {}, - }, - ], - } - - const cartService = { - create: jest.fn().mockImplementation((data) => - Promise.resolve({ - id: "test-cart", - ...data, - }) - ), - retrieve: jest.fn().mockReturnValue( - Promise.resolve({ - id: "test-cart", - ...testOrder, - }) - ), - retrieveWithTotals: jest.fn().mockReturnValue( - Promise.resolve({ - id: "test-cart", - ...testOrder, - }) - ), - update: jest.fn(), - applyDiscount: jest.fn(), - addShippingMethod: jest.fn(), - withTransaction: function () { - return this - }, - } - - const addressRepository = MockRepository({ - create: (addr) => ({ - ...addr, - }), - }) - - const draftOrderRepository = MockRepository({ - create: (d) => ({ - ...d, - }), - save: (d) => ({ - id: "test-draft-order", - ...d, - }), - }) - - const draftOrderService = new DraftOrderService({ - manager: MockManager, - regionService, - cartService, - shippingOptionService, - lineItemService, - lineItemAdjustmentService: LineItemAdjustmentServiceMock, - productVariantService, - draftOrderRepository, - addressRepository, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("creates a draft order", async () => { - const cartId = "test-cart" - const title = "test-item" - - await draftOrderService.create(testOrder) - - expect(draftOrderRepository.create).toHaveBeenCalledTimes(1) - expect(draftOrderRepository.create).toHaveBeenCalledWith({ - cart_id: cartId, - }) - - expect(cartService.create).toHaveBeenCalledTimes(1) - expect(cartService.create).toHaveBeenCalledWith({ - region_id: "test-region", - shipping_address_id: "test-shipping", - billing_address_id: "test-billing", - customer_id: "test-customer", - type: "draft_order", - }) - - expect(cartService.addShippingMethod).toHaveBeenCalledTimes(1) - expect(cartService.addShippingMethod).toHaveBeenCalledWith( - { - id: "test-cart", - ...testOrder, - }, - "test-option", - {} - ) - - expect(lineItemService.generate).toHaveBeenCalledTimes(1) - expect(lineItemService.generate).toHaveBeenCalledWith( - [ - { - variantId: "test-variant", - quantity: 2, - metadata: {}, - unit_price: undefined, - }, - ], - { - region_id: "test-region", - } - ) - - expect(lineItemService.create).toHaveBeenCalledTimes(1) - expect(lineItemService.create).toHaveBeenCalledWith([ - { - cart_id: cartId, - title, - variant_id: "test-variant", - }, - ]) - - expect(cartService.applyDiscount).toHaveBeenCalledTimes(0) - }) - - it("creates a draft order with a discount", async () => { - const cartId = "test-cart" - const title = "test-item" - - const originalTestOrder = { ...testOrder } - - testOrder["discounts"] = [{ code: "TEST" }] - await draftOrderService.create(testOrder) - - expect(draftOrderRepository.create).toHaveBeenCalledTimes(1) - expect(draftOrderRepository.create).toHaveBeenCalledWith({ - cart_id: cartId, - }) - - expect(cartService.create).toHaveBeenCalledTimes(1) - expect(cartService.create).toHaveBeenCalledWith({ - region_id: "test-region", - shipping_address_id: "test-shipping", - billing_address_id: "test-billing", - customer_id: "test-customer", - type: "draft_order", - }) - - expect(cartService.addShippingMethod).toHaveBeenCalledTimes(1) - expect(cartService.addShippingMethod).toHaveBeenCalledWith( - { - id: "test-cart", - ...originalTestOrder, - }, - "test-option", - {} - ) - - expect(lineItemService.generate).toHaveBeenCalledTimes(1) - expect(lineItemService.generate).toHaveBeenCalledWith( - [ - { - variantId: "test-variant", - quantity: 2, - metadata: {}, - unit_price: undefined, - }, - ], - { - region_id: "test-region", - } - ) - - expect(lineItemService.create).toHaveBeenCalledTimes(1) - expect(lineItemService.create).toHaveBeenCalledWith([ - { - cart_id: cartId, - title, - variant_id: "test-variant", - }, - ]) - - expect(cartService.update).toHaveBeenCalledTimes(1) - expect(cartService.update).toHaveBeenCalledWith(cartId, { - discounts: testOrder.discounts, - }) - }) - - it("fails on missing region", async () => { - try { - await draftOrderService.create({ - items: [], - }) - } catch (error) { - expect(error.message).toEqual( - `region_id is required to create a draft order` - ) - } - }) - - it("creating a draft order without items is allowed", async () => { - await draftOrderService.create({ - region_id: "test-region", - items: [], - shipping_methods: [], - }) - }) - }) - - describe("update", () => { - const testOrder = { - region_id: "test-region", - shipping_address_id: "test-shipping", - billing_address_id: "test-billing", - customer_id: "test-customer", - items: [{ variant_id: "test-variant", quantity: 2, metadata: {} }], - shipping_methods: [ - { - option_id: "test-option", - data: {}, - }, - ], - } - - const completedOrder = { - status: "completed", - ...testOrder, - } - - const draftOrderRepository = MockRepository({ - create: (d) => ({ - ...d, - }), - save: (d) => ({ - id: "test-draft-order", - ...d, - }), - findOne: (q) => { - switch (q.where.id) { - case "completed": - return Promise.resolve(completedOrder) - default: - return Promise.resolve(testOrder) - } - }, - }) - - const draftOrderService = new DraftOrderService({ - manager: MockManager, - regionService: undefined, - cartService: undefined, - shippingOptionService: undefined, - lineItemService: undefined, - lineItemAdjustmentService: LineItemAdjustmentServiceMock, - productVariantService: undefined, - draftOrderRepository, - addressRepository: undefined, - eventBusService: EventBusServiceMock, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("calls draftOrder model functions", async () => { - await draftOrderService.update("test-draft-order", { - no_notification_order: true, - }) - - expect(draftOrderRepository.save).toHaveBeenCalledTimes(1) - expect(draftOrderRepository.save).toHaveBeenCalledWith({ - no_notification_order: true, - billing_address_id: "test-billing", - customer_id: "test-customer", - items: [ - { - metadata: {}, - quantity: 2, - variant_id: "test-variant", - }, - ], - region_id: "test-region", - shipping_address_id: "test-shipping", - shipping_methods: [ - { - data: {}, - option_id: "test-option", - }, - ], - }) - }) - - it("fails to update draftOrder when already complete", async () => { - await expect(draftOrderService.update("completed", {})).rejects.toThrow( - "Can't update a draft order which is complete" - ) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/fulfillment.js b/packages/medusa/src/services/__tests__/fulfillment.js deleted file mode 100644 index 62eb4371e7..0000000000 --- a/packages/medusa/src/services/__tests__/fulfillment.js +++ /dev/null @@ -1,216 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import FulfillmentService from "../fulfillment" -import { ProductVariantInventoryServiceMock } from "../__mocks__/product-variant-inventory" - -describe("FulfillmentService", () => { - describe("createFulfillment", () => { - const fulfillmentRepository = MockRepository({}) - - const fulfillmentProviderService = { - createFulfillment: jest.fn().mockImplementation((data) => { - return Promise.resolve(data) - }), - } - - const shippingProfileService = { - retrieve: jest.fn().mockImplementation((data) => { - return Promise.resolve({ - id: IdMap.getId("default"), - name: "default_profile", - products: [IdMap.getId("product")], - shipping_options: [], - }) - }), - } - - const lineItemRepository = { - create: jest.fn().mockImplementation((data) => { - return data - }), - } - - const fulfillmentService = new FulfillmentService({ - manager: MockManager, - fulfillmentProviderService, - fulfillmentRepository, - shippingProfileService, - lineItemRepository, - productVariantInventoryService: ProductVariantInventoryServiceMock, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully create a fulfillment", async () => { - await fulfillmentService.createFulfillment( - { - shipping_methods: [ - { - shipping_option: { - profile_id: IdMap.getId("default"), - provider_id: "GLS Express", - }, - }, - ], - items: [{ id: IdMap.getId("test-line"), quantity: 9 }], - }, - [ - { - item_id: IdMap.getId("test-line"), - quantity: 9, - }, - ], - { order_id: "test", metadata: {} } - ) - - expect(fulfillmentRepository.create).toHaveBeenCalledTimes(1) - expect(fulfillmentRepository.create).toHaveBeenCalledWith({ - order_id: "test", - provider_id: "GLS Express", - items: [{ item_id: IdMap.getId("test-line"), quantity: 9 }], - data: expect.anything(), - metadata: {}, - }) - }) - - it("throws if too many items are requested fulfilled", async () => { - await expect( - fulfillmentService.createFulfillment( - { - shipping_methods: [ - { - profile_id: IdMap.getId("default"), - provider_id: "GLS Express", - }, - ], - items: [ - { - id: IdMap.getId("test-line"), - quantity: 10, - fulfilled_quantity: 0, - }, - ], - }, - [ - { - item_id: IdMap.getId("test-line"), - quantity: 12, - }, - ] - ) - ).rejects.toThrow("Cannot fulfill more items than have been purchased") - }) - }) - - describe("cancelFulfillment", () => { - const fulfillmentRepository = MockRepository({ - findOne: () => - Promise.resolve({ - canceled_at: new Date(), - items: [{ item_id: 1, quantity: 2 }], - }), - save: (f) => f, - }) - - const lineItemService = { - retrieve: jest - .fn() - .mockImplementation(() => - Promise.resolve({ id: 1, fulfilled_quantity: 2 }) - ), - update: jest.fn(), - withTransaction: function () { - return this - }, - } - - const fulfillmentProviderService = { - cancelFulfillment: (f) => f, - } - - const fulfillmentService = new FulfillmentService({ - manager: MockManager, - fulfillmentProviderService, - fulfillmentRepository, - lineItemService, - productVariantInventoryService: ProductVariantInventoryServiceMock, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("correctly cancels fulfillment", async () => { - await fulfillmentService.cancelFulfillment(IdMap.getId("fulfillment")) - - expect(fulfillmentRepository.save).toHaveBeenCalledTimes(1) - expect(fulfillmentRepository.save).toHaveBeenCalledWith({ - canceled_at: expect.any(Date), - items: expect.any(Array), - }) - - expect(lineItemService.retrieve).toHaveBeenCalledTimes(1) - expect(lineItemService.retrieve).toHaveBeenCalledWith(1) - expect(lineItemService.update).toHaveBeenCalledTimes(1) - expect(lineItemService.update).toHaveBeenCalledWith(1, { - fulfilled_quantity: 0, - }) - }) - }) - - describe("createShipment", () => { - const trackingLinkRepository = MockRepository({ create: (c) => c }) - const fulfillmentRepository = MockRepository({ - findOne: (q) => { - switch (q.where.id) { - case IdMap.getId("canceled"): - return Promise.resolve({ canceled_at: new Date() }) - default: - return Promise.resolve({ id: IdMap.getId("fulfillment") }) - } - }, - }) - - const fulfillmentService = new FulfillmentService({ - manager: MockManager, - fulfillmentRepository, - trackingLinkRepository, - }) - - const now = new Date() - beforeEach(async () => { - jest.clearAllMocks() - jest.spyOn(global, "Date").mockImplementationOnce(() => now) - }) - - it("calls order model functions", async () => { - await fulfillmentService.createShipment( - IdMap.getId("fulfillment"), - [{ tracking_number: "1234" }, { tracking_number: "2345" }], - {} - ) - - expect(fulfillmentRepository.save).toHaveBeenCalledTimes(1) - expect(fulfillmentRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("fulfillment"), - tracking_links: [ - { tracking_number: "1234" }, - { tracking_number: "2345" }, - ], - metadata: {}, - shipped_at: now, - }) - }) - - it("fails when status is canceled", async () => { - await expect( - fulfillmentService.createShipment( - IdMap.getId("canceled"), - [({ tracking_number: "1234" }, { tracking_number: "2345" })], - {} - ) - ).rejects.toThrow("Fulfillment has been canceled") - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/gift-card.js b/packages/medusa/src/services/__tests__/gift-card.js deleted file mode 100644 index 74c28479d6..0000000000 --- a/packages/medusa/src/services/__tests__/gift-card.js +++ /dev/null @@ -1,240 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" - -import GiftCardService from "../gift-card" - -describe("GiftCardService", () => { - const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - return this - }, - } - - describe("create", () => { - const giftCardRepo = MockRepository({ - create: (s) => { - return Promise.resolve(s) - }, - save: (s) => { - return Promise.resolve(s) - }, - }) - - const regionService = { - withTransaction: function () { - return this - }, - retrieve: () => { - return Promise.resolve({ - id: IdMap.getId("region-id"), - tax_rate: 19, - }) - }, - } - - const giftCardService = new GiftCardService({ - manager: MockManager, - giftCardRepository: giftCardRepo, - regionService: regionService, - eventBusService: eventBusService, - }) - - const giftCard = { - region_id: IdMap.getId("region-id"), - order_id: IdMap.getId("order-id"), - is_disabled: true, - } - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("correctly creates a giftcard", async () => { - await giftCardService.create(giftCard) - - expect(giftCardRepo.create).toHaveBeenCalledTimes(1) - expect(giftCardRepo.create).toHaveBeenCalledWith({ - region_id: IdMap.getId("region-id"), - order_id: IdMap.getId("order-id"), - is_disabled: true, - code: expect.any(String), - tax_rate: null - }) - }) - }) - - describe("retrieve", () => { - const giftCardRepo = MockRepository({ - findOne: () => { - return Promise.resolve({}) - }, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - const giftCardService = new GiftCardService({ - manager: MockManager, - giftCardRepository: giftCardRepo, - }) - - it("it calls order model functions", async () => { - await giftCardService.retrieve(IdMap.getId("gift-card"), { - relations: ["region"], - select: ["id"], - }) - - expect(giftCardRepo.findOne).toHaveBeenCalledTimes(1) - expect(giftCardRepo.findOne).toHaveBeenCalledWith({ - relationLoadStrategy: "query", - relations: { region: true }, - select: { id: true }, - where: { id: IdMap.getId("gift-card") }, - }) - }) - }) - - describe("retrieveByCode", () => { - const giftCardRepo = MockRepository({ - findOne: () => { - return Promise.resolve({}) - }, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - const giftCardService = new GiftCardService({ - manager: MockManager, - giftCardRepository: giftCardRepo, - }) - - it("it calls order model functions", async () => { - await giftCardService.retrieveByCode("1234-1234-1234-1234", { - relations: ["region"], - select: ["id"], - }) - - expect(giftCardRepo.findOne).toHaveBeenCalledTimes(1) - expect(giftCardRepo.findOne).toHaveBeenCalledWith({ - "relationLoadStrategy": "query", - "relations": {"region": true}, - "select": {"id": true}, - "where": {"code": "1234-1234-1234-1234"} - }) - }) - }) - - describe("update", () => { - const giftCard = { - region_id: IdMap.getId("region-id"), - order_id: IdMap.getId("order-id"), - is_disabled: true, - value: 5000, - } - - const giftCardRepo = MockRepository({ - findOne: (s) => { - return Promise.resolve(giftCard) - }, - save: (s) => { - return Promise.resolve(s) - }, - }) - - const regionService = { - withTransaction: function () { - return this - }, - retrieve: () => { - return Promise.resolve({ - id: IdMap.getId("other-region"), - }) - }, - } - - const giftCardService = new GiftCardService({ - manager: MockManager, - giftCardRepository: giftCardRepo, - regionService: regionService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("calls order model functions", async () => { - await giftCardService.update(IdMap.getId("giftcard-id"), { - is_disabled: false, - region_id: IdMap.getId("other-region"), - }) - - expect(giftCardRepo.save).toHaveBeenCalledTimes(1) - expect(giftCardRepo.save).toHaveBeenCalledWith({ - region_id: IdMap.getId("other-region"), - order_id: IdMap.getId("order-id"), - is_disabled: false, - value: 5000, - }) - }) - - it.each([[-100], [6000]])( - "fails to update balance with illegal input '%s'", - async (input) => { - await expect( - giftCardService.update(IdMap.getId("giftcard-id"), { - balance: input, - }) - ).rejects.toThrow("new balance is invalid") - } - ) - }) - - describe("delete", () => { - const giftCard = { - region_id: IdMap.getId("region-id"), - order_id: IdMap.getId("order-id"), - } - - const giftCardRepo = MockRepository({ - findOne: (s) => { - switch (s.where.id) { - case IdMap.getId("gift-card"): - return Promise.resolve(giftCard) - default: - return Promise.resolve() - } - }, - softRemove: (s) => { - return Promise.resolve() - }, - }) - - const giftCardService = new GiftCardService({ - manager: MockManager, - giftCardRepository: giftCardRepo, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully deletes existing gift-card", async () => { - await giftCardService.delete(IdMap.getId("gift-card")) - - expect(giftCardRepo.softRemove).toHaveBeenCalledTimes(1) - expect(giftCardRepo.softRemove).toHaveBeenCalledWith({ - region_id: IdMap.getId("region-id"), - order_id: IdMap.getId("order-id"), - }) - }) - - it("returns if no gift-card found", async () => { - await giftCardService.delete(IdMap.getId("other")) - - expect(giftCardRepo.softRemove).toHaveBeenCalledTimes(0) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/invite.js b/packages/medusa/src/services/__tests__/invite.js deleted file mode 100644 index 5f5a8cd557..0000000000 --- a/packages/medusa/src/services/__tests__/invite.js +++ /dev/null @@ -1,226 +0,0 @@ -import InviteService from "../invite" -import { MockManager, MockRepository } from "medusa-test-utils" -import { EventBusServiceMock } from "../__mocks__/event-bus" -import { MedusaError } from "medusa-core-utils" - -// const _MockManager - -describe("InviteService", () => { - describe("list", () => { - const inviteRepo = MockRepository({ - find: (q) => { - return Promise.resolve([{ id: "invite-test-id" }]) - }, - }) - - const inviteService = new InviteService({ - manager: { withRepository: jest.fn(() => inviteRepo) }, - userService: {}, - userRepository: {}, - inviteRepository: inviteRepo, - eventBusService: EventBusServiceMock, - }, { - projectConfig: { jwt_secret: 'superSecret' } - }) - - it("calls invite repository find", async () => { - await inviteService.list({ id: "test" }) - - expect(inviteRepo.find).toHaveBeenCalledTimes(1) - expect(inviteRepo.find).toHaveBeenCalledWith({ - where: { - id: "test", - }, - }) - }) - }) - - describe("token generation and validation", () => { - const inviteService = new InviteService({ - manager: MockManager, - userService: {}, - userRepository: {}, - inviteRepository: {}, - eventBusService: EventBusServiceMock, - }, { - projectConfig: { jwt_secret: 'superSecret' } - }) - - it("validating a signed token succeeds", () => { - const res = inviteService.verifyToken( - inviteService.generateToken({ data: "test" }) - ) - - expect(res).toEqual(expect.objectContaining({ data: "test" })) - }) - }) - - describe("accept", () => { - const inviteRepo = MockRepository({ - findOne: (q) => { - if (q.where.id === "accepted") { - return Promise.resolve(null) - } - if (q.where.id === "existingUser") { - return Promise.resolve({ - user_email: "existing@medusa-commerce.com", - token: inviteService.generateToken({ - user_email: "existing@medusa-commerce.com", - invite_id: "existingUser", - }), - }) - } - return Promise.resolve({ - id: q.where.id, - role: "admin", - user_email: "test@test.com", - token: inviteService.generateToken({ - user_email: "test@test.com", - invite_id: q.where.id, - }), - }) - }, - }) - - const userRepo = MockRepository({ - findOne: (q) => { - if (q.where.user_id === "test_user") { - return Promise.resolve({}) - } - if (q.where.email === "existing@medusa-commerce.com") { - return Promise.resolve("usr_test123") - } - return Promise.resolve(null) - }, - }) - - const createMock = { - create: jest.fn().mockImplementation((data) => { - return Promise.resolve({ ...data, email: "test@test.com" }) - }), - } - - const userServiceMock = { - withTransaction: jest.fn().mockImplementation((m) => { - return createMock - }), - } - - const inviteService = new InviteService({ - manager: MockManager, - userService: userServiceMock, - userRepository: userRepo, - inviteRepository: inviteRepo, - eventBusService: EventBusServiceMock, - }, { - projectConfig: { jwt_secret: 'superSecret' } - }) - - beforeEach(() => jest.clearAllMocks()) - - it("fails to accept an invite already accepted", async () => { - expect.assertions(1) - await inviteService - .accept( - inviteService.generateToken({ - user_email: "accepted@medusa-commerce.com", - invite_id: "accepted", - }), - {} - ) - .catch((err) => { - expect(err).toEqual( - new MedusaError(MedusaError.Types.INVALID_DATA, "Invalid invite") - ) - }) - }) - - it("fails to accept an with an invalid token", async () => { - expect.assertions(2) - await inviteService.accept("totally.valid.token", {}).catch((err) => { - expect(err.message).toEqual("Token is not valid") - expect(err.type).toEqual("invalid_data") - }) - }) - - it("fails to accept an with an existing user", async () => { - expect.assertions(1) - await inviteService - .accept( - inviteService.generateToken({ - user_email: "existing@medusa-commerce.com", - invite_id: "existingUser", - }), - {} - ) - .catch((err) => { - expect(err).toEqual( - new MedusaError( - MedusaError.Types.INVALID_DATA, - "User already joined" - ) - ) - }) - }) - it("accepts an invite", async () => { - await inviteService.accept( - inviteService.generateToken({ - user_email: "test@test.com", - invite_id: "not yet accepted", - }), - { first_name: "John", last_name: "Doe", password: "test stuff" } - ) - expect(createMock.create).toHaveBeenCalledTimes(1) - expect(createMock.create).toHaveBeenCalledWith( - { - email: "test@test.com", - role: "admin", - first_name: "John", - last_name: "Doe", - }, - "test stuff" - ) - - expect(inviteRepo.delete).toHaveBeenCalledTimes(1) - expect(inviteRepo.delete).toHaveBeenCalledWith({ - id: "not yet accepted", - }) - }) - }) - - describe("resend", () => { - const inviteRepo = MockRepository({ - findOne: (q) => { - return Promise.resolve({ - id: q.where.id, - role: "admin", - user_email: "test@test.com", - }) - }, - }) - - const inviteService = new InviteService({ - manager: { withRepository: jest.fn(() => inviteRepo) }, - userService: {}, - userRepository: {}, - inviteRepository: inviteRepo, - eventBusService: EventBusServiceMock, - }, { - projectConfig: { jwt_secret: 'superSecret' } - }) - - inviteService.generateToken = jest.fn() - - it("generates a token with the retreived invite", async () => { - await inviteService.resend("invite-test-id") - - expect(inviteRepo.findOne).toHaveBeenCalledTimes(1) - expect(inviteService.generateToken).toHaveBeenCalledTimes(1) - expect(inviteService.generateToken).toHaveBeenCalledWith({ - invite_id: "invite-test-id", - role: "admin", - user_email: "test@test.com", - }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/line-item-adjustment.js b/packages/medusa/src/services/__tests__/line-item-adjustment.js deleted file mode 100644 index 3158940d39..0000000000 --- a/packages/medusa/src/services/__tests__/line-item-adjustment.js +++ /dev/null @@ -1,307 +0,0 @@ -import { MockManager, MockRepository } from "medusa-test-utils" -import { In } from "typeorm" -import LineItemAdjustmentService from "../line-item-adjustment" -import { DiscountServiceMock } from "../__mocks__/discount" -import { EventBusServiceMock } from "../__mocks__/event-bus" - -describe("LineItemAdjustmentService", () => { - describe("list", () => { - const lineItemAdjustmentRepo = MockRepository({ - find: (q) => { - return Promise.resolve([ - { - id: "lia-1", - description: "discount", - amount: 1000, - item: "li-1", - discount_id: "disc_1", - }, - ]) - }, - }) - - const lineItemAdjustmentService = new LineItemAdjustmentService({ - manager: MockManager, - lineItemAdjustmentRepository: lineItemAdjustmentRepo, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls lineItemAdjustment list method", async () => { - await lineItemAdjustmentService.list( - { item_id: "li-1" }, - { - relations: ["item"], - } - ) - expect(lineItemAdjustmentRepo.find).toHaveBeenCalledTimes(1) - expect(lineItemAdjustmentRepo.find).toHaveBeenCalledWith({ - where: { - item_id: "li-1", - }, - relations: { "item": true }, - }) - }) - }) - - describe("retrieve", () => { - const lineItemAdjustmentRepo = MockRepository({ - findOne: (q) => { - switch (q.where.id) { - case "lia-1": - return Promise.resolve({ - id: "lia-1", - description: "discount", - }) - default: - return Promise.resolve() - } - }, - }) - - const lineItemAdjustmentService = new LineItemAdjustmentService({ - manager: MockManager, - lineItemAdjustmentRepository: lineItemAdjustmentRepo, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls lineItemAdjustment retrieve method", async () => { - await lineItemAdjustmentService.retrieve("lia-1", { - relations: ["item"], - }) - - expect(lineItemAdjustmentRepo.findOne).toHaveBeenCalledTimes(1) - expect(lineItemAdjustmentRepo.findOne).toHaveBeenCalledWith({ - where: { id: "lia-1" }, - relations: { "item": true }, - }) - }) - - it("fails when lineItemAdjustment is not found", async () => { - await expect( - lineItemAdjustmentService.retrieve("not-existing") - ).rejects.toThrow( - `Line item adjustment with id: not-existing was not found` - ) - }) - }) - - describe("create", () => { - const lineItemAdjustment = { - id: "lia-1", - amount: 2000, - description: "discount", - item_id: "li-3", - discount_id: "disc_999", - } - - const lineItemAdjustmentRepo = MockRepository({ - create: (f) => lineItemAdjustment, - save: (f) => Promise.resolve(lineItemAdjustment), - }) - - const lineItemAdjustmentService = new LineItemAdjustmentService({ - manager: MockManager, - lineItemAdjustmentRepository: lineItemAdjustmentRepo, - eventBusService: EventBusServiceMock, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls lineItemAdjustment create method", async () => { - await lineItemAdjustmentService.create({ - amount: 2000, - description: "discount", - item_id: "li-3", - discount_id: "disc_999", - }) - - expect(lineItemAdjustmentRepo.create).toHaveBeenCalledTimes(1) - expect(lineItemAdjustmentRepo.create).toHaveBeenCalledWith({ - amount: 2000, - description: "discount", - item_id: "li-3", - discount_id: "disc_999", - }) - - expect(lineItemAdjustmentRepo.save).toHaveBeenCalledTimes(1) - expect(lineItemAdjustmentRepo.save).toHaveBeenCalledWith({ - id: "lia-1", - amount: 2000, - description: "discount", - item_id: "li-3", - discount_id: "disc_999", - }) - }) - }) - - describe("update", () => { - const lineItemAdjustment = { id: "lia-1" } - - const lineItemAdjustmentRepo = MockRepository({ - findOne: (f) => Promise.resolve(lineItemAdjustment), - save: (f) => Promise.resolve(lineItemAdjustment), - }) - - const lineItemAdjustmentService = new LineItemAdjustmentService({ - manager: MockManager, - lineItemAdjustmentRepository: lineItemAdjustmentRepo, - eventBusService: EventBusServiceMock, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls lineItemAdjustment uppdate method", async () => { - await lineItemAdjustmentService.update("lia-1", { - amount: 6000, - }) - - expect(lineItemAdjustmentRepo.save).toHaveBeenCalledTimes(1) - expect(lineItemAdjustmentRepo.save).toHaveBeenCalledWith({ - ...lineItemAdjustment, - }) - }) - }) - - describe("delete", () => { - beforeAll(async () => { - jest.clearAllMocks() - }) - - describe("delete by line item adjustment id", () => { - const lineItemAdjustment = { id: "lia-1", item_id: "li-1" } - const lineItemAdjustmentRepo = MockRepository({ - find: (f) => Promise.resolve(lineItemAdjustment), - }) - - const lineItemAdjustmentService = new LineItemAdjustmentService({ - manager: MockManager, - lineItemAdjustmentRepository: lineItemAdjustmentRepo, - eventBusService: EventBusServiceMock, - }) - - it("calls lineItemAdjustment delete method with the right params", async () => { - await lineItemAdjustmentService.delete("lia-1") - - expect(lineItemAdjustmentRepo.delete).toHaveBeenCalledTimes(1) - expect(lineItemAdjustmentRepo.delete).toHaveBeenCalledWith({ - id: In(["lia-1"]), - }) - }) - }) - - describe("delete by item ids", () => { - const lineItemAdjustment = [ - { id: "lia-1", item: "li-1" }, - { id: "lia-2", item_id: "li-2" }, - ] - const lineItemAdjustmentRepo = MockRepository({ - find: (f) => Promise.resolve(lineItemAdjustment), - }) - - const lineItemAdjustmentService = new LineItemAdjustmentService({ - manager: MockManager, - lineItemAdjustmentRepository: lineItemAdjustmentRepo, - eventBusService: EventBusServiceMock, - }) - - it("calls lineItemAdjustment delete method with the right query", async () => { - const query = { item_id: ["li-1", "li-2", "li-3"] } - await lineItemAdjustmentService.delete(query) - - expect(lineItemAdjustmentRepo.find).toHaveBeenCalledTimes(1) - expect(lineItemAdjustmentRepo.find).toHaveBeenCalledWith({ - where: { - item_id: In(query.item_id), - }, - }) - - expect(lineItemAdjustmentRepo.remove).toHaveBeenCalledTimes(1) - expect(lineItemAdjustmentRepo.remove).toHaveBeenCalledWith( - lineItemAdjustment - ) - }) - }) - }) - - describe("createAdjustments", () => { - beforeEach(async () => { - jest.clearAllMocks() - }) - - const lineItemAdjustmentRepo = MockRepository({ - find: (f) => Promise.resolve(lineItemAdjustment), - }) - - const lineItemAdjustmentService = new LineItemAdjustmentService({ - manager: MockManager, - lineItemAdjustmentRepository: lineItemAdjustmentRepo, - discountService: DiscountServiceMock, - eventBusService: EventBusServiceMock, - }) - - lineItemAdjustmentService.createAdjustmentForLineItem = jest - .fn() - .mockImplementation(() => { - return Promise.resolve({ - item_id: "li-1", - amount: 1000, - discount_id: "disc-1", - id: "lia-1", - description: "discount", - }) - }) - - it("calls createAdjustmentForLineItem once when given a line item", () => { - const cart = { - id: "cart1", - discounts: ["disc-1"], - items: [{ id: "li-1" }], - } - const lineItem = { id: "li-1" } - - lineItemAdjustmentService.createAdjustments(cart, lineItem) - expect( - lineItemAdjustmentService.createAdjustmentForLineItem - ).toHaveBeenCalledTimes(1) - expect( - lineItemAdjustmentService.createAdjustmentForLineItem - ).toHaveBeenCalledWith(cart, lineItem) - }) - - it("calls createAdjustmentForLineItem 3 times when given a cart containing 3 line items", () => { - const cart = { - id: "cart1", - discounts: ["disc-1"], - items: [ - { - id: "li-2", - }, - { - id: "li-3", - }, - { - id: "li-4", - }, - ], - } - - lineItemAdjustmentService.createAdjustments(cart) - expect( - lineItemAdjustmentService.createAdjustmentForLineItem - ).toHaveBeenCalledTimes(3) - expect( - lineItemAdjustmentService.createAdjustmentForLineItem - ).toHaveBeenNthCalledWith(1, cart, { id: "li-2" }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/line-item.js b/packages/medusa/src/services/__tests__/line-item.js deleted file mode 100644 index f2737cd03f..0000000000 --- a/packages/medusa/src/services/__tests__/line-item.js +++ /dev/null @@ -1,803 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { FlagRouter } from "@medusajs/utils" -import LineItemService from "../line-item" -import { PricingServiceMock } from "../__mocks__/pricing" -import { ProductVariantServiceMock } from "../__mocks__/product-variant" -import { RegionServiceMock } from "../__mocks__/region" - -const unknownVariantId = "unknown-variant" - -;[true, false].forEach((isTaxInclusiveEnabled) => { - describe(`tax inclusive flag set to: ${isTaxInclusiveEnabled}`, () => { - describe("LineItemService", () => { - describe("create", () => { - const lineItemRepository = MockRepository({ - create: (data) => data, - }) - - const cartRepository = MockRepository({ - findOne: () => - Promise.resolve({ - region_id: IdMap.getId("test-region"), - }), - }) - - const regionService = { - withTransaction: function () { - return this - }, - retrieve: () => { - return { - id: IdMap.getId("test-region"), - } - }, - } - - const productVariantService = { - ...ProductVariantServiceMock, - retrieve: (query) => { - if (query === IdMap.getId("test-giftcard")) { - return { - id: IdMap.getId("test-giftcard"), - title: "Test variant", - product: { - title: "Test product", - thumbnail: "", - is_giftcard: true, - discountable: false, - }, - } - } - return { - id: IdMap.getId("test-variant"), - title: "Test variant", - product: { - title: "Test product", - thumbnail: "", - }, - } - }, - getRegionPrice: () => 100, - list: jest.fn().mockImplementation(async (selector) => { - return (selector.id || []).map((id) => ({ - id, - title: "Test variant", - product: { - title: "Test product", - thumbnail: "", - discountable: false, - is_giftcard: true, - }, - })) - }), - } - - const pricingService = { - ...PricingServiceMock, - getProductVariantsPricing: () => { - return { - [IdMap.getId("test-giftcard")]: { calculated_price: 100 }, - } - }, - getProductVariantPricing: () => { - return { - calculated_price: 100, - } - }, - } - - const featureFlagRouter = new FlagRouter({ - tax_inclusive_pricing: isTaxInclusiveEnabled, - }) - - const lineItemService = new LineItemService({ - manager: MockManager, - pricingService, - lineItemRepository, - productVariantService, - regionService, - cartRepository, - featureFlagRouter, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully create a line item", async () => { - await lineItemService.create({ - variant_id: IdMap.getId("test-variant"), - cart_id: IdMap.getId("test-cart"), - title: "Test product", - description: "Test variant", - thumbnail: "", - unit_price: 100, - quantity: 1, - }) - - expect(lineItemRepository.create).toHaveBeenCalledTimes(1) - expect(lineItemRepository.create).toHaveBeenCalledWith([ - { - variant_id: IdMap.getId("test-variant"), - cart_id: IdMap.getId("test-cart"), - title: "Test product", - description: "Test variant", - thumbnail: "", - unit_price: 100, - quantity: 1, - }, - ]) - }) - - it("successfully create a line item with price and quantity", async () => { - await lineItemService.create({ - variant_id: IdMap.getId("test-variant"), - cart_id: IdMap.getId("test-cart"), - unit_price: 50, - quantity: 2, - }) - - expect(lineItemRepository.create).toHaveBeenCalledTimes(1) - expect(lineItemRepository.create).toHaveBeenCalledWith([ - { - variant_id: IdMap.getId("test-variant"), - cart_id: IdMap.getId("test-cart"), - unit_price: 50, - quantity: 2, - }, - ]) - }) - - it("successfully create a line item giftcard", async () => { - const line = await lineItemService.generate( - IdMap.getId("test-giftcard"), - IdMap.getId("test-region"), - 1 - ) - - await lineItemService.create({ - ...line, - cart_id: IdMap.getId("test-cart"), - }) - - expect(lineItemRepository.create).toHaveBeenCalledTimes(2) - expect(lineItemRepository.create).toHaveBeenNthCalledWith(2, [ - expect.objectContaining({ - allow_discounts: false, - variant_id: IdMap.getId("test-giftcard"), - cart_id: IdMap.getId("test-cart"), - title: "Test product", - description: "Test variant", - thumbnail: "", - unit_price: 100, - quantity: 1, - is_giftcard: true, - should_merge: true, - metadata: {}, - }), - ]) - }) - }) - - describe("update", () => { - const lineItemRepository = MockRepository({ - find: () => - Promise.resolve([ - { - id: IdMap.getId("test-line-item"), - variant_id: IdMap.getId("test-variant"), - variant: { - id: IdMap.getId("test-variant"), - title: "Test variant", - }, - cart_id: IdMap.getId("test-cart"), - title: "Test product", - description: "Test variant", - thumbnail: "", - unit_price: 50, - quantity: 1, - }, - ]), - }) - - const lineItemService = new LineItemService({ - manager: MockManager, - lineItemRepository, - productVariantService: ProductVariantServiceMock, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully updates a line item with quantity", async () => { - await lineItemService.update(IdMap.getId("test-line-item"), { - quantity: 2, - has_shipping: true, - }) - - expect(lineItemRepository.save).toHaveBeenCalledTimes(1) - expect(lineItemRepository.save).toHaveBeenCalledWith([ - { - id: IdMap.getId("test-line-item"), - variant_id: IdMap.getId("test-variant"), - variant: { - id: IdMap.getId("test-variant"), - title: "Test variant", - }, - cart_id: IdMap.getId("test-cart"), - title: "Test product", - description: "Test variant", - thumbnail: "", - unit_price: 50, - quantity: 2, - has_shipping: true, - }, - ]) - }) - - it("successfully updates a line item with metadata", async () => { - await lineItemService.update(IdMap.getId("test-line-item"), { - metadata: { - testKey: "testValue", - }, - }) - - expect(lineItemRepository.save).toHaveBeenCalledTimes(1) - expect(lineItemRepository.save).toHaveBeenCalledWith([ - { - id: IdMap.getId("test-line-item"), - variant_id: IdMap.getId("test-variant"), - variant: { - id: IdMap.getId("test-variant"), - title: "Test variant", - }, - cart_id: IdMap.getId("test-cart"), - title: "Test product", - description: "Test variant", - thumbnail: "", - unit_price: 50, - quantity: 1, - metadata: { - testKey: "testValue", - }, - }, - ]) - }) - }) - describe("delete", () => { - const lineItemRepository = MockRepository({ - find: () => - Promise.resolve([ - { - id: IdMap.getId("test-line-item"), - variant_id: IdMap.getId("test-variant"), - variant: { - id: IdMap.getId("test-variant"), - title: "Test variant", - }, - cart_id: IdMap.getId("test-cart"), - title: "Test product", - description: "Test variant", - thumbnail: "", - unit_price: 50, - quantity: 1, - }, - ]), - }) - - const lineItemService = new LineItemService({ - manager: MockManager, - lineItemRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully deletes", async () => { - await lineItemService.delete(IdMap.getId("test-line-item")) - - expect(lineItemRepository.remove).toHaveBeenCalledTimes(1) - expect(lineItemRepository.remove).toHaveBeenCalledWith([ - { - id: IdMap.getId("test-line-item"), - variant_id: IdMap.getId("test-variant"), - variant: { - id: IdMap.getId("test-variant"), - title: "Test variant", - }, - cart_id: IdMap.getId("test-cart"), - title: "Test product", - description: "Test variant", - thumbnail: "", - unit_price: 50, - quantity: 1, - }, - ]) - }) - }) - }) - }) -}) - -describe("LineItemService", () => { - describe(`tax inclusive pricing tests `, () => { - describe("generate", () => { - const lineItemRepository = MockRepository({ - create: (data) => data, - }) - - const cartRepository = MockRepository({ - findOne: () => - Promise.resolve({ - region_id: IdMap.getId("test-region"), - }), - }) - - const regionService = { - withTransaction: function () { - return this - }, - retrieve: () => { - return { - id: IdMap.getId("test-region"), - } - }, - } - - const productVariantService = { - ...ProductVariantServiceMock, - retrieve: (query) => { - if (query === IdMap.getId("test-giftcard")) { - return { - id: IdMap.getId("test-giftcard"), - title: "Test variant", - product: { - title: "Test product", - thumbnail: "", - is_giftcard: true, - discountable: false, - }, - } - } - return { - id: IdMap.getId("test-variant"), - title: "Test variant", - product: { - title: "Test product", - thumbnail: "", - }, - } - }, - getRegionPrice: () => 100, - list: jest.fn().mockImplementation(async (selector) => { - return (selector.id || []).map((id) => ({ - id, - title: "Test variant", - product: { - title: "Test product", - thumbnail: "", - }, - })) - }), - } - - const pricingService = { - ...PricingServiceMock, - getProductVariantsPricing: () => { - return { - [IdMap.getId("test-variant")]: { - calculated_price: 100, - calculated_price_includes_tax: true, - }, - } - }, - getProductVariantPricing: () => { - return { - calculated_price: 100, - calculated_price_includes_tax: true, - } - }, - } - - const featureFlagRouter = new FlagRouter({ - tax_inclusive_pricing: true, - }) - - const lineItemService = new LineItemService({ - manager: MockManager, - pricingService, - lineItemRepository, - productVariantService, - regionService, - cartRepository, - featureFlagRouter, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully create a line item with tax inclusive set to true", async () => { - await lineItemService.generate( - IdMap.getId("test-variant"), - IdMap.getId("test-region"), - 1 - ) - - expect(lineItemRepository.create).toHaveBeenCalledTimes(1) - expect(lineItemRepository.create).toHaveBeenCalledWith({ - unit_price: 100, - title: "Test product", - description: "Test variant", - thumbnail: "", - variant_id: IdMap.getId("test-variant"), - quantity: 1, - order_edit_id: null, - allow_discounts: undefined, - is_giftcard: undefined, - metadata: {}, - should_merge: true, - includes_tax: true, - variant: expect.objectContaining({ - id: expect.any(String), - product: expect.objectContaining({ - thumbnail: "", - title: "Test product", - }), - title: "Test variant", - }), - }) - }) - - it("successfully create a line item with tax inclusive set to true by passing an object", async () => { - await lineItemService.generate( - { - variantId: IdMap.getId("test-variant"), - quantity: 1, - }, - { - region_id: IdMap.getId("test-region"), - } - ) - - expect(lineItemRepository.create).toHaveBeenCalledTimes(1) - expect(lineItemRepository.create).toHaveBeenCalledWith({ - unit_price: 100, - title: "Test product", - description: "Test variant", - thumbnail: "", - variant_id: IdMap.getId("test-variant"), - quantity: 1, - allow_discounts: undefined, - order_edit_id: null, - is_giftcard: undefined, - metadata: {}, - should_merge: true, - includes_tax: true, - variant: expect.objectContaining({ - id: expect.any(String), - product: expect.objectContaining({ - thumbnail: "", - title: "Test product", - }), - title: "Test variant", - }), - }) - }) - }) - - describe("generate", () => { - const lineItemRepository = MockRepository({ - create: (data) => data, - }) - - const cartRepository = MockRepository({ - findOne: ({ id }) => - Promise.resolve( - !id - ? null - : { - region_id: IdMap.getId("test-region"), - } - ), - }) - - const regionService = { - withTransaction: function () { - return this - }, - retrieve: () => { - return { - id: IdMap.getId("test-region"), - } - }, - } - - const productVariantService = { - ...ProductVariantServiceMock, - retrieve: (query) => { - if (query === IdMap.getId("test-giftcard")) { - return { - id: IdMap.getId("test-giftcard"), - title: "Test variant", - product: { - title: "Test product", - thumbnail: "", - is_giftcard: true, - discountable: false, - }, - } - } - }, - getRegionPrice: () => 100, - list: jest.fn().mockImplementation(async (selector) => { - return (selector.id || []) - .map((id) => { - if (id === unknownVariantId) { - return null - } - - return { - id, - title: "Test variant", - product: { - title: "Test product", - thumbnail: "", - }, - } - }) - .filter(Boolean) - }), - } - - const pricingService = { - ...PricingServiceMock, - getProductVariantsPricing: () => { - return { - [IdMap.getId("test-variant")]: { - calculated_price: 100, - calculated_price_includes_tax: false, - }, - } - }, - getProductVariantPricing: () => { - return { - calculated_price: 100, - calculated_price_includes_tax: false, - } - }, - } - - const featureFlagRouter = new FlagRouter({ - tax_inclusive_pricing: true, - }) - - const lineItemService = new LineItemService({ - manager: MockManager, - pricingService, - lineItemRepository, - productVariantService, - regionService, - cartRepository, - featureFlagRouter, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("should not succeed to generate a line item if a variant id is not provided", async () => { - const err = await lineItemService - .generate( - [ - { - variantId: "", - quantity: 1, - }, - ], - { - region_id: IdMap.getId("test-region"), - } - ) - .catch((e) => e) - - expect(err).toBeDefined() - expect(err.message).toEqual( - "Unable to generate the line item because one or more required argument(s) are missing. Ensure a variant id is passed for each variant" - ) - }) - - it("should not succeed to generate a line item if a variant id is not found", async () => { - const err = await lineItemService - .generate( - [ - { - variantId: unknownVariantId, - quantity: 1, - }, - ], - { - region_id: IdMap.getId("test-region"), - } - ) - .catch((e) => e) - - expect(err).toBeDefined() - expect(err.message).toEqual( - "Unable to generate the line items, some variant has not been found: unknown-variant" - ) - }) - - it("successfully create a line item with tax inclusive set to false", async () => { - await lineItemService.generate( - IdMap.getId("test-variant"), - IdMap.getId("test-region"), - 1 - ) - - expect(lineItemRepository.create).toHaveBeenCalledTimes(1) - expect(lineItemRepository.create).toHaveBeenCalledWith({ - unit_price: 100, - title: "Test product", - description: "Test variant", - thumbnail: "", - variant_id: IdMap.getId("test-variant"), - quantity: 1, - allow_discounts: undefined, - order_edit_id: null, - is_giftcard: undefined, - metadata: {}, - should_merge: true, - includes_tax: false, - variant: expect.objectContaining({ - id: expect.any(String), - product: expect.objectContaining({ - thumbnail: "", - title: "Test product", - }), - title: "Test variant", - }), - }) - }) - - it("successfully create a line item with tax inclusive set to false by passing an object", async () => { - await lineItemService.generate( - { - variantId: IdMap.getId("test-variant"), - quantity: 1, - }, - { - region_id: IdMap.getId("test-region"), - } - ) - - expect(lineItemRepository.create).toHaveBeenCalledTimes(1) - expect(lineItemRepository.create).toHaveBeenCalledWith({ - unit_price: 100, - title: "Test product", - description: "Test variant", - thumbnail: "", - variant_id: IdMap.getId("test-variant"), - quantity: 1, - allow_discounts: undefined, - is_giftcard: undefined, - order_edit_id: null, - metadata: {}, - should_merge: true, - includes_tax: false, - variant: expect.objectContaining({ - id: expect.any(String), - product: expect.objectContaining({ - thumbnail: "", - title: "Test product", - }), - title: "Test variant", - }), - }) - }) - }) - - describe("clone", () => { - const buildLineItem = (id) => ({ - id, - original_item_id: id, - swap_id: "test", - order_id: "test", - tax_lines: [ - { - rate: 10, - item_id: id, - }, - ], - adjustments: [ - { - amount: 10, - item_id: id, - }, - ], - }) - const buildExpectedLineItem = (id) => - expect.objectContaining({ - original_item_id: id, - swap_id: undefined, - claim_order_id: undefined, - cart_id: undefined, - order_edit_id: undefined, - order_id: "test", - tax_lines: expect.arrayContaining([ - expect.objectContaining({ - rate: 10, - }), - ]), - adjustments: expect.arrayContaining([ - expect.objectContaining({ - amount: 10, - }), - ]), - }) - - const lineItemRepository = MockRepository({ - create: (data) => data, - save: (data) => data, - find: (selector) => { - return selector.where.id.value.map(buildLineItem) - }, - }) - - const featureFlagRouter = new FlagRouter({}) - - const lineItemService = new LineItemService({ - manager: MockManager, - pricingService: PricingServiceMock, - lineItemRepository, - productVariantService: ProductVariantServiceMock, - regionService: RegionServiceMock, - cartRepository: MockRepository, - featureFlagRouter, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully clone line items with tax lines and adjustments", async () => { - const lineItemId1 = IdMap.getId("line-item-1") - const lineItemId2 = IdMap.getId("line-item-2") - - await lineItemService.cloneTo([lineItemId1, lineItemId2], { - order_id: "test", - }) - - expect(lineItemRepository.save).toHaveBeenCalledTimes(1) - expect(lineItemRepository.create).toHaveBeenCalledTimes(1) - expect(lineItemRepository.create).toHaveBeenCalledWith( - expect.arrayContaining([ - buildExpectedLineItem(lineItemId1), - buildExpectedLineItem(lineItemId2), - ]) - ) - expect(lineItemRepository.save).toHaveBeenCalledWith( - expect.arrayContaining([ - buildExpectedLineItem(lineItemId1), - buildExpectedLineItem(lineItemId2), - ]) - ) - }) - - it("throw on clone line items if none of the foreign keys is specified", async () => { - const lineItemId1 = IdMap.getId("line-item-1") - const lineItemId2 = IdMap.getId("line-item-2") - - const err = await lineItemService - .cloneTo([lineItemId1, lineItemId2]) - .catch((e) => e) - - expect(err.message).toBe( - "Unable to clone a line item that is not attached to at least one of: order_edit, order, swap, claim or cart." - ) - }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/new-totals.ts b/packages/medusa/src/services/__tests__/new-totals.ts deleted file mode 100644 index a30dc47cde..0000000000 --- a/packages/medusa/src/services/__tests__/new-totals.ts +++ /dev/null @@ -1,1138 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { asClass, asValue, createContainer } from "awilix" -import { TaxCalculationContext } from "../../interfaces" -import TaxInclusivePricingFeatureFlag from "../../loaders/feature-flags/tax-inclusive-pricing" -import { - Discount, - DiscountRuleType, - LineItem, - ProductVariant, - Region, - ShippingMethod, -} from "../../models" -import { - defaultContainerMock, - giftCards, - giftCardsWithTaxRate, - lineItems, - shippingMethods, -} from "../__fixtures__/new-totals" -import { taxProviderServiceMock } from "../__mocks__/tax-provider" -import { NewTotalsService } from "../index" - -describe("New totals service", () => { - describe("Without [MEDUSA_FF_TAX_INCLUSIVE_PRICING]", () => { - describe("getLineItemTotals", () => { - let container - let newTotalsService: NewTotalsService - - beforeEach(() => { - container = createContainer({}, defaultContainerMock) - container.register( - "taxProviderService", - asValue({ - ...taxProviderServiceMock, - getTaxLinesMap: jest - .fn() - .mockImplementation(async (items: LineItem[]) => { - const result = { - lineItemsTaxLines: {}, - } - - for (const item of items) { - result.lineItemsTaxLines[item.id] = [ - { - item_id: item.id, - name: "default", - code: "default", - rate: 30, - }, - ] - } - - return result - }), - }) - ) - container.register("newTotalsService", asClass(NewTotalsService)) - newTotalsService = container.resolve("newTotalsService") - }) - - afterEach(() => { - jest.clearAllMocks() - }) - - it("should use the items tax lines to compute the totals", async () => { - const testItem = lineItems[0] - - const calculationContext = { - allocation_map: { - [testItem.id]: {}, - }, - shipping_methods: [], - } as unknown as TaxCalculationContext - - const itemsTotalsMap = await newTotalsService.getLineItemTotals( - [testItem], - { - includeTax: true, - calculationContext, - } - ) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // unit_price: 1000, taxes 20% - expect(itemsTotalsMap[testItem.id]).toEqual( - expect.objectContaining({ - unit_price: 1000, - subtotal: 1000, - total: 1200, - original_total: 1200, - discount_total: 0, - original_tax_total: 200, - tax_total: 200, - tax_lines: expect.arrayContaining(testItem.tax_lines), - }) - ) - }) - - it("should fetch the items tax lines to compute the totals", async () => { - const testItem = { ...lineItems[0] } as LineItem - testItem.variant = new ProductVariant() - testItem.tax_lines = [] - - const calculationContext = { - allocation_map: { - [testItem.id]: {}, - }, - shipping_methods: [], - } as unknown as TaxCalculationContext - - const itemsTotalsMap = await newTotalsService.getLineItemTotals( - [testItem], - { - includeTax: true, - calculationContext, - } - ) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).toHaveBeenCalledTimes(1) - expect(taxProviderService.getTaxLinesMap).toHaveBeenCalledWith( - [testItem], - calculationContext - ) - - // unit_price: 1000, taxes 30% - expect(itemsTotalsMap[testItem.id]).toEqual( - expect.objectContaining({ - unit_price: 1000, - subtotal: 1000, - total: 1300, - original_total: 1300, - discount_total: 0, - original_tax_total: 300, - tax_total: 300, - tax_lines: expect.arrayContaining([ - expect.objectContaining({ - name: "default", - code: "default", - rate: 30, - }), - ]), - }) - ) - }) - - it("should not use tax lines when includeTax is not true to compute the totals", async () => { - const testItem = { ...lineItems[0] } as LineItem - testItem.tax_lines = [] - - const calculationContext = { - allocation_map: { - [testItem.id]: {}, - }, - shipping_methods: [], - } as unknown as TaxCalculationContext - - const itemsTotalsMap = await newTotalsService.getLineItemTotals( - [testItem], - { - includeTax: false, - calculationContext, - } - ) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // unit_price: 1000 - expect(itemsTotalsMap[testItem.id]).toEqual( - expect.objectContaining({ - unit_price: 1000, - subtotal: 1000, - total: 1000, - original_total: 1000, - discount_total: 0, - original_tax_total: 0, - tax_total: 0, - tax_lines: expect.arrayContaining([]), - }) - ) - }) - - it("should use the provided tax rate to compute the totals", async () => { - const testItem = lineItems[0] - - const calculationContext = { - allocation_map: { - [testItem.id]: {}, - }, - shipping_methods: [], - } as unknown as TaxCalculationContext - - const itemsTotalsMap = await newTotalsService.getLineItemTotals( - [testItem], - { - taxRate: 20, - calculationContext, - } - ) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // unit_price: 1000, taxes 20% - expect(itemsTotalsMap[testItem.id]).toEqual( - expect.objectContaining({ - unit_price: 1000, - subtotal: 1000, - total: 1200, - original_total: 1200, - discount_total: 0, - original_tax_total: 200, - tax_total: 200, - tax_lines: expect.arrayContaining([]), - }) - ) - }) - }) - - describe("getShippingMethodTotals", () => { - let container - let newTotalsService: NewTotalsService - - beforeEach(() => { - container = createContainer({}, defaultContainerMock) - container.register( - "taxProviderService", - asValue({ - ...taxProviderServiceMock, - getTaxLinesMap: jest - .fn() - .mockImplementation( - async ( - items: LineItem[], - calculationContext: TaxCalculationContext - ) => { - const result = { - shippingMethodsTaxLines: {}, - } - - for (const method of calculationContext.shipping_methods) { - result.shippingMethodsTaxLines[method.id] = [ - { - shipping_method_id: method.id, - name: "default", - code: "default", - rate: 30, - }, - ] - } - - return result - } - ), - }) - ) - container.register("newTotalsService", asClass(NewTotalsService)) - newTotalsService = container.resolve("newTotalsService") - }) - - afterEach(() => { - jest.clearAllMocks() - }) - - it("should use the shipping method tax lines to compute the totals", async () => { - const testShippingMethod = shippingMethods[0] - - const calculationContext = { - allocation_map: {}, - shipping_methods: [testShippingMethod], - } as unknown as TaxCalculationContext - - const shippingMethodTotalsMap = - await newTotalsService.getShippingMethodTotals([testShippingMethod], { - includeTax: true, - calculationContext, - }) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // price: 1000, taxes: 20% - expect(shippingMethodTotalsMap[testShippingMethod.id]).toEqual( - expect.objectContaining({ - price: 1000, - subtotal: 1000, - total: 1200, - original_total: 1200, - original_tax_total: 200, - tax_total: 200, - tax_lines: expect.arrayContaining(testShippingMethod.tax_lines), - }) - ) - }) - - it("should fetch the shipping method tax lines to compute the totals", async () => { - const testShippingMethod = { ...shippingMethods[0] } as ShippingMethod - testShippingMethod.tax_lines = [] - - const calculationContext = { - allocation_map: {}, - shipping_methods: [testShippingMethod], - } as unknown as TaxCalculationContext - - const shippingMethodTotalsMap = - await newTotalsService.getShippingMethodTotals([testShippingMethod], { - includeTax: true, - calculationContext, - }) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).toHaveBeenCalledTimes(1) - expect(taxProviderService.getTaxLinesMap).toHaveBeenCalledWith( - [], - calculationContext - ) - - // price: 1000, taxes 30% - expect(shippingMethodTotalsMap[testShippingMethod.id]).toEqual( - expect.objectContaining({ - price: 1000, - subtotal: 1000, - total: 1300, - original_total: 1300, - original_tax_total: 300, - tax_total: 300, - tax_lines: expect.arrayContaining([ - expect.objectContaining({ - name: "default", - code: "default", - rate: 30, - }), - ]), - }) - ) - }) - - it("should not use tax lines when includeTax is not true to compute the totals", async () => { - const testShippingMethod = { ...shippingMethods[0] } as ShippingMethod - testShippingMethod.tax_lines = [] - - const calculationContext = { - allocation_map: {}, - shipping_methods: [testShippingMethod], - } as unknown as TaxCalculationContext - - const shippingMethodTotalsMap = - await newTotalsService.getShippingMethodTotals([testShippingMethod], { - includeTax: false, - calculationContext, - }) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // price: 1000 - expect(shippingMethodTotalsMap[testShippingMethod.id]).toEqual( - expect.objectContaining({ - price: 1000, - subtotal: 1000, - total: 1000, - original_total: 1000, - original_tax_total: 0, - tax_total: 0, - tax_lines: expect.arrayContaining([]), - }) - ) - }) - - it("should use the provided tax rate to compute the totals", async () => { - const testShippingMethod = shippingMethods[0] - - const calculationContext = { - allocation_map: {}, - shipping_methods: [testShippingMethod], - } as unknown as TaxCalculationContext - - const shippingMethodTotalsMap = - await newTotalsService.getShippingMethodTotals([testShippingMethod], { - taxRate: 20, - calculationContext, - }) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // unit_price: 1000, taxes 20% - expect(shippingMethodTotalsMap[testShippingMethod.id]).toEqual( - expect.objectContaining({ - price: 1000, - subtotal: 1000, - total: 1000, // Legacy does not include the taxes - original_total: 1000, // Legacy does not include the taxes - original_tax_total: 200, - tax_total: 200, - tax_lines: expect.arrayContaining([]), - }) - ) - }) - - it("should compute a total to 0 if a free shipping discount is present", async () => { - const testShippingMethod = shippingMethods[0] - - const discounts = [ - { - rule: { - type: DiscountRuleType.FREE_SHIPPING, - }, - }, - ] as Discount[] - - const calculationContext = { - allocation_map: {}, - shipping_methods: [testShippingMethod], - } as unknown as TaxCalculationContext - - const shippingMethodTotalsMap = - await newTotalsService.getShippingMethodTotals([testShippingMethod], { - includeTax: true, - calculationContext, - discounts, - }) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // unit_price: 1000, taxes 20% - expect(shippingMethodTotalsMap[testShippingMethod.id]).toEqual( - expect.objectContaining({ - price: 1000, - subtotal: 0, - total: 0, - original_total: 1200, - original_tax_total: 200, - tax_total: 0, - tax_lines: expect.arrayContaining(testShippingMethod.tax_lines), - }) - ) - }) - }) - - describe("getLineItemRefund", () => { - let container - let newTotalsService: NewTotalsService - - beforeEach(() => { - container = createContainer({}, defaultContainerMock) - container.register("newTotalsService", asClass(NewTotalsService)) - newTotalsService = container.resolve("newTotalsService") - }) - - afterEach(() => { - jest.clearAllMocks() - }) - - it("should compute the line item refundable amount", () => { - const testItem = lineItems[0] - - const calculationContext = { - allocation_map: {}, - shipping_methods: [], - } as unknown as TaxCalculationContext - - const refundAmount = newTotalsService.getLineItemRefund(testItem, { - calculationContext, - }) - - // unit_price: 1000, taxes: 20% - expect(refundAmount).toEqual(1200) - }) - - it("should compute the line item refundable amount using the taxRate", () => { - const testItem = lineItems[0] - - const calculationContext = { - allocation_map: {}, - shipping_methods: [], - } as unknown as TaxCalculationContext - - const refundAmount = newTotalsService.getLineItemRefund(testItem, { - taxRate: 30, - calculationContext, - }) - - // unit_price: 1000, taxes: 30% - expect(refundAmount).toEqual(1300) - }) - }) - - describe("getGiftCardTotals", () => { - let container - let newTotalsService: NewTotalsService - - beforeEach(() => { - container = createContainer({}, defaultContainerMock) - container.register("newTotalsService", asClass(NewTotalsService)) - newTotalsService = container.resolve("newTotalsService") - }) - - afterEach(() => { - jest.clearAllMocks() - }) - - it("should compute the gift cards totals amount in non taxable region", async () => { - const maxAmount = 1000 - - const testGiftCard = giftCards[0] - - const region = { - gift_cards_taxable: false, - } as Region - - const gitCardTotals = await newTotalsService.getGiftCardTotals( - maxAmount, - { - giftCards: [testGiftCard], - region, - } - ) - - expect(gitCardTotals).toEqual( - expect.objectContaining({ - total: 1000, - tax_total: 0, - }) - ) - }) - - it("should compute the gift cards totals amount using the gift card tax rate", async () => { - const maxAmount = 1000 - - const testGiftCard = giftCardsWithTaxRate[0] - - const region = { - // These values aren't involved in calculating tax rates for a gift card - // GiftCard.tax_rate will be the source of truth for tax calculations - // This is needed for giftCardTransactions backwards compatability reasons - gift_cards_taxable: true, - tax_rate: 0, - } as Region - - const gitCardTotals = await newTotalsService.getGiftCardTotals( - maxAmount, - { - giftCards: [testGiftCard], - region, - } - ) - - expect(gitCardTotals).toEqual( - expect.objectContaining({ - total: 1000, - tax_total: 200, - }) - ) - }) - - it("should compute the gift cards totals amount in non taxable region using gift card transactions", async () => { - const maxAmount = 1000 - const testGiftCard = giftCards[0] - const giftCardTransactions = [ - { - tax_rate: 20, - is_taxable: false, - amount: 1000, - gift_card: testGiftCard - }, - ] - - const region = { - gift_cards_taxable: false, - } as Region - - const gitCardTotals = await newTotalsService.getGiftCardTotals( - maxAmount, - { - giftCardTransactions, - region, - } - ) - - expect(gitCardTotals).toEqual( - expect.objectContaining({ - total: 1000, - tax_total: 200, - }) - ) - }) - - it("should compute the gift cards totals amount in a taxable region using gift card transactions", async () => { - const maxAmount = 1000 - const testGiftCard = giftCards[0] - const giftCardTransactions = [ - { - tax_rate: 20, - is_taxable: null, - amount: 1000, - gift_card: testGiftCard - }, - ] - - const region = { - gift_cards_taxable: true, - tax_rate: 30, - } as Region - - const gitCardTotals = await newTotalsService.getGiftCardTotals( - maxAmount, - { - giftCardTransactions: giftCardTransactions, - region, - } - ) - - expect(gitCardTotals).toEqual( - expect.objectContaining({ - total: 1000, - tax_total: 300, - }) - ) - }) - - it("should compute the gift cards totals amount using gift card transactions for gift card with tax_rate", async () => { - const maxAmount = 1000 - const testGiftCard = giftCardsWithTaxRate[0] - const giftCardTransactions = [ - { - tax_rate: 20, - is_taxable: null, - amount: 1000, - gift_card: testGiftCard - }, - ] - - const region = { - // These values aren't involved in calculating tax rates for a gift card - // GiftCard.tax_rate will be the source of truth for tax calculations - // This is needed for giftCardTransactions backwards compatability reasons - gift_cards_taxable: false, - tax_rate: 99, - } as Region - - const gitCardTotals = await newTotalsService.getGiftCardTotals( - maxAmount, - { - giftCardTransactions: giftCardTransactions, - region, - } - ) - - expect(gitCardTotals).toEqual( - expect.objectContaining({ - total: 1000, - tax_total: 200, - }) - ) - }) - }) - }) - - describe("With [MEDUSA_FF_TAX_INCLUSIVE_PRICING]", () => { - describe("getLineItemTotals", () => { - let container - let newTotalsService: NewTotalsService - - beforeEach(() => { - container = createContainer({}, defaultContainerMock) - container.register( - "featureFlagRouter", - asValue( - new FlagRouter({ - [TaxInclusivePricingFeatureFlag.key]: true, - }) - ) - ) - container.register( - "taxProviderService", - asValue({ - ...taxProviderServiceMock, - getTaxLinesMap: jest - .fn() - .mockImplementation(async (items: LineItem[]) => { - const result = { - lineItemsTaxLines: {}, - } - - for (const item of items) { - result.lineItemsTaxLines[item.id] = [ - { - item_id: item.id, - name: "default", - code: "default", - rate: 30, - }, - ] - } - - return result - }), - }) - ) - container.register("newTotalsService", asClass(NewTotalsService)) - newTotalsService = container.resolve("newTotalsService") - }) - - afterEach(() => { - jest.clearAllMocks() - }) - - it("should use the items tax lines to compute the totals", async () => { - const testItem = { ...lineItems[0] } as LineItem - testItem.includes_tax = true - - const calculationContext = { - allocation_map: { - [testItem.id]: {}, - }, - shipping_methods: [], - } as unknown as TaxCalculationContext - - const itemsTotalsMap = await newTotalsService.getLineItemTotals( - [testItem], - { - includeTax: true, - calculationContext, - } - ) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // unit_price: 1000 including taxes, taxes 20% - expect(itemsTotalsMap[testItem.id]).toEqual( - expect.objectContaining({ - unit_price: 1000, - subtotal: 833, - total: 1000, - original_total: 1000, - discount_total: 0, - original_tax_total: 167, - tax_total: 167, - tax_lines: expect.arrayContaining(testItem.tax_lines), - }) - ) - }) - - it("should fetch the tax lines to compute the totals", async () => { - const testItem = { ...lineItems[0] } as LineItem - testItem.tax_lines = [] - testItem.variant = new ProductVariant() - testItem.includes_tax = true - - const calculationContext = { - allocation_map: { - [testItem.id]: {}, - }, - shipping_methods: [], - } as unknown as TaxCalculationContext - - const itemsTotalsMap = await newTotalsService.getLineItemTotals( - [testItem], - { - includeTax: true, - calculationContext, - } - ) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).toHaveBeenCalledTimes(1) - expect(taxProviderService.getTaxLinesMap).toHaveBeenCalledWith( - [testItem], - calculationContext - ) - - // unit_price: 1000 including taxes, taxes 30% - expect(itemsTotalsMap[testItem.id]).toEqual( - expect.objectContaining({ - unit_price: 1000, - subtotal: 769, - total: 1000, - original_total: 1000, - discount_total: 0, - original_tax_total: 231, - tax_total: 231, - tax_lines: expect.arrayContaining([ - expect.objectContaining({ - name: "default", - code: "default", - rate: 30, - }), - ]), - }) - ) - }) - - it("should not use tax lines when includeTax is not true to compute the totals", async () => { - const testItem = { ...lineItems[0] } as LineItem - testItem.includes_tax = true - - const calculationContext = { - allocation_map: { - [testItem.id]: {}, - }, - shipping_methods: [], - } as unknown as TaxCalculationContext - - const itemsTotalsMap = await newTotalsService.getLineItemTotals( - [testItem], - { - includeTax: false, - calculationContext, - } - ) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // unit_price: 1000 including taxes - expect(itemsTotalsMap[testItem.id]).toEqual( - expect.objectContaining({ - unit_price: 1000, - subtotal: 833, - total: 1000, - original_total: 1000, - discount_total: 0, - original_tax_total: 167, - tax_total: 167, - tax_lines: expect.arrayContaining([]), - }) - ) - }) - - it("should use the provided tax rate to compute the totals", async () => { - const testItem = lineItems[0] - testItem.includes_tax = true - - const calculationContext = { - allocation_map: { - [testItem.id]: {}, - }, - shipping_methods: [], - } as unknown as TaxCalculationContext - - const itemsTotalsMap = await newTotalsService.getLineItemTotals( - [testItem], - { - taxRate: 20, - calculationContext, - } - ) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // unit_price: 1000 including taxes, taxes 20% - expect(itemsTotalsMap[testItem.id]).toEqual( - expect.objectContaining({ - unit_price: 1000, - subtotal: 833, - total: 1000, - original_total: 1000, - discount_total: 0, - original_tax_total: 167, - tax_total: 167, - tax_lines: expect.arrayContaining([]), - }) - ) - }) - }) - - describe("getShippingMethodTotals", () => { - let container - let newTotalsService: NewTotalsService - - beforeEach(() => { - container = createContainer({}, defaultContainerMock) - container.register( - "featureFlagRouter", - asValue( - new FlagRouter({ - [TaxInclusivePricingFeatureFlag.key]: true, - }) - ) - ) - container.register( - "taxProviderService", - asValue({ - ...taxProviderServiceMock, - getTaxLinesMap: jest - .fn() - .mockImplementation( - async ( - items: LineItem[], - calculationContext: TaxCalculationContext - ) => { - const result = { - shippingMethodsTaxLines: {}, - } - - for (const method of calculationContext.shipping_methods) { - result.shippingMethodsTaxLines[method.id] = [ - { - shipping_method_id: method.id, - name: "default", - code: "default", - rate: 30, - }, - ] - } - - return result - } - ), - }) - ) - container.register("newTotalsService", asClass(NewTotalsService)) - newTotalsService = container.resolve("newTotalsService") - }) - - afterEach(() => { - jest.clearAllMocks() - }) - - it("should use the shipping method tax lines to compute the totals", async () => { - const testShippingMethod = shippingMethods[0] - testShippingMethod.includes_tax = true - - const calculationContext = { - allocation_map: {}, - shipping_methods: [testShippingMethod], - } as unknown as TaxCalculationContext - - const shippingMethodTotalsMap = - await newTotalsService.getShippingMethodTotals([testShippingMethod], { - includeTax: true, - calculationContext, - }) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // price: 1000 including taxes, taxes: 20% - expect(shippingMethodTotalsMap[testShippingMethod.id]).toEqual( - expect.objectContaining({ - price: 1000, - subtotal: 833, - total: 1000, - original_total: 1000, - original_tax_total: 167, - tax_total: 167, - tax_lines: expect.arrayContaining(testShippingMethod.tax_lines), - }) - ) - }) - - it("should fetch shipping method tax lines to compute the totals", async () => { - const testShippingMethod = { ...shippingMethods[0] } as ShippingMethod - testShippingMethod.tax_lines = [] - testShippingMethod.includes_tax = true - - const calculationContext = { - allocation_map: {}, - shipping_methods: [testShippingMethod], - } as unknown as TaxCalculationContext - - const shippingMethodTotalsMap = - await newTotalsService.getShippingMethodTotals([testShippingMethod], { - includeTax: true, - calculationContext, - }) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).toHaveBeenCalledTimes(1) - expect(taxProviderService.getTaxLinesMap).toHaveBeenCalledWith( - [], - calculationContext - ) - - // price: 1000 including taxes, taxes 30% - expect(shippingMethodTotalsMap[testShippingMethod.id]).toEqual( - expect.objectContaining({ - price: 1000, - subtotal: 769, - total: 1000, - original_total: 1000, - original_tax_total: 231, - tax_total: 231, - tax_lines: expect.arrayContaining([ - expect.objectContaining({ - name: "default", - code: "default", - rate: 30, - }), - ]), - }) - ) - }) - - it("should not use tax lines when includeTax is not true to compute the totals", async () => { - const testShippingMethod = { ...shippingMethods[0] } as ShippingMethod - testShippingMethod.tax_lines = [] - testShippingMethod.includes_tax = true - - const calculationContext = { - allocation_map: {}, - shipping_methods: [testShippingMethod], - } as unknown as TaxCalculationContext - - const shippingMethodTotalsMap = - await newTotalsService.getShippingMethodTotals([testShippingMethod], { - includeTax: false, - calculationContext, - }) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // price: 1000 including taxes - expect(shippingMethodTotalsMap[testShippingMethod.id]).toEqual( - expect.objectContaining({ - price: 1000, - subtotal: 1000, - total: 1000, - original_total: 1000, - original_tax_total: 0, - tax_total: 0, - tax_lines: expect.arrayContaining([]), - }) - ) - }) - - // Not applicable to legacy shipping method totals calculation - /*it("should use the provided tax rate to compute the totals", async () => {})*/ - - it("should compute a total to 0 if a free shipping discount is present", async () => { - const testShippingMethod = shippingMethods[0] - testShippingMethod.includes_tax = true - - const discounts = [ - { - rule: { - type: DiscountRuleType.FREE_SHIPPING, - }, - }, - ] as Discount[] - - const calculationContext = { - allocation_map: {}, - shipping_methods: [testShippingMethod], - } as unknown as TaxCalculationContext - - const shippingMethodTotalsMap = - await newTotalsService.getShippingMethodTotals([testShippingMethod], { - includeTax: true, - calculationContext, - discounts, - }) - - const taxProviderService = container.resolve("taxProviderService") - expect(taxProviderService.getTaxLinesMap).not.toHaveBeenCalled() - - // unit_price: 1000 including taxes, taxes 20% - expect(shippingMethodTotalsMap[testShippingMethod.id]).toEqual( - expect.objectContaining({ - price: 1000, - subtotal: 0, - total: 0, - original_total: 1000, - original_tax_total: 167, - tax_total: 0, - tax_lines: expect.arrayContaining(testShippingMethod.tax_lines), - }) - ) - }) - }) - - describe("getLineItemRefund", () => { - let container - let newTotalsService: NewTotalsService - - beforeEach(() => { - container = createContainer({}, defaultContainerMock) - container.register( - "featureFlagRouter", - asValue( - new FlagRouter({ - [TaxInclusivePricingFeatureFlag.key]: true, - }) - ) - ) - container.register("newTotalsService", asClass(NewTotalsService)) - newTotalsService = container.resolve("newTotalsService") - }) - - afterEach(() => { - jest.clearAllMocks() - }) - - it("should compute the line item refundable amount", () => { - const testItem = lineItems[0] - testItem.includes_tax = true - - const calculationContext = { - allocation_map: {}, - shipping_methods: [], - } as unknown as TaxCalculationContext - - const refundAmount = newTotalsService.getLineItemRefund(testItem, { - calculationContext, - }) - - // unit_price: 1000 including taxes, taxes: 20% - expect(refundAmount).toEqual(1000) - }) - - it("should compute the line item refundable amount using the taxRate", () => { - const testItem = lineItems[0] - testItem.includes_tax = true - - const calculationContext = { - allocation_map: {}, - shipping_methods: [], - } as unknown as TaxCalculationContext - - const refundAmount = newTotalsService.getLineItemRefund(testItem, { - taxRate: 30, - calculationContext, - }) - - // unit_price: 1000 including taxes, taxes: 30% - expect(refundAmount).toEqual(1000) - }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/note.js b/packages/medusa/src/services/__tests__/note.js deleted file mode 100644 index 887972eb4c..0000000000 --- a/packages/medusa/src/services/__tests__/note.js +++ /dev/null @@ -1,209 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" - -import { EventBusServiceMock } from "../__mocks__/event-bus" -import NoteService from "../note" - -describe("NoteService", () => { - describe("list", () => { - const noteRepo = MockRepository({ - find: (q) => { - return Promise.resolve([ - { id: IdMap.getId("note"), value: "some note" }, - ]) - }, - findAndCount: (q) => { - return Promise.resolve([ - [{ id: IdMap.getId("note"), value: "some note" }], - 1, - ]) - }, - }) - - const noteService = new NoteService({ - manager: MockManager, - noteRepository: noteRepo, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls note model functions", async () => { - await noteService.list( - { resource_id: IdMap.getId("note") }, - { - relations: ["author"], - } - ) - expect(noteRepo.findAndCount).toHaveBeenCalledTimes(1) - expect(noteRepo.findAndCount).toHaveBeenCalledWith({ - where: { - resource_id: IdMap.getId("note"), - }, - relations: { author: true }, - }) - }) - }) - - describe("retrieve", () => { - const noteRepo = MockRepository({ - findOne: (q) => { - switch (q.where.id) { - case IdMap.getId("note"): - return Promise.resolve({ - id: IdMap.getId("note"), - value: "some note", - }) - default: - return Promise.resolve() - } - }, - }) - - const noteService = new NoteService({ - manager: MockManager, - noteRepository: noteRepo, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls note model functions", async () => { - await noteService.retrieve(IdMap.getId("note"), { relations: ["author"] }) - - expect(noteRepo.findOne).toHaveBeenCalledTimes(1) - expect(noteRepo.findOne).toHaveBeenCalledWith({ - where: { id: IdMap.getId("note") }, - relations: { author: true }, - }) - }) - - it("fails when note is not found", async () => { - await expect( - noteService.retrieve(IdMap.getId("not-existing")) - ).rejects.toThrow( - `Note with id: ${IdMap.getId("not-existing")} was not found.` - ) - }) - }) - - describe("create", () => { - const note = { - id: IdMap.getId("note"), - author_id: IdMap.getId("user"), - } - - const noteRepo = MockRepository({ - create: (f) => note, - save: (f) => Promise.resolve(note), - }) - - const noteService = new NoteService({ - manager: MockManager, - noteRepository: noteRepo, - eventBusService: EventBusServiceMock, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls note model functions", async () => { - await noteService.create({ - resource_id: IdMap.getId("resource-id"), - resource_type: "type", - value: "my note", - author_id: IdMap.getId("user"), - }) - - expect(noteRepo.create).toHaveBeenCalledTimes(1) - expect(noteRepo.create).toHaveBeenCalledWith({ - resource_id: IdMap.getId("resource-id"), - resource_type: "type", - value: "my note", - author_id: IdMap.getId("user"), - metadata: {}, - }) - - expect(noteRepo.save).toHaveBeenCalledTimes(1) - expect(noteRepo.save).toHaveBeenCalledWith({ - id: IdMap.getId("note"), - author_id: IdMap.getId("user"), - }) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - NoteService.Events.CREATED, - { id: IdMap.getId("note") } - ) - }) - }) - - describe("update", () => { - const note = { id: IdMap.getId("note") } - - const noteRepo = MockRepository({ - findOne: (f) => Promise.resolve(note), - save: (f) => Promise.resolve(note), - }) - - const noteService = new NoteService({ - manager: MockManager, - noteRepository: noteRepo, - eventBusService: EventBusServiceMock, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls note model functions", async () => { - await noteService.update(IdMap.getId("note"), "new note") - - expect(noteRepo.save).toHaveBeenCalledTimes(1) - expect(noteRepo.save).toHaveBeenCalledWith({ - ...note, - value: "new note", - }) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - NoteService.Events.UPDATED, - { id: IdMap.getId("note") } - ) - }) - }) - - describe("delete", () => { - const note = { id: IdMap.getId("note") } - - const noteRepo = MockRepository({ - softRemove: (f) => Promise.resolve(), - findOne: (f) => Promise.resolve(note), - }) - - const noteService = new NoteService({ - manager: MockManager, - noteRepository: noteRepo, - eventBusService: EventBusServiceMock, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls note model functions", async () => { - await noteService.delete(IdMap.getId("note")) - - expect(noteRepo.softRemove).toHaveBeenCalledTimes(1) - expect(noteRepo.softRemove).toHaveBeenCalledWith(note) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - NoteService.Events.DELETED, - { id: IdMap.getId("note") } - ) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/notification.js b/packages/medusa/src/services/__tests__/notification.js deleted file mode 100644 index 64b6361b65..0000000000 --- a/packages/medusa/src/services/__tests__/notification.js +++ /dev/null @@ -1,81 +0,0 @@ -import NotificationService from "../notification" -import { MockManager, MockRepository } from "medusa-test-utils" - -describe("NotificationService", () => { - const notificationRepository = MockRepository({ create: c => c }) - - const container = { - manager: MockManager, - notificationRepository, - noti_test: { - sendNotification: jest.fn(() => - Promise.resolve({ - to: "test@mail.com", - data: { id: "something" }, - }) - ), - }, - } - - beforeEach(() => { - jest.clearAllMocks() - }) - - describe("send", () =>{ - - it("successfully calls provider and saves noti", async () => { - const notificationService = new NotificationService(container) - - await notificationService.send("event.test", { id: "test" }, "test") - - expect(container.noti_test.sendNotification).toHaveBeenCalledTimes(1) - expect(container.noti_test.sendNotification).toHaveBeenCalledWith( - "event.test", - { id: "test" }, - null - ) - - const constructed = { - resource_type: "event", - resource_id: "test", - customer_id: null, - to: "test@mail.com", - data: { id: "something" }, - event_name: "event.test", - provider_id: "test", - } - - expect(notificationRepository.create).toHaveBeenCalledTimes(1) - expect(notificationRepository.create).toHaveBeenCalledWith(constructed) - - expect(notificationRepository.save).toHaveBeenCalledTimes(1) - expect(notificationRepository.save).toHaveBeenCalledWith(constructed) - }) - }) - - describe("handleEvent", () => { - - it("cancels notification if no_notification is set", async () => { - const notificationService = new NotificationService(container) - const event = "event.test" - notificationService.subscribe(event, "test") - - await notificationService.handleEvent(event, {id: "id", - return_id: "id", - no_notification: true}) - - expect(container.noti_test.sendNotification).not.toHaveBeenCalled() - }) - - it("if no_notification is not set notification is send", async () => { - const notificationService = new NotificationService(container) - const event = "event.test" - notificationService.subscribe(event, "test") - - await notificationService.handleEvent(event, {id: "id", return_id: "id"}) - - expect(container.noti_test.sendNotification).toHaveBeenCalledTimes(1) - }) - - }) -}) diff --git a/packages/medusa/src/services/__tests__/order-edit-item-change.ts b/packages/medusa/src/services/__tests__/order-edit-item-change.ts deleted file mode 100644 index bcffc5d092..0000000000 --- a/packages/medusa/src/services/__tests__/order-edit-item-change.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { In } from "typeorm" -import EventBusService from "../event-bus" -import { - LineItemService, - OrderEditItemChangeService, - TaxProviderService -} from "../index" -import { EventBusServiceMock } from "../__mocks__/event-bus" -import { LineItemServiceMock } from "../__mocks__/line-item" - -const taxProviderServiceMock = { - withTransaction: function () { - return this - }, - clearLineItemsTaxLines: jest.fn().mockImplementation(() => Promise.resolve()), -} - -describe("OrderEditItemChangeService", () => { - afterEach(() => { - jest.clearAllMocks() - }) - - const orderItemChangeRepository = MockRepository({ - delete: jest.fn().mockImplementation(() => { - return Promise.resolve() - }), - find: jest.fn().mockImplementation((conditions) => { - return Promise.resolve( - conditions.where?.id?.value?.map((id) => ({ - id, - line_item_id: "li_" + id, - })) - ) - }), - }) - - const orderEditItemChangeService = new OrderEditItemChangeService({ - manager: MockManager, - orderItemChangeRepository, - eventBusService: EventBusServiceMock as unknown as EventBusService, - lineItemService: LineItemServiceMock as unknown as LineItemService, - taxProviderService: taxProviderServiceMock as unknown as TaxProviderService, - }) - - it("should remove a item change", async () => { - const itemChangeId = IdMap.getId("order-edit-item-change-1") - await orderEditItemChangeService.delete(itemChangeId) - - expect(orderItemChangeRepository.delete).toHaveBeenCalledTimes(1) - expect(orderItemChangeRepository.delete).toHaveBeenCalledWith({ - id: In([itemChangeId]), - }) - - expect(taxProviderServiceMock.clearLineItemsTaxLines).toHaveBeenCalledTimes( - 1 - ) - expect(taxProviderServiceMock.clearLineItemsTaxLines).toHaveBeenCalledWith([ - "li_" + itemChangeId, - ]) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - OrderEditItemChangeService.Events.DELETED, - { ids: [itemChangeId] } - ) - }) -}) diff --git a/packages/medusa/src/services/__tests__/order-edit.ts b/packages/medusa/src/services/__tests__/order-edit.ts deleted file mode 100644 index 7a0f3746a8..0000000000 --- a/packages/medusa/src/services/__tests__/order-edit.ts +++ /dev/null @@ -1,470 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { - LineItemService, - NewTotalsService, - OrderEditItemChangeService, - OrderEditService, - OrderService, - TaxProviderService, - TotalsService, -} from "../index" -import { OrderEditItemChangeType, OrderEditStatus } from "../../models" - -import EventBusService from "../event-bus" -import { EventBusServiceMock } from "../__mocks__/event-bus" -import LineItemAdjustmentService from "../line-item-adjustment" -import { LineItemAdjustmentServiceMock } from "../__mocks__/line-item-adjustment" -import { LineItemServiceMock } from "../__mocks__/line-item" -import NewTotalsServiceMock from "../__mocks__/new-totals" -import { OrderServiceMock } from "../__mocks__/order" -import { TotalsServiceMock } from "../__mocks__/totals" -import { orderEditItemChangeServiceMock } from "../__mocks__/order-edit-item-change" -import { taxProviderServiceMock } from "../__mocks__/tax-provider" - -const orderEditToUpdate = { - id: IdMap.getId("order-edit-to-update"), - created_at: new Date(), - status: "created", -} - -const orderEditWithChanges = { - id: IdMap.getId("order-edit-with-changes"), - order: { - id: IdMap.getId("order-edit-with-changes-order"), - items: [ - { - id: IdMap.getId("line-item-1"), - }, - { - id: IdMap.getId("line-item-2"), - }, - ], - }, - items: [ - { - original_item_id: IdMap.getId("line-item-1"), - id: IdMap.getId("cloned-line-item-1"), - }, - { - original_item_id: IdMap.getId("line-item-2"), - id: IdMap.getId("cloned-line-item-2"), - }, - ], - changes: [ - { - type: OrderEditItemChangeType.ITEM_REMOVE, - id: "order-edit-with-changes-removed-change", - original_line_item_id: IdMap.getId("line-item-1"), - original_line_item: { - id: IdMap.getId("line-item-1"), - }, - }, - { - type: OrderEditItemChangeType.ITEM_ADD, - id: IdMap.getId("order-edit-with-changes-added-change"), - line_item_id: IdMap.getId("line-item-3"), - line_item: { - id: IdMap.getId("line-item-3"), - }, - }, - { - type: OrderEditItemChangeType.ITEM_UPDATE, - id: IdMap.getId("order-edit-with-changes-updated-change"), - original_line_item_id: IdMap.getId("line-item-2"), - original_line_item: { - id: IdMap.getId("line-item-2"), - }, - line_item_id: IdMap.getId("line-item-4"), - line_item: { - id: IdMap.getId("line-item-4"), - }, - }, - ], -} - -const orderEditWithAddedLineItem = { - id: IdMap.getId("order-edit-with-changes"), - order: { - id: IdMap.getId("order-edit-change"), - cart: { - discounts: [{ rule: {} }], - }, - region: { id: IdMap.getId("test-region") }, - }, -} - -const lineItemServiceMock = { - ...LineItemServiceMock, - list: jest.fn().mockImplementation(() => { - return Promise.resolve([ - { - id: IdMap.getId("line-item-1"), - }, - { - id: IdMap.getId("line-item-2"), - }, - ]) - }), - retrieve: jest.fn().mockImplementation((id) => { - const data = { - id, - quantity: 1, - fulfilled_quantity: 1, - } - - if (id === IdMap.getId("line-item-1")) { - return Promise.resolve({ - ...data, - order_edit_id: IdMap.getId("order-edit-update-line-item"), - }) - } - return Promise.resolve(data) - }), - cloneTo: () => [], -} - -describe("OrderEditService", () => { - afterEach(() => { - jest.clearAllMocks() - }) - - const orderEditRepository = MockRepository({ - findOne: (query) => { - if (query?.where?.id === IdMap.getId("order-edit-to-update")) { - return orderEditToUpdate - } - if (query?.where?.id === IdMap.getId("order-edit-with-changes")) { - return orderEditWithChanges - } - if (query?.where?.id === IdMap.getId("order-edit-update-line-item")) { - return { - ...orderEditWithChanges, - changes: [], - } - } - if (query?.where?.id === IdMap.getId("confirmed-order-edit")) { - return { - ...orderEditWithChanges, - id: IdMap.getId("confirmed-order-edit"), - status: OrderEditStatus.CONFIRMED, - } - } - if (query?.where?.id === IdMap.getId("requested-order-edit")) { - return { - ...orderEditWithChanges, - id: IdMap.getId("requested-order-edit"), - status: OrderEditStatus.REQUESTED, - } - } - if (query?.where?.id === IdMap.getId("declined-order-edit")) { - return { - ...orderEditWithChanges, - id: IdMap.getId("declined-order-edit"), - declined_reason: "wrong size", - declined_at: new Date(), - declined_by: "admin_user", - status: OrderEditStatus.DECLINED, - } - } - if (query?.where?.id === IdMap.getId("canceled-order-edit")) { - return { ...orderEditWithChanges, status: "canceled" } - } - if (query?.where?.id === IdMap.getId("confirmed-order-edit")) { - return { ...orderEditWithChanges, status: "confirmed" } - } - if (query?.where?.id === IdMap.getId("declined-order-edit")) { - return { ...orderEditWithChanges, status: "declined" } - } - - return - }, - create: (data) => { - return { - ...orderEditWithChanges, - ...data, - } - }, - }) - const orderEditService = new OrderEditService({ - manager: MockManager, - orderEditRepository, - orderService: OrderServiceMock as unknown as OrderService, - eventBusService: EventBusServiceMock as unknown as EventBusService, - totalsService: TotalsServiceMock as unknown as TotalsService, - newTotalsService: NewTotalsServiceMock as unknown as NewTotalsService, - lineItemService: lineItemServiceMock as unknown as LineItemService, - orderEditItemChangeService: - orderEditItemChangeServiceMock as unknown as OrderEditItemChangeService, - lineItemAdjustmentService: - LineItemAdjustmentServiceMock as unknown as LineItemAdjustmentService, - taxProviderService: taxProviderServiceMock as unknown as TaxProviderService, - }) - - it("should retrieve an order edit and call the repository with the right arguments", async () => { - await orderEditService.retrieve(IdMap.getId("order-edit-with-changes")) - expect(orderEditRepository.findOne).toHaveBeenCalledTimes(1) - expect(orderEditRepository.findOne).toHaveBeenCalledWith({ - where: { id: IdMap.getId("order-edit-with-changes") }, - }) - }) - - it("should update an order edit with the right arguments", async () => { - await orderEditService.update(IdMap.getId("order-edit-to-update"), { - internal_note: "test note", - }) - expect(orderEditRepository.save).toHaveBeenCalledTimes(1) - expect(orderEditRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - id: IdMap.getId("order-edit-to-update"), - internal_note: "test note", - }) - ) - }) - - it("should create an order edit and call the repository with the right arguments as well as the event bus service", async () => { - const data = { - order_id: IdMap.getId("order-edit-order-id"), - internal_note: "internal note", - } - await orderEditService.create(data, { - createdBy: IdMap.getId("admin_user"), - }) - - expect(orderEditRepository.create).toHaveBeenCalledTimes(1) - expect(orderEditRepository.create).toHaveBeenCalledWith({ - order_id: data.order_id, - internal_note: data.internal_note, - created_by: IdMap.getId("admin_user"), - }) - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - OrderEditService.Events.CREATED, - { id: expect.any(String) } - ) - }) - - it("should update a line item and create an item change to an order edit", async () => { - await orderEditService.updateLineItem( - IdMap.getId("order-edit-update-line-item"), - IdMap.getId("line-item-1"), - { - quantity: 3, - } - ) - - expect(orderEditItemChangeServiceMock.list).toHaveBeenCalledTimes(1) - expect(orderEditItemChangeServiceMock.create).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustments - ).toHaveBeenCalledTimes(1) - }) - - describe("decline", () => { - it("declines an order edit", async () => { - const result = await orderEditService.decline( - IdMap.getId("requested-order-edit"), - { - declinedReason: "I requested a different color for the new product", - declinedBy: "admin_user", - } - ) - - expect(result).toEqual( - expect.objectContaining({ - id: IdMap.getId("requested-order-edit"), - declined_at: expect.any(Date), - declined_reason: "I requested a different color for the new product", - declined_by: "admin_user", - }) - ) - }) - - it("fails to decline a confirmed order edit", async () => { - await expect( - orderEditService.decline(IdMap.getId("confirmed-order-edit"), { - declinedReason: "I requested a different color for the new product", - declinedBy: "admin_user", - }) - ).rejects.toThrowError( - "Cannot decline an order edit with status confirmed." - ) - }) - - it("fails to re-decline an already declined order edit", async () => { - const result = await orderEditService.decline( - IdMap.getId("declined-order-edit"), - { - declinedReason: "I requested a different color for the new product", - declinedBy: "admin_user", - } - ) - - expect(result).toEqual( - expect.objectContaining({ - id: IdMap.getId("declined-order-edit"), - declined_at: expect.any(Date), - declined_reason: "wrong size", - declined_by: "admin_user", - status: "declined", - }) - ) - }) - }) - - it("should add a line item to an order edit", async () => { - jest - .spyOn(orderEditService, "refreshAdjustments") - .mockImplementation(async () => {}) - - await orderEditService.addLineItem(IdMap.getId("order-edit-with-changes"), { - variant_id: IdMap.getId("to-be-added-variant"), - quantity: 3, - }) - - expect(LineItemServiceMock.generate).toHaveBeenCalledTimes(1) - expect(orderEditService.refreshAdjustments).toHaveBeenCalledTimes(1) - expect(taxProviderServiceMock.createTaxLines).toHaveBeenCalledTimes(1) - expect(orderEditItemChangeServiceMock.create).toHaveBeenCalledTimes(1) - }) - - describe("requestConfirmation", () => { - describe("created edit", () => { - const orderEditId = IdMap.getId("order-edit-with-changes") - const userId = IdMap.getId("user-id") - let result - - beforeEach(async () => { - jest.spyOn(orderEditService, "decorateTotals").mockResolvedValue({ - difference_due: 1500, - } as any) - - result = await orderEditService.requestConfirmation(orderEditId, { - requestedBy: userId, - }) - }) - - it("sets fields correctly for update", async () => { - expect(result).toEqual( - expect.objectContaining({ - requested_at: expect.any(Date), - requested_by: userId, - }) - ) - - expect(orderEditRepository.save).toHaveBeenCalledWith({ - ...orderEditWithChanges, - requested_at: expect.any(Date), - requested_by: userId, - }) - - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - OrderEditService.Events.REQUESTED, - { id: orderEditId } - ) - }) - }) - - describe("requested edit", () => { - const orderEditId = IdMap.getId("requested-order-edit") - const userId = IdMap.getId("user-id") - let result - - beforeEach(async () => { - result = await orderEditService.requestConfirmation(orderEditId, { - requestedBy: userId, - }) - }) - - afterEach(() => { - jest.clearAllMocks() - }) - }) - - describe("cancel", () => { - it("Cancels an order edit", async () => { - const id = IdMap.getId("order-edit-with-changes") - const userId = IdMap.getId("user-id") - - await orderEditService.cancel(id, { canceledBy: userId }) - - expect(orderEditRepository.save).toHaveBeenCalledWith({ - ...orderEditWithChanges, - canceled_by: userId, - canceled_at: expect.any(Date), - }) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - OrderEditService.Events.CANCELED, - { id } - ) - }) - - it("Returns early in case of an already canceled order edit", async () => { - const id = IdMap.getId("canceled-order-edit") - const userId = IdMap.getId("user-id") - - const result = await orderEditService.cancel(id, { - canceledBy: userId, - }) - - expect(result).toEqual(expect.objectContaining({ status: "canceled" })) - - expect(orderEditRepository.save).toHaveBeenCalledTimes(0) - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(0) - }) - - test.each(["confirmed", "declined"])( - "Fails to cancel an edit with status %s", - async (status) => { - expect.assertions(1) - const id = IdMap.getId(`${status}-order-edit`) - const userId = IdMap.getId("user-id") - - try { - await orderEditService.cancel(id, { canceledBy: userId }) - } catch (err) { - expect(err.message).toEqual( - `Cannot cancel order edit with status ${status}` - ) - } - } - ) - }) - - describe("confirm", () => { - it("confirms an order edit", async () => { - const id = IdMap.getId("order-edit-with-changes") - const userId = IdMap.getId("user-id") - - await orderEditService.confirm(id, { confirmedBy: userId }) - - expect(orderEditRepository.save).toHaveBeenCalledWith({ - ...orderEditWithChanges, - confirmed_by: userId, - confirmed_at: expect.any(Date), - }) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - OrderEditService.Events.CONFIRMED, - { id } - ) - }) - - it("returns early in case of an already confirmed order edit", async () => { - const id = IdMap.getId("confirmed-order-edit") - const userId = IdMap.getId("user-id") - - const result = await orderEditService.confirm(id, { - confirmedBy: userId, - }) - - expect(result).toEqual(expect.objectContaining({ status: "confirmed" })) - - expect(orderEditRepository.save).toHaveBeenCalledTimes(0) - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(0) - }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/order.js b/packages/medusa/src/services/__tests__/order.js deleted file mode 100644 index 3e28b46b24..0000000000 --- a/packages/medusa/src/services/__tests__/order.js +++ /dev/null @@ -1,1700 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { FlagRouter } from "@medusajs/utils" -import { LineItemServiceMock } from "../__mocks__/line-item" -import { newTotalsServiceMock } from "../__mocks__/new-totals" -import { ProductVariantInventoryServiceMock } from "../__mocks__/product-variant-inventory" -import { taxProviderServiceMock } from "../__mocks__/tax-provider" -import OrderService from "../order" - -describe("OrderService", () => { - const totalsService = { - withTransaction: function () { - return this - }, - getCalculationContext: jest.fn().mockImplementation((order, lineItems) => { - return Promise.resolve({}) - }), - getLineItemTotals: jest.fn().mockImplementation(() => { - return Promise.resolve({}) - }), - getLineItemRefund: () => {}, - getTotal: (o) => { - return o.total || 0 - }, - getGiftCardableAmount: (o) => { - return o.subtotal || 0 - }, - getRefundedTotal: (o) => { - return o.refunded_total || 0 - }, - getShippingTotal: (o) => { - return o.shipping_total || 0 - }, - getGiftCardTotal: (o) => { - return o.gift_card_total || 0 - }, - getDiscountTotal: (o) => { - return o.discount_total || 0 - }, - getTaxTotal: (o) => { - return o.tax_total || 0 - }, - getSubtotal: (o) => { - return o.subtotal || 0 - }, - getPaidTotal: (o) => { - return o.paid_total || 0 - }, - } - - const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - return this - }, - } - - const productVariantInventoryService = { - ...ProductVariantInventoryServiceMock, - } - - describe("createFromCart", () => { - const orderRepo = MockRepository({ - create: (p) => p, - save: (p) => ({ ...p, id: "id" }), - }) - const lineItemService = { - update: jest.fn(), - withTransaction: function () { - return this - }, - } - const shippingOptionService = { - updateShippingMethod: jest.fn(), - withTransaction: function () { - return this - }, - } - const giftCardService = { - create: jest.fn(), - update: jest.fn(), - createTransaction: jest.fn(), - withTransaction: function () { - return this - }, - } - const paymentProviderService = { - getStatus: (payment) => { - return Promise.resolve(payment.status || "authorized") - }, - updatePayment: jest.fn(), - cancelPayment: jest.fn().mockImplementation((payment) => { - return Promise.resolve({ ...payment, status: "cancelled" }) - }), - withTransaction: function () { - return this - }, - } - const emptyCart = { - region: {}, - items: [], - total: 0, - } - const cartService = { - retrieveWithTotals: jest.fn().mockImplementation((query) => { - if (query === "empty") { - return Promise.resolve(emptyCart) - } - return Promise.resolve({ - id: "cart_id", - email: "test@test.com", - customer_id: "cus_1234", - payment: { - id: "testpayment", - amount: 100, - status: "authorized", - }, - region_id: "test", - region: { - id: "test", - currency_code: "eur", - name: "test", - tax_rate: 25, - }, - shipping_address_id: "1234", - billing_address_id: "1234", - discounts: [], - gift_cards: [], - shipping_methods: [{ id: "method_1" }], - items: [{ id: "item_1" }, { id: "item_2" }], - total: 100, - }) - }), - update: jest.fn(() => Promise.resolve()), - withTransaction: function () { - return this - }, - } - - const discountService = {} - const regionService = {} - const orderService = new OrderService({ - manager: MockManager, - orderRepository: orderRepo, - lineItemService, - giftCardService, - paymentProviderService, - shippingOptionService, - totalsService, - newTotalsService: newTotalsServiceMock, - discountService, - regionService, - eventBusService, - cartService, - productVariantInventoryService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("fails when no items", async () => { - const res = orderService.createFromCart("empty") - await expect(res).rejects.toThrow("Cannot create order from empty cart") - }) - - it("calls order model functions", async () => { - const cart = { - id: "cart_id", - email: "test@test.com", - customer_id: "cus_1234", - payment: { - id: "testpayment", - amount: 100, - status: "authorized", - }, - region_id: "test", - region: { - id: "test", - currency_code: "eur", - name: "test", - tax_rate: 25, - }, - shipping_address_id: "1234", - billing_address_id: "1234", - gift_cards: [], - discounts: [], - shipping_methods: [{ id: "method_1" }], - items: [ - { id: "item_1", variant_id: "variant-1", quantity: 1 }, - { id: "item_2", variant_id: "variant-2", quantity: 1 }, - ], - total: 100, - subtotal: 100, - discount_total: 0, - } - - orderService.cartService_.retrieveWithTotals = jest.fn(() => - Promise.resolve(cart) - ) - - await orderService.createFromCart("cart_id") - const order = { - payment_status: "awaiting", - email: cart.email, - customer_id: cart.customer_id, - shipping_methods: cart.shipping_methods, - discounts: cart.discounts, - billing_address_id: cart.billing_address_id, - shipping_address_id: cart.shipping_address_id, - region_id: cart.region_id, - currency_code: "eur", - cart_id: "cart_id", - gift_cards: [], - metadata: {}, - } - - expect(cartService.retrieveWithTotals).toHaveBeenCalledTimes(1) - expect(cartService.retrieveWithTotals).toHaveBeenCalledWith("cart_id", { - relations: ["region", "payment", "items"], - }) - - expect(paymentProviderService.updatePayment).toHaveBeenCalledTimes(1) - expect(paymentProviderService.updatePayment).toHaveBeenCalledWith( - "testpayment", - { - order_id: "id", - } - ) - - expect(lineItemService.update).toHaveBeenCalledTimes(2) - expect(lineItemService.update).toHaveBeenCalledWith("item_1", { - order_id: "id", - }) - expect(lineItemService.update).toHaveBeenCalledWith("item_2", { - order_id: "id", - }) - - expect(orderRepo.create).toHaveBeenCalledTimes(1) - expect(orderRepo.create).toHaveBeenCalledWith(order) - expect(orderRepo.save).toHaveBeenCalledWith(order) - }) - - describe("gift card creation", () => { - const taxLineRateOne = 20 - const taxLineRateTwo = 10 - const giftCardValue = 100 - const totalGiftCardsPurchased = 2 - const expectedGiftCardTaxRate = taxLineRateOne + taxLineRateTwo - const lineItemWithGiftCard = { - id: "item_1", - variant_id: "variant-1", - // quantity: 2, - is_giftcard: true, - subtotal: giftCardValue * totalGiftCardsPurchased, - quantity: totalGiftCardsPurchased, - metadata: {}, - tax_lines: [ - { - rate: taxLineRateOne, - }, - { - rate: taxLineRateTwo, - }, - ], - } - - const lineItemWithoutGiftCard = { - ...lineItemWithGiftCard, - is_giftcard: false, - } - - const cartWithGiftcard = { - id: "id", - email: "test@test.com", - customer_id: "cus_1234", - payment: {}, - region_id: "test", - region: { - id: "test", - currency_code: "eur", - name: "test", - tax_rate: 25, - }, - shipping_address_id: "1234", - billing_address_id: "1234", - gift_cards: [], - discounts: [], - shipping_methods: [{ id: "method_1" }], - items: [lineItemWithGiftCard], - total: 100, - subtotal: 100, - discount_total: 0, - } - - const cartWithoutGiftcard = { - ...cartWithGiftcard, - items: [lineItemWithoutGiftCard], - } - - it("creates gift cards when a lineItem contains a gift card variant", async () => { - orderService.cartService_.retrieveWithTotals = jest.fn(() => - Promise.resolve(cartWithGiftcard) - ) - - await orderService.createFromCart("id") - - expect(giftCardService.create).toHaveBeenCalledTimes( - totalGiftCardsPurchased - ) - expect(giftCardService.create).toHaveBeenCalledWith({ - order_id: "id", - region_id: "test", - value: giftCardValue, - balance: giftCardValue, - metadata: {}, - tax_rate: expectedGiftCardTaxRate, - }) - }) - - it("does not create gift cards when a lineItem doesn't contains a gift card variant", async () => { - orderService.cartService_.retrieveWithTotals = jest.fn(() => - Promise.resolve(cartWithoutGiftcard) - ) - - await orderService.createFromCart("id") - - expect(giftCardService.create).not.toHaveBeenCalled() - }) - }) - - it("creates gift card transactions", async () => { - const cart = { - id: "cart_id", - email: "test@test.com", - customer_id: "cus_1234", - payment: { - id: "testpayment", - amount: 100, - status: "authorized", - }, - region_id: "test", - region: { - id: "test", - currency_code: "eur", - name: "test", - gift_cards_taxable: true, - tax_rate: 25, - }, - shipping_address_id: "1234", - billing_address_id: "1234", - gift_cards: [ - { - id: "gid", - code: "GC", - balance: 80, - tax_rate: 25, - }, - ], - discounts: [], - shipping_methods: [{ id: "method_1" }], - items: [ - { id: "item_1", variant_id: "variant-1", quantity: 1 }, - { id: "item_2", variant_id: "variant-2", quantity: 1 }, - ], - subtotal: 100, - total: 100, - discount_total: 0, - gift_card_total: 100, - } - - orderService.cartService_.retrieveWithTotals = () => { - return Promise.resolve(cart) - } - - await orderService.createFromCart("cart_id") - const order = { - payment_status: "awaiting", - email: cart.email, - customer_id: cart.customer_id, - shipping_methods: cart.shipping_methods, - discounts: cart.discounts, - billing_address_id: cart.billing_address_id, - shipping_address_id: cart.shipping_address_id, - region_id: cart.region_id, - currency_code: "eur", - cart_id: "cart_id", - gift_cards: [ - { - id: "gid", - code: "GC", - balance: 80, - tax_rate: 25, - }, - ], - metadata: {}, - } - - expect(giftCardService.update).toHaveBeenCalledTimes(1) - expect(giftCardService.update).toHaveBeenCalledWith("gid", { - balance: 0, - is_disabled: true, - }) - - expect(giftCardService.createTransaction).toHaveBeenCalledTimes(1) - expect(giftCardService.createTransaction).toHaveBeenCalledWith({ - gift_card_id: "gid", - order_id: "id", - is_taxable: true, - tax_rate: 25, - amount: 80, - }) - - expect(paymentProviderService.updatePayment).toHaveBeenCalledTimes(1) - expect(paymentProviderService.updatePayment).toHaveBeenCalledWith( - "testpayment", - { - order_id: "id", - } - ) - - expect(lineItemService.update).toHaveBeenCalledTimes(2) - expect(lineItemService.update).toHaveBeenCalledWith("item_1", { - order_id: "id", - }) - expect(lineItemService.update).toHaveBeenCalledWith("item_2", { - order_id: "id", - }) - - expect(orderRepo.create).toHaveBeenCalledTimes(1) - expect(orderRepo.create).toHaveBeenCalledWith(order) - expect(orderRepo.save).toHaveBeenCalledWith(order) - }) - - it("creates cart with 0 total", async () => { - const cart = { - id: "cart_id", - email: "test@test.com", - customer_id: "cus_1234", - payment: { - id: "testpayment", - amount: 100, - status: "authorized", - }, - region_id: "test", - region: { - id: "test", - currency_code: "eur", - name: "test", - tax_rate: 25, - }, - gift_cards: [], - shipping_address_id: "1234", - billing_address_id: "1234", - discounts: [], - shipping_methods: [{ id: "method_1" }], - items: [ - { id: "item_1", variant_id: "variant-1", quantity: 1 }, - { id: "item_2", variant_id: "variant-2", quantity: 1 }, - ], - total: 0, - subtotal: 0, - discount_total: 0, - } - orderService.cartService_.retrieveWithTotals = () => Promise.resolve(cart) - await orderService.createFromCart("cart_id") - const order = { - payment_status: "awaiting", - email: cart.email, - customer_id: cart.customer_id, - shipping_methods: cart.shipping_methods, - discounts: cart.discounts, - billing_address_id: cart.billing_address_id, - shipping_address_id: cart.shipping_address_id, - gift_cards: [], - region_id: cart.region_id, - currency_code: "eur", - cart_id: "cart_id", - metadata: {}, - } - expect(orderRepo.create).toHaveBeenCalledTimes(1) - expect(orderRepo.create).toHaveBeenCalledWith(order) - - expect(lineItemService.update).toHaveBeenCalledTimes(2) - expect(lineItemService.update).toHaveBeenCalledWith("item_1", { - order_id: "id", - }) - expect(lineItemService.update).toHaveBeenCalledWith("item_2", { - order_id: "id", - }) - - expect(orderRepo.save).toHaveBeenCalledWith(order) - }) - }) - - describe("retrieve", () => { - const orderRepo = MockRepository({ - findOneWithRelations: (q) => { - return Promise.resolve({}) - }, - }) - const orderService = new OrderService({ - manager: MockManager, - orderRepository: orderRepo, - totalsService, - newTotalsService: newTotalsServiceMock, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls order model functions", async () => { - await orderService.retrieve(IdMap.getId("test-order")) - expect(orderRepo.findOneWithRelations).toHaveBeenCalledTimes(1) - expect(orderRepo.findOneWithRelations).toHaveBeenCalledWith( - {}, - { - where: { id: IdMap.getId("test-order") }, - } - ) - }) - }) - - describe("retrieveByCartIdWithTotals", () => { - const orderRepo = MockRepository({ - findOneWithRelations: (q) => { - return Promise.resolve({}) - }, - }) - - const orderService = new OrderService({ - totalsService, - newTotalsService: newTotalsServiceMock, - manager: MockManager, - orderRepository: orderRepo, - }) - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls order model functions", async () => { - await orderService.retrieveByCartIdWithTotals(IdMap.getId("test-cart")) - - expect(orderRepo.findOneWithRelations).toHaveBeenCalledTimes(1) - expect(orderRepo.findOneWithRelations).toHaveBeenCalledWith( - expect.any(Object), - { - where: { cart_id: IdMap.getId("test-cart") }, - } - ) - }) - }) - - describe("update", () => { - const orderRepo = MockRepository({ - findOneWithRelations: (rel, q) => { - switch (q.where.id) { - case IdMap.getId("fulfilled-order"): - return Promise.resolve({ - fulfillment_status: "fulfilled", - payment_status: "awaiting", - status: "pending", - }) - case IdMap.getId("canceled-order"): - return Promise.resolve({ - status: "canceled", - }) - default: - return Promise.resolve({ - fulfillment_status: "not_fulfilled", - payment_status: "awaiting", - status: "pending", - }) - } - }, - }) - const orderService = new OrderService({ - totalsService, - newTotalsService: newTotalsServiceMock, - manager: MockManager, - orderRepository: orderRepo, - eventBusService, - lineItemService: LineItemServiceMock, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("calls order model functions", async () => { - await orderService.update(IdMap.getId("test-order"), { - email: "oliver@test.dk", - }) - - expect(orderRepo.save).toHaveBeenCalledTimes(1) - expect(orderRepo.save).toHaveBeenCalledWith({ - email: "oliver@test.dk", - fulfillment_status: "not_fulfilled", - payment_status: "awaiting", - status: "pending", - }) - }) - - it("throws if metadata update are attempted", async () => { - await orderService.update(IdMap.getId("test-order"), { - metadata: { test: "foo" }, - }) - expect(orderRepo.save).toHaveBeenCalledTimes(1) - expect(orderRepo.save).toHaveBeenCalledWith({ - metadata: { test: "foo" }, - fulfillment_status: "not_fulfilled", - payment_status: "awaiting", - status: "pending", - }) - }) - - it("throws if payment method update is attempted after fulfillment", async () => { - await expect( - orderService.update(IdMap.getId("fulfilled-order"), { - payment: { - provider_id: "test", - profile_id: "test", - }, - }) - ).rejects.toThrow( - "Can't update shipping, billing, items and payment method when order is processed" - ) - }) - - it("throws if items update is attempted after fulfillment", async () => { - await expect( - orderService.update(IdMap.getId("fulfilled-order"), { - items: [], - }) - ).rejects.toThrow( - "Can't update shipping, billing, items and payment method when order is processed" - ) - }) - - it("throws if order is canceled", async () => { - await expect( - orderService.update(IdMap.getId("canceled-order"), {}) - ).rejects.toThrow("A canceled order cannot be updated") - }) - }) - - describe("cancel", () => { - const now = new Date() - - const orderRepo = MockRepository({ - findOneWithRelations: (rel, q) => { - switch (q.where.id) { - case IdMap.getId("paid-order"): - return Promise.resolve({ - fulfillment_status: "fulfilled", - payment_status: "paid", - status: "pending", - }) - case IdMap.getId("refunded-order"): - return Promise.resolve({ - fulfillment_status: "fulfilled", - payment_status: "refunded", - refunds: [ - { - order_id: IdMap.getId("refunded-order"), - }, - ], - status: "pending", - }) - default: - return Promise.resolve({ - fulfillment_status: "not_fulfilled", - payment_status: "awaiting", - status: "pending", - fulfillments: [ - { id: "fulfillment_test", canceled_at: now, items: [] }, - ], - payments: [{ id: "payment_test" }], - items: [ - { id: "item_1", variant_id: "variant-1", quantity: 12 }, - { id: "item_2", variant_id: "variant-2", quantity: 1 }, - ], - }) - } - }, - }) - - const fulfillmentService = { - cancelFulfillment: jest.fn(), - withTransaction: function () { - return this - }, - } - - const paymentProviderService = { - cancelPayment: jest.fn(), - withTransaction: function () { - return this - }, - } - - const orderService = new OrderService({ - totalsService, - newTotalsService: newTotalsServiceMock, - manager: MockManager, - orderRepository: orderRepo, - paymentProviderService, - fulfillmentService, - eventBusService, - productVariantInventoryService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("calls order model functions", async () => { - try { - await orderService.retrieve(IdMap.getId("not-fulfilled-order")) - await orderService.cancel(IdMap.getId("not-fulfilled-order")) - } catch (e) { - console.warn(e) - } - - expect(paymentProviderService.cancelPayment).toHaveBeenCalledTimes(1) - expect(paymentProviderService.cancelPayment).toHaveBeenCalledWith({ - id: "payment_test", - }) - - expect(orderRepo.save).toHaveBeenCalledTimes(1) - expect(orderRepo.save).toHaveBeenCalledWith({ - fulfillment_status: "canceled", - payment_status: "canceled", - canceled_at: expect.any(Date), - status: "canceled", - fulfillments: [{ id: "fulfillment_test", canceled_at: now, items: [] }], - payments: [{ id: "payment_test" }], - items: [ - { - id: "item_1", - quantity: 12, - variant_id: "variant-1", - }, - { - id: "item_2", - quantity: 1, - variant_id: "variant-2", - }, - ], - }) - }) - - it("fails if order has refunds", async () => { - await expect( - orderService.cancel(IdMap.getId("refunded-order")) - ).rejects.toThrow("Order with refund(s) cannot be canceled") - }) - }) - - describe("capturePayment", () => { - const orderRepo = MockRepository({ - findOneWithRelations: (rel, q) => { - switch (q.where.id) { - case IdMap.getId("fail"): - return Promise.resolve({ - payment_status: "awaiting", - payments: [{ id: "payment_fail", captured_at: null }], - }) - case IdMap.getId("canceled"): - return Promise.resolve({ status: "canceled" }) - default: - return Promise.resolve({ - fulfillment_status: "not_fulfilled", - payment_status: "awaiting", - status: "pending", - fulfillments: [{ id: "fulfillment_test" }], - payments: [{ id: "payment_test", captured_at: null }], - }) - } - }, - }) - - const paymentProviderService = { - capturePayment: jest - .fn() - .mockImplementation((p) => - p.id === "payment_fail" - ? Promise.reject() - : Promise.resolve({ ...p, captured_at: "notnull" }) - ), - withTransaction: function () { - return this - }, - } - - const orderService = new OrderService({ - manager: MockManager, - orderRepository: orderRepo, - paymentProviderService, - totalsService, - newTotalsService: newTotalsServiceMock, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("calls order model functions", async () => { - await orderService.capturePayment("test-order") - - expect(paymentProviderService.capturePayment).toHaveBeenCalledTimes(1) - expect(paymentProviderService.capturePayment).toHaveBeenCalledWith({ - id: "payment_test", - captured_at: null, - }) - - expect(orderRepo.save).toHaveBeenCalledTimes(1) - expect(orderRepo.save).toHaveBeenCalledWith({ - fulfillment_status: "not_fulfilled", - payment_status: "captured", - status: "pending", - fulfillments: [{ id: "fulfillment_test" }], - payments: [{ id: "payment_test", captured_at: "notnull" }], - }) - }) - - it("sets requires action on failure", async () => { - await orderService.capturePayment(IdMap.getId("fail")) - - expect(paymentProviderService.capturePayment).toHaveBeenCalledTimes(1) - expect(paymentProviderService.capturePayment).toHaveBeenCalledWith({ - id: "payment_fail", - captured_at: null, - }) - - expect(orderRepo.save).toHaveBeenCalledTimes(1) - expect(orderRepo.save).toHaveBeenCalledWith({ - payment_status: "requires_action", - payments: [{ id: "payment_fail", captured_at: null }], - }) - }) - - it("fails if order is canceled", async () => { - await expect( - orderService.capturePayment(IdMap.getId("canceled")) - ).rejects.toThrow("A canceled order cannot capture payment") - }) - }) - - describe("createFulfillment", () => { - const partialOrder = { - fulfillments: [], - shipping_methods: [{ id: "ship" }], - items: [ - { - id: "item_1", - quantity: 2, - fulfilled_quantity: 0, - }, - { - id: "item_2", - quantity: 1, - fulfilled_quantity: 0, - }, - ], - } - - const order = { - fulfillments: [], - shipping_methods: [{ id: "ship" }], - no_notification: true, - items: [ - { - id: "item_1", - quantity: 2, - fulfilled_quantity: 0, - }, - ], - } - - const orderRepo = MockRepository({ - findOneWithRelations: (rel, q) => { - switch (q.where.id) { - case "partial": - return Promise.resolve(partialOrder) - case "canceled": - return Promise.resolve({ status: "canceled", ...order }) - default: - return Promise.resolve(order) - } - }, - }) - - const lineItemService = { - update: jest.fn(), - withTransaction: function () { - return this - }, - } - - const fulfillmentService = { - createFulfillment: jest.fn().mockImplementation((o, i, m) => { - return Promise.resolve([ - { - items: i, - }, - ]) - }), - withTransaction: function () { - return this - }, - } - - const orderService = new OrderService({ - manager: MockManager, - orderRepository: orderRepo, - fulfillmentService, - lineItemService, - totalsService, - newTotalsService: newTotalsServiceMock, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("calls order model functions", async () => { - await orderService.createFulfillment("test-order", [ - { - item_id: "item_1", - quantity: 2, - }, - ]) - - expect(fulfillmentService.createFulfillment).toHaveBeenCalledTimes(1) - expect(fulfillmentService.createFulfillment).toHaveBeenCalledWith( - order, - [ - { - item_id: "item_1", - quantity: 2, - }, - ], - { metadata: {}, order_id: "test-order", location_id: undefined } - ) - - expect(lineItemService.update).toHaveBeenCalledTimes(1) - expect(lineItemService.update).toHaveBeenCalledWith("item_1", { - fulfilled_quantity: 2, - }) - - expect(orderRepo.save).toHaveBeenCalledTimes(1) - expect(orderRepo.save).toHaveBeenCalledWith({ - ...order, - fulfillment_status: "fulfilled", - }) - }) - - it("sets partially fulfilled", async () => { - await orderService.createFulfillment("partial", [ - { - item_id: "item_1", - quantity: 2, - }, - ]) - - expect(fulfillmentService.createFulfillment).toHaveBeenCalledTimes(1) - expect(fulfillmentService.createFulfillment).toHaveBeenCalledWith( - partialOrder, - [ - { - item_id: "item_1", - quantity: 2, - }, - ], - { metadata: {}, order_id: "partial", location_id: undefined } - ) - - expect(lineItemService.update).toHaveBeenCalledTimes(1) - expect(lineItemService.update).toHaveBeenCalledWith("item_1", { - fulfilled_quantity: 2, - }) - - expect(orderRepo.save).toHaveBeenCalledTimes(1) - expect(orderRepo.save).toHaveBeenCalledWith({ - ...partialOrder, - fulfillment_status: "partially_fulfilled", - }) - }) - - it("sets partially fulfilled", async () => { - await orderService.createFulfillment("test", [ - { - item_id: "item_1", - quantity: 1, - }, - ]) - - expect(fulfillmentService.createFulfillment).toHaveBeenCalledTimes(1) - expect(fulfillmentService.createFulfillment).toHaveBeenCalledWith( - order, - [ - { - item_id: "item_1", - quantity: 1, - }, - ], - { metadata: {}, order_id: "test", location_id: undefined } - ) - - expect(lineItemService.update).toHaveBeenCalledTimes(1) - expect(lineItemService.update).toHaveBeenCalledWith("item_1", { - fulfilled_quantity: 1, - }) - - expect(orderRepo.save).toHaveBeenCalledTimes(1) - expect(orderRepo.save).toHaveBeenCalledWith({ - ...order, - fulfillment_status: "partially_fulfilled", - }) - }) - - it("Calls createFulfillment with locationId", async () => { - await orderService.createFulfillment( - "test", - [ - { - item_id: "item_1", - quantity: 1, - }, - ], - { - location_id: "loc_1", - } - ) - - expect(fulfillmentService.createFulfillment).toHaveBeenCalledTimes(1) - expect(fulfillmentService.createFulfillment).toHaveBeenCalledWith( - order, - [ - { - item_id: "item_1", - quantity: 1, - }, - ], - { - metadata: {}, - order_id: "test", - no_notification: undefined, - location_id: "loc_1", - } - ) - }) - - it("fails if order is canceled", async () => { - await expect( - orderService.createFulfillment("canceled", [ - { - item_id: "item_1", - quantity: 1, - }, - ]) - ).rejects.toThrow("A canceled order cannot be fulfilled") - }) - it.each([ - [true, true], - [false, false], - [undefined, true], - ])( - "emits correct no_notification option with '%s'", - async (input, expected) => { - await orderService.createFulfillment( - "test-order", - [ - { - item_id: "item_1", - quantity: 1, - }, - ], - { no_notification: input } - ) - - expect(eventBusService.emit).toHaveBeenCalledWith([ - { - eventName: expect.any(String), - data: { - id: expect.any(String), - no_notification: expected, - }, - }, - ]) - } - ) - }) - - describe("cancelFulfillment", () => { - const orderRepo = MockRepository({ - findOneWithRelations: () => Promise.resolve({}), - save: (f) => Promise.resolve(f), - }) - - const fulfillmentService = { - cancelFulfillment: jest.fn().mockImplementation((f) => { - switch (f) { - case IdMap.getId("no-order"): - return Promise.resolve({}) - default: - return Promise.resolve({ - order_id: IdMap.getId("order-id"), - }) - } - }), - withTransaction: function () { - return this - }, - } - - const orderService = new OrderService({ - manager: MockManager, - orderRepository: orderRepo, - fulfillmentService, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully cancels fulfillment and corrects order status", async () => { - await orderService.cancelFulfillment(IdMap.getId("order")) - - expect(fulfillmentService.cancelFulfillment).toHaveBeenCalledTimes(1) - expect(fulfillmentService.cancelFulfillment).toHaveBeenCalledWith( - IdMap.getId("order") - ) - - expect(orderRepo.save).toHaveBeenCalledTimes(1) - expect(orderRepo.save).toHaveBeenCalledWith({ - fulfillment_status: "canceled", - }) - }) - - it("fails to cancel fulfillment when not related to an order", async () => { - await expect( - orderService.cancelFulfillment(IdMap.getId("no-order")) - ).rejects.toThrow(`Fufillment not related to an order`) - }) - }) - - describe("registerReturnReceived", () => { - const order = { - items: [ - { - id: "item_1", - quantity: 10, - returned_quantity: 10, - }, - ], - payments: [{ id: "payment_test", amount: 100 }], - refunded_total: 0, - paid_total: 100, - refundable_amount: 100, - total: 100, - } - const orderRepo = MockRepository({ - findOneWithRelations: (rel, q) => { - switch (q.where.id) { - case IdMap.getId("canceled"): - return Promise.resolve({ status: "canceled", ...order }) - default: - return Promise.resolve(order) - } - }, - }) - - const paymentProviderService = { - refundPayment: jest - .fn() - .mockImplementation((p) => - p.id === "payment_fail" ? Promise.reject() : Promise.resolve() - ), - withTransaction: function () { - return this - }, - } - - const orderService = new OrderService({ - manager: MockManager, - orderRepository: orderRepo, - paymentProviderService, - totalsService, - newTotalsService: newTotalsServiceMock, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("calls order model functions", async () => { - await orderService.registerReturnReceived(IdMap.getId("order"), { - id: IdMap.getId("good"), - order_id: IdMap.getId("order"), - status: "received", - refund_amount: 100, - }) - - expect(orderRepo.save).toHaveBeenCalledTimes(1) - expect(orderRepo.save).toHaveBeenCalledWith({ - ...order, - fulfillment_status: "returned", - }) - - expect(paymentProviderService.refundPayment).toHaveBeenCalledTimes(1) - expect(paymentProviderService.refundPayment).toHaveBeenCalledWith( - order.payments, - 100, - "return" - ) - }) - - it("return with custom refund", async () => { - await orderService.registerReturnReceived( - IdMap.getId("order"), - { - id: IdMap.getId("good"), - order_id: IdMap.getId("order"), - status: "received", - refund_amount: 95, - }, - 95 - ) - - expect(paymentProviderService.refundPayment).toHaveBeenCalledTimes(1) - expect(paymentProviderService.refundPayment).toHaveBeenCalledWith( - order.payments, - 95, - "return" - ) - }) - - it("fails when order is canceled", async () => { - await expect( - orderService.registerReturnReceived(IdMap.getId("canceled"), {}) - ).rejects.toThrow("A canceled order cannot be registered as received") - }) - }) - - describe("completeOrder", () => { - const orderRepo = MockRepository({ - findOneWithRelations: (rel, q) => { - switch (q.where.id) { - case IdMap.getId("canceled"): - return Promise.resolve({ status: "canceled" }) - default: - return Promise.resolve({ id: IdMap.getId("order") }) - } - }, - save: jest.fn().mockImplementation((f) => f), - }) - - const orderService = new OrderService({ - manager: MockManager, - orderRepository: orderRepo, - eventBusService: eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully creates order", async () => { - await orderService.completeOrder(IdMap.getId("order")) - - expect(orderRepo.save).toHaveBeenCalledTimes(1) - expect(orderRepo.save).toHaveBeenCalledWith({ - id: IdMap.getId("order"), - status: "completed", - }) - }) - - it("fails when order is canceled", async () => { - await expect( - orderService.completeOrder(IdMap.getId("canceled")) - ).rejects.toThrow("A canceled order cannot be completed") - }) - }) - - describe("addShippingMethod", () => { - const orderRepo = MockRepository({ - findOneWithRelations: (rel, q) => { - switch (q.where.id) { - case IdMap.getId("canceled"): - return Promise.resolve({ status: "canceled" }) - default: - return Promise.resolve({ - id: IdMap.getId("order"), - shipping_methods: [ - { shipping_option: { profile_id: IdMap.getId("method1") } }, - ], - }) - } - }, - save: jest.fn().mockImplementation((f) => f), - }) - - const optionService = { - createShippingMethod: jest - .fn() - .mockImplementation((optionId, data, config) => - Promise.resolve({ shipping_option: { profile_id: optionId } }) - ), - deleteShippingMethods: jest - .fn() - .mockImplementation(() => Promise.resolve({})), - - withTransaction: function () { - return this - }, - } - - const orderService = new OrderService({ - manager: MockManager, - orderRepository: orderRepo, - eventBusService: eventBusService, - shippingOptionService: optionService, - totalsService, - taxProviderService: taxProviderServiceMock, - newTotalsService: newTotalsServiceMock, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully adds shipping method", async () => { - await orderService.addShippingMethod( - IdMap.getId("order"), - IdMap.getId("option"), - { some: "data" }, - {} - ) - - expect(optionService.createShippingMethod).toHaveBeenCalledTimes(1) - expect(optionService.createShippingMethod).toHaveBeenCalledWith( - IdMap.getId("option"), - { some: "data" }, - { - order: { - discount_total: 0, - gift_card_tax_total: 0, - gift_card_total: 0, - id: IdMap.getId("order"), - items: [], - item_tax_total: 0, - paid_total: 0, - raw_discount_total: 0, - refundable_amount: 0, - refunded_total: 0, - shipping_methods: [ - { - shipping_option: { - profile_id: IdMap.getId("method1"), - }, - }, - ], - shipping_total: 0, - shipping_tax_total: 0, - subtotal: 0, - tax_total: 0, - total: 0, - }, - } - ) - - expect(optionService.deleteShippingMethods).not.toHaveBeenCalled() - }) - - it("successfully removes shipping method if same option profile", async () => { - await orderService.addShippingMethod( - IdMap.getId("order"), - IdMap.getId("method1"), - { some: "data" } - ) - - expect(optionService.createShippingMethod).toHaveBeenCalledTimes(1) - expect(optionService.createShippingMethod).toHaveBeenCalledWith( - IdMap.getId("method1"), - { some: "data" }, - { - order: { - discount_total: 0, - gift_card_tax_total: 0, - gift_card_total: 0, - id: IdMap.getId("order"), - items: [], - item_tax_total: 0, - paid_total: 0, - raw_discount_total: 0, - refundable_amount: 0, - refunded_total: 0, - shipping_methods: [ - { - shipping_option: { - profile_id: IdMap.getId("method1"), - }, - }, - ], - shipping_total: 0, - shipping_tax_total: 0, - subtotal: 0, - tax_total: 0, - total: 0, - }, - } - ) - - expect(optionService.deleteShippingMethods).toHaveBeenCalledTimes(1) - expect(optionService.deleteShippingMethods).toHaveBeenCalledWith({ - shipping_option: { - profile_id: IdMap.getId("method1"), - }, - }) - }) - - it("fails if order is canceled", async () => { - await expect( - orderService.addShippingMethod( - IdMap.getId("canceled"), - IdMap.getId("option"), - { some: "data" } - ) - ).rejects.toThrow("A shipping method cannot be added to a canceled order") - }) - }) - - describe("createShipment", () => { - const partialOrder = { - items: [ - { - id: "item_1", - quantity: 2, - fulfilled_quantity: 0, - }, - { - id: "item_2", - quantity: 1, - fulfilled_quantity: 0, - }, - ], - } - - const order = { - items: [ - { - id: "item_1", - quantity: 2, - fulfilled_quantity: 0, - }, - ], - no_notification: true, - } - - const orderRepo = MockRepository({ - findOneWithRelations: (rel, q) => { - switch (q.where.id) { - case IdMap.getId("partial"): - return Promise.resolve(partialOrder) - case IdMap.getId("canceled"): - return Promise.resolve({ status: "canceled" }) - default: - return Promise.resolve(order) - } - }, - }) - - const lineItemService = { - update: jest.fn(), - withTransaction: function () { - return this - }, - } - - const fulfillmentService = { - retrieve: () => - Promise.resolve({ - order_id: IdMap.getId("test"), - no_notification: true, - }), - createShipment: jest - .fn() - .mockImplementation((shipmentId, tracking, meta) => { - return Promise.resolve({ - items: [ - { - item_id: "item_1", - quantity: 2, - }, - ], - }) - }), - withTransaction: function () { - return this - }, - } - - const orderService = new OrderService({ - manager: MockManager, - orderRepository: orderRepo, - totalsService, - newTotalsService: newTotalsServiceMock, - fulfillmentService, - lineItemService, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("calls order model functions", async () => { - await orderService.createShipment( - IdMap.getId("test"), - IdMap.getId("fulfillment"), - [{ tracking_number: "1234" }, { tracking_number: "2345" }], - {} - ) - - expect(fulfillmentService.createShipment).toHaveBeenCalledTimes(1) - expect(fulfillmentService.createShipment).toHaveBeenCalledWith( - IdMap.getId("fulfillment"), - [{ tracking_number: "1234" }, { tracking_number: "2345" }], - { metadata: undefined, no_notification: true } - ) - - expect(orderRepo.save).toHaveBeenCalledTimes(1) - expect(orderRepo.save).toHaveBeenCalledWith({ - ...order, - fulfillment_status: "shipped", - }) - }) - - it("fails when order is canceled", async () => { - await expect( - orderService.createShipment( - IdMap.getId( - "canceled", - IdMap.getId("fulfillment"), - [{ tracking_number: "1234" }], - {} - ) - ) - ).rejects.toThrow("A canceled order cannot be fulfilled as shipped") - }) - it.each([ - [true, true], - [false, false], - [undefined, true], - ])( - "emits correct no_notification option with '%s'", - async (input, expected) => { - await orderService.createShipment( - IdMap.getId("test"), - IdMap.getId("fulfillment"), - [{ tracking_number: "1234" }, { tracking_number: "2345" }], - { no_notification: input } - ) - - expect(eventBusService.emit).toHaveBeenCalledWith(expect.any(String), { - id: expect.any(String), - no_notification: expected, - }) - } - ) - }) - - describe("createRefund", () => { - beforeEach(async () => { - jest.clearAllMocks() - }) - - const orderRepo = MockRepository({ - findOneWithRelations: (rel, q) => { - switch (q.where.id) { - case IdMap.getId("cannot"): - return Promise.resolve({ - id: IdMap.getId("order"), - payments: [ - { - id: "payment", - }, - ], - total: 100, - refunded_total: 100, - }) - case IdMap.getId("canceled"): - return Promise.resolve({ - status: "canceled", - }) - default: - return Promise.resolve({ - id: IdMap.getId("order_123"), - payments: [ - { - id: "payment", - }, - ], - total: 100, - paid_total: 100, - refundable_amount: 100, - refunded_total: 0, - no_notification: true, - }) - } - }, - }) - - const paymentProviderService = { - refundPayment: jest - .fn() - .mockImplementation((p) => Promise.resolve({ id: "ref" })), - withTransaction: function () { - return this - }, - } - - const orderService = new OrderService({ - manager: MockManager, - orderRepository: orderRepo, - paymentProviderService, - totalsService, - newTotalsService: newTotalsServiceMock, - eventBusService, - }) - - it("success", async () => { - await orderService.createRefund( - IdMap.getId("order_123"), - 100, - "discount", - "note" - ) - - expect(paymentProviderService.refundPayment).toHaveBeenCalledTimes(1) - expect(paymentProviderService.refundPayment).toHaveBeenCalledWith( - [{ id: "payment" }], - 100, - "discount", - "note" - ) - }) - - it("fails when refund is off", async () => { - await expect( - orderService.createRefund( - IdMap.getId("cannot"), - 100, - "discount", - "note" - ) - ).rejects.toThrow("Cannot refund more than the original order amount") - }) - it("fails when order is canceled", async () => { - await expect( - orderService.createRefund( - IdMap.getId("canceled"), - 100, - "discount", - "note" - ) - ).rejects.toThrow("A canceled order cannot be refunded") - }) - - it.each([ - [false, false], - [undefined, true], - ])( - "emits correct no_notification option with '%s'", - async (input, expected) => { - await orderService.createRefund( - IdMap.getId("order_123"), - 100, - "discount", - "note", - { no_notification: input } - ) - - expect(eventBusService.emit).toHaveBeenCalledWith(expect.any(String), { - id: expect.any(String), - no_notification: expected, - refund_id: expect.any(String), - }) - } - ) - }) -}) diff --git a/packages/medusa/src/services/__tests__/payment-collection.ts b/packages/medusa/src/services/__tests__/payment-collection.ts deleted file mode 100644 index 38bfd816bc..0000000000 --- a/packages/medusa/src/services/__tests__/payment-collection.ts +++ /dev/null @@ -1,704 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { - PaymentCollection, - PaymentCollectionStatus, - PaymentCollectionType -} from "../../models" -import { PaymentCollectionsSessionsBatchInput } from "../../types/payment-collection" -import EventBusService from "../event-bus" -import { - CustomerService, - PaymentCollectionService, - PaymentProviderService -} from "../index" -import { CustomerServiceMock } from "../__mocks__/customer" -import { EventBusServiceMock } from "../__mocks__/event-bus" -import { - DefaultProviderMock, - PaymentProviderServiceMock -} from "../__mocks__/payment-provider" - -describe("PaymentCollectionService", () => { - afterEach(() => { - jest.clearAllMocks() - }) - - const paymentCollectionSample = { - id: IdMap.getId("payment-collection-id1"), - region_id: IdMap.getId("region1"), - region: { - payment_providers: [ - { - id: IdMap.getId("region1_provider1"), - }, - { - id: IdMap.getId("region1_provider2"), - }, - ], - }, - payment_sessions: [ - { - id: IdMap.getId("payCol_session1"), - provider_id: IdMap.getId("region1_provider1"), - amount: 100, - }, - ], - amount: 100, - created_at: new Date(), - metadata: { - pluginInfo: "xyz", - }, - status: PaymentCollectionStatus.NOT_PAID, - } - - const paymentCollectionWithSessions = { - id: IdMap.getId("payment-collection-session"), - region_id: IdMap.getId("region1"), - region: { - payment_providers: [ - { - id: IdMap.getId("region1_provider1"), - }, - ], - }, - payment_sessions: [ - { - id: IdMap.getId("payCol_session1"), - provider_id: IdMap.getId("region1_provider1"), - amount: 100, - }, - ], - amount: 100, - created_at: new Date(), - status: PaymentCollectionStatus.NOT_PAID, - } as PaymentCollection - - const paymentCollectionAuthorizedSample = { - id: IdMap.getId("payment-collection-id2"), - region_id: IdMap.getId("region1"), - amount: 35000, - status: PaymentCollectionStatus.AUTHORIZED, - region: { - payment_providers: [ - { - id: IdMap.getId("region1_provider1"), - }, - ], - }, - } - - const zeroSample = { - id: IdMap.getId("payment-collection-zero"), - region_id: IdMap.getId("region1"), - amount: 0, - status: PaymentCollectionStatus.NOT_PAID, - } - - const noSessionSample = { - id: IdMap.getId("payment-collection-zero"), - region_id: IdMap.getId("region1"), - amount: 10000, - status: PaymentCollectionStatus.NOT_PAID, - } - - const fullyAuthorizedSample = { - id: IdMap.getId("payment-collection-fully"), - region_id: IdMap.getId("region1"), - amount: 35000, - authorized_amount: 35000, - region: { - payment_providers: [ - { - id: IdMap.getId("region1_provider1"), - }, - ], - }, - payment_sessions: [ - { - id: IdMap.getId("payCol_session1"), - payment_authorized_at: Date.now(), - provider_id: IdMap.getId("region1_provider1"), - amount: 35000, - }, - ], - payments: [ - { - id: IdMap.getId("payment-123"), - amount: 35000, - }, - ], - status: PaymentCollectionStatus.AUTHORIZED, - } as unknown as PaymentCollection - - const partiallyAuthorizedSample = { - id: IdMap.getId("payment-collection-partial"), - region_id: IdMap.getId("region1"), - amount: 70000, - authorized_amount: 35000, - region: { - payment_providers: [ - { - id: IdMap.getId("region1_provider1"), - }, - ], - }, - payment_sessions: [ - { - id: IdMap.getId("payCol_session1"), - provider_id: IdMap.getId("region1_provider1"), - amount: 35000, - }, - { - id: IdMap.getId("payCol_session2"), - payment_authorized_at: Date.now(), - provider_id: IdMap.getId("region1_provider1"), - amount: 35000, - }, - ], - payments: [], - status: PaymentCollectionStatus.PARTIALLY_AUTHORIZED, - } - - const notAuthorizedSample = { - id: IdMap.getId("payment-collection-not-authorized"), - region_id: IdMap.getId("region1"), - amount: 70000, - region: { - payment_providers: [ - { - id: IdMap.getId("region1_provider1"), - }, - ], - }, - payment_sessions: [ - { - id: IdMap.getId("payCol_session1"), - provider_id: IdMap.getId("region1_provider1"), - amount: 35000, - }, - { - id: IdMap.getId("payCol_session2"), - provider_id: IdMap.getId("region1_provider1"), - amount: 35000, - }, - ], - payments: [], - status: PaymentCollectionStatus.PARTIALLY_AUTHORIZED, - } as unknown as PaymentCollection - - const paymentCollectionRepository = MockRepository({ - find: (query) => { - const map = { - [IdMap.getId("payment-collection-id1")]: paymentCollectionSample, - [IdMap.getId("payment-collection-id2")]: - paymentCollectionAuthorizedSample, - [IdMap.getId("payment-collection-session")]: - paymentCollectionWithSessions, - [IdMap.getId("payment-collection-zero")]: zeroSample, - [IdMap.getId("payment-collection-no-session")]: noSessionSample, - [IdMap.getId("payment-collection-fully")]: fullyAuthorizedSample, - [IdMap.getId("payment-collection-partial")]: partiallyAuthorizedSample, - [IdMap.getId("payment-collection-not-authorized")]: notAuthorizedSample, - } - - if (map[query?.where?.id]) { - return [{ ...map[query?.where?.id] }] - } - return - }, - create: (data) => { - return { - ...paymentCollectionSample, - ...data, - } - }, - save: (data) => { - return data - }, - }) - - paymentCollectionRepository.deleteMultiple = jest - .fn() - .mockImplementation(() => { - return Promise.resolve() - }) - - paymentCollectionRepository.getPaymentCollectionIdBySessionId = jest - .fn() - .mockImplementation(async () => { - return paymentCollectionWithSessions - }) - - const paymentCollectionService = new PaymentCollectionService({ - manager: MockManager, - paymentCollectionRepository, - eventBusService: EventBusServiceMock as unknown as EventBusService, - paymentProviderService: - PaymentProviderServiceMock as unknown as PaymentProviderService, - customerService: CustomerServiceMock as unknown as CustomerService, - }) - - it("should retrieve a payment collection", async () => { - await paymentCollectionService.retrieve( - IdMap.getId("payment-collection-id1") - ) - expect(paymentCollectionRepository.find).toHaveBeenCalledTimes(1) - expect(paymentCollectionRepository.find).toHaveBeenCalledWith({ - where: { id: IdMap.getId("payment-collection-id1") }, - }) - }) - - it("should throw error if payment collection is not found", async () => { - const payCol = paymentCollectionService.retrieve( - IdMap.getId("payment-collection-non-existing-id") - ) - - expect(payCol).rejects.toThrow(Error) - expect(paymentCollectionRepository.find).toBeCalledTimes(1) - }) - - it("should create a payment collection", async () => { - const entity = await paymentCollectionService.create({ - region_id: IdMap.getId("region2"), - type: PaymentCollectionType.ORDER_EDIT, - currency_code: "USD", - amount: 190, - created_by: IdMap.getId("user-id"), - description: "some description", - metadata: { - abc: 123, - }, - }) - expect(paymentCollectionRepository.save).toHaveBeenCalledTimes(1) - expect(paymentCollectionRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - id: IdMap.getId("payment-collection-id1"), - region_id: IdMap.getId("region2"), - amount: 190, - created_by: IdMap.getId("user-id"), - status: PaymentCollectionStatus.NOT_PAID, - description: "some description", - metadata: { - abc: 123, - }, - }) - ) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - PaymentCollectionService.Events.CREATED, - entity - ) - }) - - it("should update a payment collection with the right arguments", async () => { - const submittedChanges = { - description: "updated description", - metadata: { - extra: 123, - arr: ["a", "b", "c"], - }, - } - const internalChanges = { - ...submittedChanges, - } - internalChanges.metadata = { - ...internalChanges.metadata, - ...{ - pluginInfo: "xyz", - }, - } - - const entity = await paymentCollectionService.update( - IdMap.getId("payment-collection-id1"), - submittedChanges - ) - expect(paymentCollectionRepository.save).toHaveBeenCalledTimes(1) - expect(paymentCollectionRepository.save).toHaveBeenCalledWith( - expect.objectContaining(internalChanges) - ) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - PaymentCollectionService.Events.UPDATED, - entity - ) - }) - - it("should throw error to update a non-existing payment collection", async () => { - const submittedChanges = { - description: "updated description", - metadata: { - extra: 123, - arr: ["a", "b", "c"], - }, - } - - const payCol = paymentCollectionService.update( - IdMap.getId("payment-collection-non-existing"), - submittedChanges - ) - - expect(payCol).rejects.toThrow(Error) - expect(paymentCollectionRepository.save).toBeCalledTimes(0) - expect(EventBusServiceMock.emit).toBeCalledTimes(0) - }) - - it("should delete a payment collection", async () => { - const entity = await paymentCollectionService.delete( - IdMap.getId("payment-collection-id1") - ) - expect(paymentCollectionRepository.remove).toHaveBeenCalledTimes(1) - expect(paymentCollectionRepository.remove).toHaveBeenCalledWith( - expect.objectContaining({ - id: IdMap.getId("payment-collection-id1"), - region_id: IdMap.getId("region1"), - amount: 100, - }) - ) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - PaymentCollectionService.Events.DELETED, - entity - ) - }) - - it("should ignore to delete a non-existing payment collection", async () => { - const entity = await paymentCollectionService.delete( - IdMap.getId("payment-collection-non-existing") - ) - expect(paymentCollectionRepository.remove).toHaveBeenCalledTimes(0) - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(0) - expect(entity).toBe(undefined) - }) - - it("should throw and error when trying to delete an initialized payment collection", async () => { - const entity = paymentCollectionService.delete( - IdMap.getId("payment-collection-id2") - ) - expect(paymentCollectionRepository.remove).toHaveBeenCalledTimes(0) - - expect(entity).rejects.toThrow(Error) - }) - - describe("Manage Single Payment Session", () => { - afterEach(() => { - jest.clearAllMocks() - }) - - it("should throw error if payment collection doesn't have the correct status", async () => { - const ret = paymentCollectionService.setPaymentSession( - IdMap.getId("payment-collection-id2"), - { - provider_id: IdMap.getId("region1_provider1"), - }, - "customer1" - ) - - expect(ret).rejects.toThrowError( - new Error( - `Cannot set payment sessions for a payment collection with status ${PaymentCollectionStatus.AUTHORIZED}` - ) - ) - expect(PaymentProviderServiceMock.createSession).toBeCalledTimes(0) - }) - - it("should ignore session if provider doesn't belong to the region", async () => { - const multiRet = paymentCollectionService.setPaymentSession( - IdMap.getId("payment-collection-id1"), - { - provider_id: IdMap.getId("region1_invalid_provider"), - }, - "customer1" - ) - - expect(multiRet).rejects.toThrow(`Payment provider not found`) - expect(PaymentProviderServiceMock.createSession).toBeCalledTimes(0) - }) - - it("should add a new session", async () => { - await paymentCollectionService.setPaymentSession( - IdMap.getId("payment-collection-id1"), - { - provider_id: IdMap.getId("region1_provider2"), - }, - "lebron" - ) - - expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes(1) - expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(paymentCollectionRepository.save).toHaveBeenCalledTimes(1) - }) - - it("should update an existing one", async () => { - await paymentCollectionService.setPaymentSession( - IdMap.getId("payment-collection-id1"), - { - provider_id: IdMap.getId("region1_provider1"), - }, - "lebron" - ) - - expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes(0) - expect(PaymentProviderServiceMock.updateSession).toHaveBeenCalledTimes(1) - expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(paymentCollectionRepository.save).toHaveBeenCalledTimes(1) - }) - - it("should add a new session and delete existing one", async () => { - const inp: PaymentCollectionsSessionsBatchInput[] = [ - { - amount: 100, - provider_id: IdMap.getId("region1_provider1"), - }, - ] - await paymentCollectionService.setPaymentSessionsBatch( - IdMap.getId("payment-collection-session"), - inp, - IdMap.getId("lebron") - ) - - expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes(1) - expect(PaymentProviderServiceMock.updateSession).toHaveBeenCalledTimes(0) - expect(paymentCollectionRepository.delete).toHaveBeenCalledTimes(1) - - expect(paymentCollectionRepository.save).toHaveBeenCalledTimes(1) - }) - }) - - describe("Manage Multiple Payment Sessions", () => { - afterEach(() => { - jest.clearAllMocks() - }) - - it("should throw error if payment collection doesn't have the correct status", async () => { - const inp: PaymentCollectionsSessionsBatchInput[] = [ - { - amount: 100, - provider_id: IdMap.getId("region1_provider1"), - }, - ] - const ret = paymentCollectionService.setPaymentSessionsBatch( - IdMap.getId("payment-collection-id2"), - inp, - "customer1" - ) - - expect(ret).rejects.toThrowError( - new Error( - `Cannot set payment sessions for a payment collection with status ${PaymentCollectionStatus.AUTHORIZED}` - ) - ) - - expect(PaymentProviderServiceMock.createSession).toBeCalledTimes(0) - }) - - it("should throw error if amount is different than requested", async () => { - const inp: PaymentCollectionsSessionsBatchInput[] = [ - { - amount: 101, - provider_id: IdMap.getId("region1_provider1"), - }, - ] - - const ret = paymentCollectionService.setPaymentSessionsBatch( - IdMap.getId("payment-collection-id1"), - inp, - "customer1" - ) - - expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes(0) - expect(ret).rejects.toThrow( - `The sum of sessions is not equal to 100 on Payment Collection` - ) - - const multInp: PaymentCollectionsSessionsBatchInput[] = [ - { - amount: 51, - provider_id: IdMap.getId("region1_provider1"), - }, - { - amount: 50, - provider_id: IdMap.getId("region1_provider2"), - }, - ] - const multiRet = paymentCollectionService.setPaymentSessionsBatch( - IdMap.getId("payment-collection-id1"), - multInp, - "customer1" - ) - - expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes(0) - expect(multiRet).rejects.toThrow( - `The sum of sessions is not equal to 100 on Payment Collection` - ) - }) - - it("should ignore sessions where provider doesn't belong to the region", async () => { - const multInp: PaymentCollectionsSessionsBatchInput[] = [ - { - amount: 50, - provider_id: IdMap.getId("region1_provider1"), - }, - { - amount: 50, - provider_id: IdMap.getId("region1_invalid_provider"), - }, - ] - const multiRet = paymentCollectionService.setPaymentSessionsBatch( - IdMap.getId("payment-collection-id1"), - multInp, - "customer1" - ) - - expect(multiRet).rejects.toThrow( - `The sum of sessions is not equal to 100 on Payment Collection` - ) - expect(PaymentProviderServiceMock.createSession).toBeCalledTimes(0) - }) - - it("should add a new session and update existing one", async () => { - const inp: PaymentCollectionsSessionsBatchInput[] = [ - { - session_id: IdMap.getId("payCol_session1"), - amount: 50, - provider_id: IdMap.getId("region1_provider1"), - }, - { - amount: 50, - provider_id: IdMap.getId("region1_provider1"), - }, - ] - await paymentCollectionService.setPaymentSessionsBatch( - IdMap.getId("payment-collection-session"), - inp, - "lebron" - ) - - expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes(1) - expect(PaymentProviderServiceMock.updateSession).toHaveBeenCalledTimes(1) - expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1) - expect(paymentCollectionRepository.save).toHaveBeenCalledTimes(1) - }) - - it("should add a new session and delete existing one", async () => { - const inp: PaymentCollectionsSessionsBatchInput[] = [ - { - amount: 100, - provider_id: IdMap.getId("region1_provider1"), - }, - ] - await paymentCollectionService.setPaymentSessionsBatch( - IdMap.getId("payment-collection-session"), - inp, - IdMap.getId("lebron") - ) - - expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes(1) - expect(PaymentProviderServiceMock.updateSession).toHaveBeenCalledTimes(0) - expect(paymentCollectionRepository.delete).toHaveBeenCalledTimes(1) - - expect(paymentCollectionRepository.save).toHaveBeenCalledTimes(1) - }) - - it("should refresh a payment session", async () => { - await paymentCollectionService.refreshPaymentSession( - IdMap.getId("payment-collection-session"), - IdMap.getId("payCol_session1"), - "customer1" - ) - - expect(PaymentProviderServiceMock.refreshSession).toHaveBeenCalledTimes(1) - expect(DefaultProviderMock.deletePayment).toHaveBeenCalledTimes(1) - expect(PaymentProviderServiceMock.createSession).toHaveBeenCalledTimes(1) - }) - - it("should throw to refresh a payment session that doesn't exist", async () => { - const sess = paymentCollectionService.refreshPaymentSession( - IdMap.getId("payment-collection-session"), - IdMap.getId("payCol_session-not-found"), - "customer1" - ) - - expect(sess).rejects.toThrow( - `Session with id ${IdMap.getId( - "payCol_session-not-found" - )} was not found` - ) - expect(PaymentProviderServiceMock.refreshSession).toBeCalledTimes(0) - expect(DefaultProviderMock.deletePayment).toBeCalledTimes(0) - expect(PaymentProviderServiceMock.createSession).toBeCalledTimes(0) - }) - }) - - describe("Authorize Payments", () => { - afterEach(() => { - jest.clearAllMocks() - }) - - it("should mark as authorized if amount is 0", async () => { - const auth = await paymentCollectionService.authorizePaymentSessions( - IdMap.getId("payment-collection-zero"), - [] - ) - - expect(PaymentProviderServiceMock.authorizePayment).toHaveBeenCalledTimes( - 0 - ) - expect(auth.status).toBe(PaymentCollectionStatus.AUTHORIZED) - }) - - it("should reject payment collection without payment sessions", async () => { - const ret = paymentCollectionService.authorizePaymentSessions( - IdMap.getId("payment-collection-no-session"), - [] - ) - - expect(ret).rejects.toThrowError( - new Error( - "You cannot complete a Payment Collection without a payment session." - ) - ) - }) - - it("should call authorizePayments for all sessions", async () => { - await paymentCollectionService.authorizePaymentSessions( - IdMap.getId("payment-collection-not-authorized"), - [IdMap.getId("payCol_session1"), IdMap.getId("payCol_session2")] - ) - - expect(PaymentProviderServiceMock.authorizePayment).toHaveBeenCalledTimes( - 2 - ) - expect(PaymentProviderServiceMock.createPayment).toHaveBeenCalledTimes(2) - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - }) - - it("should skip authorized sessions - partially authorized", async () => { - await paymentCollectionService.authorizePaymentSessions( - IdMap.getId("payment-collection-partial"), - [IdMap.getId("payCol_session1"), IdMap.getId("payCol_session2")] - ) - - expect(PaymentProviderServiceMock.authorizePayment).toHaveBeenCalledTimes( - 1 - ) - expect(PaymentProviderServiceMock.createPayment).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - }) - - it("should skip authorized sessions - fully authorized", async () => { - await paymentCollectionService.authorizePaymentSessions( - IdMap.getId("payment-collection-fully"), - [IdMap.getId("payCol_session1"), IdMap.getId("payCol_session2")] - ) - - expect(PaymentProviderServiceMock.authorizePayment).toHaveBeenCalledTimes( - 0 - ) - expect(PaymentProviderServiceMock.createPayment).toHaveBeenCalledTimes(0) - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(0) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/payment-provider.ts b/packages/medusa/src/services/__tests__/payment-provider.ts deleted file mode 100644 index a08c915842..0000000000 --- a/packages/medusa/src/services/__tests__/payment-provider.ts +++ /dev/null @@ -1,1043 +0,0 @@ -import { asValue, createContainer } from "awilix" -import { MockRepository } from "medusa-test-utils" -import { - defaultContainer, - defaultPaymentSessionInputData, - PaymentProcessor, -} from "../__fixtures__/payment-provider" -import { testPayServiceMock } from "../__mocks__/test-pay" -import { EOL } from "os" -import { PaymentSessionStatus, RefundReason } from "../../models" - -describe(`PaymentProviderService`, () => { - const container = createContainer({}, defaultContainer) - container.register("pp_default_provider", asValue(testPayServiceMock)) - container - .register( - "paymentSessionRepository", - asValue( - MockRepository({ - findOne: () => - Promise.resolve({ - id: "session", - provider_id: "default_provider", - data: { - id: "1234", - }, - }), - }) - ) - ) - .register( - "paymentRepository", - asValue( - MockRepository({ - findOne: () => - Promise.resolve({ - id: "pay_jadazdjk", - provider_id: "default_provider", - data: { - id: "1234", - }, - }), - find: () => - Promise.resolve([ - { - id: "pay_jadazdjk", - provider_id: "default_provider", - data: { - id: "1234", - }, - captured_at: new Date(), - amount: 100, - amount_refunded: 0, - }, - ]), - }) - ) - ) - - const providerService = container.resolve("paymentProviderService") - - afterEach(() => { - jest.clearAllMocks() - }) - - it("successfully retrieves payment provider", () => { - const provider = providerService.retrieveProvider("default_provider") - expect(provider.identifier).toEqual("test-pay") - }) - - it("successfully creates session", async () => { - await providerService.createSession("default_provider", { - object: "cart", - region: { - currency_code: "usd", - }, - total: 100, - }) - - expect(testPayServiceMock.createPayment).toBeCalledTimes(1) - expect(testPayServiceMock.createPayment).toBeCalledWith({ - amount: 100, - object: "cart", - total: 100, - region: { - currency_code: "usd", - }, - cart: { - context: undefined, - email: undefined, - id: undefined, - shipping_address: undefined, - shipping_methods: undefined, - }, - currency_code: "usd", - }) - }) - - it("successfully update session", async () => { - await providerService.updateSession( - { - id: "session", - provider_id: "default_provider", - data: { - id: "1234", - }, - }, - { - object: "cart", - total: 100, - } - ) - - expect(testPayServiceMock.updatePayment).toBeCalledTimes(1) - expect(testPayServiceMock.updatePayment).toBeCalledWith( - { id: "1234" }, - { - amount: 100, - object: "cart", - total: 100, - cart: { - context: undefined, - email: undefined, - id: undefined, - shipping_address: undefined, - shipping_methods: undefined, - }, - } - ) - }) - - it("successfully refresh session", async () => { - await providerService.refreshSession( - { - id: "session", - provider_id: "default_provider", - data: { - id: "1234", - }, - }, - { - provider_id: "default_provider", - amount: 100, - currency_code: "usd", - cart: { - id: "cart-test", - }, - } - ) - - expect(testPayServiceMock.deletePayment).toBeCalledTimes(1) - expect(testPayServiceMock.createPayment).toBeCalledTimes(1) - }) - - it("successfully delete session", async () => { - await providerService.deleteSession({ - id: "session", - provider_id: "default_provider", - data: { - id: "1234", - }, - }) - - expect(testPayServiceMock.deletePayment).toBeCalledTimes(1) - }) - - it("successfully delete session", async () => { - await providerService.deleteSession({ - id: "session", - provider_id: "default_provider", - data: { - id: "1234", - }, - }) - - expect(testPayServiceMock.deletePayment).toBeCalledTimes(1) - }) - - it("successfully authorize payment", async () => { - await providerService.authorizePayment( - { - id: "session", - provider_id: "default_provider", - data: { - id: "1234", - }, - }, - {} - ) - - expect(testPayServiceMock.authorizePayment).toBeCalledTimes(1) - }) - - it("successfully update session data", async () => { - await providerService.updateSessionData( - { - id: "session", - provider_id: "default_provider", - data: { - id: "1234", - }, - }, - {} - ) - - expect(testPayServiceMock.updatePaymentData).toBeCalledTimes(1) - }) - - it("successfully cancel payment", async () => { - await providerService.cancelPayment({ - id: "pay_jadazdjk", - }) - expect(testPayServiceMock.cancelPayment).toBeCalledTimes(1) - }) - - it("successfully capture payment", async () => { - await providerService.capturePayment({ - id: "pay_jadazdjk", - }) - expect(testPayServiceMock.capturePayment).toBeCalledTimes(1) - }) - - it("successfully refund payment", async () => { - await providerService.refundPayment( - [ - { - id: "pay_jadazdjk", - }, - ], - 50 - ) - expect(testPayServiceMock.refundPayment).toBeCalledTimes(1) - }) -}) - -describe("PaymentProviderService using AbstractPaymentProcessor", () => { - const paymentProcessorResolutionKey = "pp_payment_processor" - const paymentServiceResolutionKey = "paymentProviderService" - const paymentProviderId = "payment_processor" - - describe("createSession", () => { - const container = createContainer({}, defaultContainer) - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.initiatePayment = jest - .fn() - .mockReturnValue(Promise.resolve({ session_data: {} })) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - it("successfully creates session", async () => { - await providerService.createSession(defaultPaymentSessionInputData) - - const provider = container.resolve(paymentProcessorResolutionKey) - - expect(provider.initiatePayment).toBeCalledTimes(1) - expect(provider.initiatePayment).toBeCalledWith({ - billing_address: defaultPaymentSessionInputData.cart.billing_address, - email: defaultPaymentSessionInputData.cart.email, - currency_code: defaultPaymentSessionInputData.currency_code, - amount: defaultPaymentSessionInputData.amount, - resource_id: "cart-test", - customer: undefined, - context: {}, - paymentSessionData: {}, - }) - }) - - it("throw an error using the provider error response", async () => { - const errResponse = { - error: "Error", - code: 400, - detail: "Error details", - } - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.initiatePayment = jest - .fn() - .mockReturnValue(Promise.resolve(errResponse)) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - const err = await providerService - .createSession(defaultPaymentSessionInputData) - .catch((e) => e) - - expect(err.message).toBe( - `${errResponse.error}:${EOL}${errResponse.detail}` - ) - }) - }) - - describe("refreshSession", () => { - const sessionId = "test-session" - const externalId = "external-id" - const paymentSessionData = { id: externalId } - - const container = createContainer({}, defaultContainer) - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.deletePayment = jest - .fn() - .mockReturnValue(Promise.resolve()) - mockPaymentProcessor.initiatePayment = jest - .fn() - .mockReturnValue(Promise.resolve({ session_data: paymentSessionData })) - - container - .register(paymentProcessorResolutionKey, asValue(mockPaymentProcessor)) - .register( - "paymentSessionRepository", - asValue( - MockRepository({ - findOne: jest - .fn() - .mockImplementation(async () => ({ data: paymentSessionData })), - }) - ) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - it("successfully refresh a session", async () => { - await providerService.refreshSession( - { - id: sessionId, - data: paymentSessionData, - provider_id: paymentProviderId, - }, - defaultPaymentSessionInputData - ) - - const provider = container.resolve(paymentProcessorResolutionKey) - - expect(provider.deletePayment).toBeCalledTimes(1) - expect(provider.deletePayment).toBeCalledWith({ id: externalId }) - - expect(provider.initiatePayment).toBeCalledTimes(1) - expect(provider.initiatePayment).toBeCalledWith({ - billing_address: defaultPaymentSessionInputData.cart.billing_address, - email: defaultPaymentSessionInputData.cart.email, - currency_code: defaultPaymentSessionInputData.currency_code, - amount: defaultPaymentSessionInputData.amount, - resource_id: "cart-test", - customer: undefined, - context: {}, - paymentSessionData: {}, - }) - }) - - it("throw an error using the provider error response", async () => { - const errResponse = { - error: "Error", - code: 400, - detail: "Error details", - } - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.deletePayment = jest - .fn() - .mockReturnValue(Promise.resolve(errResponse)) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - const err = await providerService - .refreshSession( - { - id: sessionId, - data: paymentSessionData, - provider_id: paymentProviderId, - }, - defaultPaymentSessionInputData - ) - .catch((e) => e) - - expect(err.message).toBe( - `${errResponse.error}:${EOL}${errResponse.detail}` - ) - }) - }) - - describe("updateSession", () => { - const sessionId = "test-session" - const externalId = "external-id" - const paymentSessionData = { id: externalId } - - const container = createContainer({}, defaultContainer) - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.updatePayment = jest - .fn() - .mockReturnValue(Promise.resolve({ session_data: paymentSessionData })) - - container - .register(paymentProcessorResolutionKey, asValue(mockPaymentProcessor)) - .register( - "paymentSessionRepository", - asValue( - MockRepository({ - findOne: jest - .fn() - .mockImplementation(async () => ({ data: paymentSessionData })), - }) - ) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - it("successfully update a session", async () => { - await providerService.updateSession( - { - id: sessionId, - data: paymentSessionData, - provider_id: paymentProviderId, - }, - defaultPaymentSessionInputData - ) - - const provider = container.resolve(paymentProcessorResolutionKey) - - expect(provider.updatePayment).toBeCalledTimes(1) - expect(provider.updatePayment).toBeCalledWith({ - billing_address: defaultPaymentSessionInputData.cart.billing_address, - email: defaultPaymentSessionInputData.cart.email, - currency_code: defaultPaymentSessionInputData.currency_code, - amount: defaultPaymentSessionInputData.amount, - resource_id: "cart-test", - customer: undefined, - context: {}, - paymentSessionData, - }) - }) - - it("throw an error using the provider error response", async () => { - const errResponse = { - error: "Error", - code: 400, - detail: "Error details", - } - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.updatePayment = jest - .fn() - .mockReturnValue(Promise.resolve(errResponse)) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - const err = await providerService - .updateSession( - { - id: sessionId, - data: paymentSessionData, - provider_id: paymentProviderId, - }, - defaultPaymentSessionInputData - ) - .catch((e) => e) - - expect(err.message).toBe( - `${errResponse.error}:${EOL}${errResponse.detail}` - ) - }) - }) - - describe("deleteSession", () => { - const sessionId = "test-session" - const externalId = "external-id" - const paymentSessionData = { id: externalId } - - const container = createContainer({}, defaultContainer) - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.deletePayment = jest.fn() - - container - .register(paymentProcessorResolutionKey, asValue(mockPaymentProcessor)) - .register( - "paymentSessionRepository", - asValue( - MockRepository({ - findOne: jest - .fn() - .mockImplementation(async () => ({ data: paymentSessionData })), - }) - ) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - it("successfully delete a session", async () => { - await providerService.deleteSession({ - id: sessionId, - data: paymentSessionData, - provider_id: paymentProviderId, - }) - - const provider = container.resolve(paymentProcessorResolutionKey) - - expect(provider.deletePayment).toBeCalledTimes(1) - expect(provider.deletePayment).toBeCalledWith(paymentSessionData) - }) - - it("throw an error using the provider error response", async () => { - const errResponse = { - error: "Error", - code: 400, - detail: "Error details", - } - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.deletePayment = jest - .fn() - .mockReturnValue(Promise.resolve(errResponse)) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - const err = await providerService - .deleteSession({ - id: sessionId, - data: paymentSessionData, - provider_id: paymentProviderId, - }) - .catch((e) => e) - - expect(err.message).toBe( - `${errResponse.error}:${EOL}${errResponse.detail}` - ) - }) - }) - - describe("createPayment", () => { - const sessionId = "test-session" - const externalId = "external-id" - const paymentInput = { - cart_id: defaultPaymentSessionInputData.cart.id, - amount: defaultPaymentSessionInputData.amount, - currency_code: defaultPaymentSessionInputData.currency_code, - provider_id: defaultPaymentSessionInputData.provider_id, - payment_session: { - id: sessionId, - data: { id: externalId }, - }, - } - - const container = createContainer({}, defaultContainer) - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.retrievePayment = jest - .fn() - .mockReturnValue(Promise.resolve({})) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - it("successfully create a payment", async () => { - await providerService.createPayment(paymentInput) - - const provider = container.resolve(paymentProcessorResolutionKey) - - expect(provider.retrievePayment).toBeCalledTimes(1) - expect(provider.retrievePayment).toBeCalledWith( - paymentInput.payment_session.data - ) - }) - - it("throw an error using the provider error response", async () => { - const errResponse = { - error: "Error", - code: 400, - detail: "Error details", - } - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.retrievePayment = jest - .fn() - .mockReturnValue(Promise.resolve(errResponse)) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - const err = await providerService - .createPayment(paymentInput) - .catch((e) => e) - - expect(err.message).toBe( - `${errResponse.error}:${EOL}${errResponse.detail}` - ) - }) - }) - - describe("authorizePayment", () => { - const externalId = "external-id" - const paymentSession = { - id: "test-session", - data: { id: externalId }, - provider_id: paymentProviderId, - } - const context = { ip: "0.0.0.0" } - - const container = createContainer({}, defaultContainer) - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.authorizePayment = jest - .fn() - .mockReturnValue(Promise.resolve({})) - - container - .register(paymentProcessorResolutionKey, asValue(mockPaymentProcessor)) - .register( - "paymentSessionRepository", - asValue( - MockRepository({ - findOne: jest.fn().mockImplementation(async () => ({ data: {} })), - }) - ) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - it("successfully authorize a payment", async () => { - await providerService.authorizePayment(paymentSession, context) - - const provider = container.resolve(paymentProcessorResolutionKey) - - expect(provider.authorizePayment).toBeCalledTimes(1) - expect(provider.authorizePayment).toBeCalledWith( - paymentSession.data, - context - ) - }) - - it("throw an error using the provider error response", async () => { - const errResponse = { - error: "Error", - code: 400, - detail: "Error details", - } - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.authorizePayment = jest - .fn() - .mockReturnValue(Promise.resolve(errResponse)) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - const err = await providerService - .authorizePayment(paymentSession, context) - .catch((e) => e) - - expect(err.message).toBe( - `${errResponse.error}:${EOL}${errResponse.detail}` - ) - }) - }) - - describe("cancelPayment", () => { - const externalId = "external-id" - const payment = { - id: "payment-id", - data: { id: externalId }, - provider_id: paymentProviderId, - } - - const container = createContainer({}, defaultContainer) - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.cancelPayment = jest - .fn() - .mockReturnValue(Promise.resolve()) - - container - .register(paymentProcessorResolutionKey, asValue(mockPaymentProcessor)) - .register( - "paymentRepository", - asValue( - MockRepository({ - findOne: jest.fn().mockImplementation(async () => payment), - }) - ) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - it("successfully cancel a payment", async () => { - await providerService.cancelPayment(payment) - - const provider = container.resolve(paymentProcessorResolutionKey) - - expect(provider.cancelPayment).toBeCalledTimes(1) - expect(provider.cancelPayment).toBeCalledWith(payment.data) - }) - - it("throw an error using the provider error response", async () => { - const errResponse = { - error: "Error", - code: 400, - detail: "Error details", - } - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.cancelPayment = jest - .fn() - .mockReturnValue(Promise.resolve(errResponse)) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - const err = await providerService.cancelPayment(payment).catch((e) => e) - - expect(err.message).toBe( - `${errResponse.error}:${EOL}${errResponse.detail}` - ) - }) - }) - - describe("getStatus", () => { - const payment = { - data: { id: "id" }, - provider_id: paymentProviderId, - } - - const container = createContainer({}, defaultContainer) - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.getPaymentStatus = jest - .fn() - .mockReturnValue(Promise.resolve(PaymentSessionStatus.PENDING)) - - container - .register(paymentProcessorResolutionKey, asValue(mockPaymentProcessor)) - .register( - "paymentRepository", - asValue( - MockRepository({ - findOne: jest.fn().mockImplementation(async () => payment), - }) - ) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - it("successfully cancel a payment", async () => { - await providerService.getStatus(payment) - - const provider = container.resolve(paymentProcessorResolutionKey) - - expect(provider.getPaymentStatus).toBeCalledTimes(1) - expect(provider.getPaymentStatus).toBeCalledWith(payment.data) - }) - }) - - describe("capturePayment", () => { - const externalId = "external-id" - const payment = { - data: { id: externalId }, - id: "payment-id", - provider_id: paymentProviderId, - } - - const container = createContainer({}, defaultContainer) - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.capturePayment = jest - .fn() - .mockReturnValue(Promise.resolve(payment.data)) - - container - .register(paymentProcessorResolutionKey, asValue(mockPaymentProcessor)) - .register( - "paymentRepository", - asValue( - MockRepository({ - findOne: jest.fn().mockImplementation(async () => payment), - }) - ) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - it("successfully capture a payment", async () => { - await providerService.capturePayment(payment) - - const provider = container.resolve(paymentProcessorResolutionKey) - - expect(provider.capturePayment).toBeCalledTimes(1) - expect(provider.capturePayment).toBeCalledWith(payment.data) - }) - - it("throw an error using the provider error response", async () => { - const errResponse = { - error: "Error", - code: 400, - detail: "Error details", - } - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.capturePayment = jest - .fn() - .mockReturnValue(Promise.resolve(errResponse)) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - const err = await providerService.capturePayment(payment).catch((e) => e) - - expect(err.message).toBe( - `${errResponse.error}:${EOL}${errResponse.detail}` - ) - }) - }) - - describe("refundPayment", () => { - afterEach(() => { - jest.clearAllMocks() - }) - - const payments = [ - { - id: "p1", - captured_at: new Date(), - data: { id: "id1" }, - amount: 1000, - amount_refunded: 0, - provider_id: paymentProviderId, - }, - { - id: "p2", - captured_at: new Date(), - data: { id: "id2" }, - amount: 1000, - amount_refunded: 0, - provider_id: paymentProviderId, - }, - { - id: "p3", - captured_at: new Date(), - data: { id: "id3" }, - amount: 1000, - amount_refunded: 1000, // already fully refunded - provider_id: paymentProviderId, - }, - ] - - const container = createContainer({}, defaultContainer) - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.refundPayment = jest - .fn() - .mockImplementation(async (data) => data) - - container - .register(paymentProcessorResolutionKey, asValue(mockPaymentProcessor)) - .register( - "paymentRepository", - asValue( - MockRepository({ - find: jest.fn().mockImplementation(async () => payments), - }) - ) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - const paymentRepo = container.resolve("paymentRepository") - - it("successfully refund the payments", async () => { - await providerService.refundPayment( - payments, - 1500, - RefundReason.OTHER, - "note" - ) - - const provider = container.resolve(paymentProcessorResolutionKey) - - expect(provider.refundPayment).toBeCalledTimes(2) - expect(provider.refundPayment).toHaveBeenNthCalledWith( - 1, - payments[0].data, - 1000 - ) - expect(provider.refundPayment).toHaveBeenNthCalledWith( - 2, - payments[1].data, - 500 - ) - - expect(paymentRepo.save).toBeCalledTimes(2) - expect(paymentRepo.save).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ amount_refunded: 1000 }) - ) - expect(paymentRepo.save).toHaveBeenNthCalledWith( - 2, - expect.objectContaining({ amount_refunded: 500 }) - ) - }) - - it("throw an error using the provider error response", async () => { - const errResponse = { - error: "Error", - code: 400, - detail: "Error details", - } - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.refundPayment = jest - .fn() - .mockReturnValue(Promise.resolve(errResponse)) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - const err = await providerService.refundPayment(payments).catch((e) => e) - - expect(err.message).toBe( - `${errResponse.error}:${EOL}${errResponse.detail}` - ) - }) - }) - - describe("refundFromPayment", () => { - const payment = { - id: "p1", - captured_at: new Date(), - data: { id: "id1" }, - amount: 1000, - amount_refunded: 0, - provider_id: paymentProviderId, - } - - const container = createContainer({}, defaultContainer) - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.refundPayment = jest - .fn() - .mockImplementation(async (data) => data) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - const paymentRepo = container.resolve("paymentRepository") - - it("successfully refund the payments", async () => { - await providerService.refundFromPayment( - payment, - 500, - RefundReason.OTHER, - "note" - ) - - const provider = container.resolve(paymentProcessorResolutionKey) - - expect(provider.refundPayment).toBeCalledTimes(1) - expect(provider.refundPayment).toBeCalledWith(payment.data, 500) - - expect(paymentRepo.save).toBeCalledTimes(1) - expect(paymentRepo.save).toBeCalledWith( - expect.objectContaining({ amount_refunded: 500 }) - ) - }) - - it("throw an error using the provider error response", async () => { - const errResponse = { - error: "Error", - code: 400, - detail: "Error details", - } - - const mockPaymentProcessor = new PaymentProcessor(container) - mockPaymentProcessor.refundPayment = jest - .fn() - .mockReturnValue(Promise.resolve(errResponse)) - - container.register( - paymentProcessorResolutionKey, - asValue(mockPaymentProcessor) - ) - - const providerService = container.resolve(paymentServiceResolutionKey) - - const err = await providerService - .refundFromPayment(payment) - .catch((e) => e) - - expect(err.message).toBe( - `${errResponse.error}:${EOL}${errResponse.detail}` - ) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/price-list.js b/packages/medusa/src/services/__tests__/price-list.js deleted file mode 100644 index 752f5520de..0000000000 --- a/packages/medusa/src/services/__tests__/price-list.js +++ /dev/null @@ -1,194 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { MoneyAmountRepository } from "../../repositories/money-amount" -import { FlagRouter } from "@medusajs/utils" -import PriceListService from "../price-list" -import { RegionServiceMock } from "../__mocks__/region" - -const priceListRepository = MockRepository({ - findOne: (q) => { - if (q === IdMap.getId("batman")) { - return Promise.resolve(undefined) - } - return Promise.resolve({ id: IdMap.getId("ironman") }) - }, - create: (data) => { - return Promise.resolve({ id: IdMap.getId("ironman"), ...data }) - }, - save: (data) => Promise.resolve(data), -}) - -const customerGroupService = { - retrieve: jest.fn((id) => { - if (id === IdMap.getId("group")) { - return Promise.resolve({ id: IdMap.getId("group") }) - } - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `CustomerGroup with id ${id} was not found` - ) - }), -} - -describe("PriceListService", () => { - const moneyAmountRepository = MockRepository() - - moneyAmountRepository.addPriceListPrices = jest.fn(() => Promise.resolve()) - moneyAmountRepository.removePriceListPrices = jest.fn(() => Promise.resolve()) - moneyAmountRepository.updatePriceListPrices = jest.fn(() => Promise.resolve()) - - const priceListService = new PriceListService({ - manager: MockManager, - customerGroupService, - priceListRepository, - moneyAmountRepository, - featureFlagRouter: new FlagRouter({}), - regionService: RegionServiceMock, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - describe("retrieve", () => { - it("successfully retrieves a price list", async () => { - const result = await priceListService.retrieve(IdMap.getId("ironman")) - - expect(priceListRepository.findOne).toHaveBeenCalledTimes(1) - expect(priceListRepository.findOne).toHaveBeenCalledWith({ - where: { id: IdMap.getId("ironman") }, - }) - - expect(result.id).toEqual(IdMap.getId("ironman")) - }) - - it("fails on non-existing product variant id", async () => { - try { - await priceListService.retrieve(IdMap.getId("batman")) - } catch (error) { - expect(error.message).toBe( - `Price list with id: ${IdMap.getId("batman")} was not found` - ) - } - }) - }) - - describe("create", () => { - it("creates a new Price List", async () => { - await priceListService.create({ - name: "VIP winter sale", - description: "Winter sale for VIP customers. 25% off selected items.", - type: "sale", - status: "active", - starts_at: "2022-07-01T00:00:00.000Z", - ends_at: "2022-07-31T00:00:00.000Z", - customer_groups: [{ id: IdMap.getId("group") }], - prices: [ - { - amount: 100, - currency_code: "usd", - min_quantity: 1, - max_quantity: 100, - }, - ], - }) - - expect(priceListRepository.create).toHaveBeenCalledTimes(1) - expect(priceListRepository.create).toHaveBeenCalledWith({ - name: "VIP winter sale", - description: "Winter sale for VIP customers. 25% off selected items.", - type: "sale", - status: "active", - starts_at: "2022-07-01T00:00:00.000Z", - ends_at: "2022-07-31T00:00:00.000Z", - }) - expect(customerGroupService.retrieve).toHaveBeenCalledTimes(1) - expect(customerGroupService.retrieve).toHaveBeenCalledWith( - IdMap.getId("group") - ) - expect(moneyAmountRepository.addPriceListPrices).toHaveBeenCalledTimes(1) - expect(moneyAmountRepository.addPriceListPrices).toHaveBeenCalledWith( - IdMap.getId("ironman"), - [ - { - amount: 100, - currency_code: "usd", - min_quantity: 1, - max_quantity: 100, - }, - ] - ) - }) - }) - - describe("update", () => { - const updateRelatedMoneyAmountRepository = MockRepository() - updateRelatedMoneyAmountRepository.create = jest - .fn() - .mockImplementation((rawEntity) => Promise.resolve(rawEntity)) - - updateRelatedMoneyAmountRepository.save = jest - .fn() - .mockImplementation(() => Promise.resolve()) - updateRelatedMoneyAmountRepository.updatePriceListPrices = - MoneyAmountRepository.updatePriceListPrices - - const manager = { - save: (entities) => Promise.resolve(entities), - create: (entities) => Promise.resolve(entities), - } - const updateRelatedPriceListService = new PriceListService({ - manager: { ...MockManager, ...manager }, - customerGroupService, - priceListRepository, - moneyAmountRepository: updateRelatedMoneyAmountRepository, - featureFlagRouter: new FlagRouter({}), - regionService: RegionServiceMock, - }) - - it("update only existing price lists and related money amount", async () => { - await updateRelatedPriceListService.update(IdMap.getId("ironman"), { - description: "Updated description", - name: "Updated name", - prices: [ - { - id: "pl_dakjn", - amount: 100, - currency_code: "usd", - min_quantity: 1, - max_quantity: 100, - }, - ], - }) - - expect(updateRelatedMoneyAmountRepository.create).not.toHaveBeenCalled() - expect(updateRelatedMoneyAmountRepository.save).toHaveBeenCalled() - }) - - it("update only existing and create new price lists and related money amount", async () => { - await updateRelatedPriceListService.update(IdMap.getId("ironman"), { - description: "Updated description", - name: "Updated name", - prices: [ - { - id: "pl_dakjn", - amount: 100, - currency_code: "usd", - min_quantity: 1, - max_quantity: 100, - }, - { - amount: 100, - currency_code: "usd", - min_quantity: 1, - max_quantity: 100, - }, - ], - }) - - expect(updateRelatedMoneyAmountRepository.create).toHaveBeenCalledTimes(1) - expect(updateRelatedMoneyAmountRepository.save).toHaveBeenCalled() - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/product-category.ts b/packages/medusa/src/services/__tests__/product-category.ts deleted file mode 100644 index 7468652700..0000000000 --- a/packages/medusa/src/services/__tests__/product-category.ts +++ /dev/null @@ -1,287 +0,0 @@ -import { IdMap, MockManager as manager } from "medusa-test-utils" -import { EventBusService, ProductCategoryService } from "../" -import { - invalidProdCategoryId, - productCategoryRepositoryMock as productCategoryRepository, - validProdCategoryId, - validProdCategoryIdWithChildren, validProdCategoryRankChange, validProdCategoryWithSiblings -} from "../../repositories/__mocks__/product-category" -import { tempReorderRank } from "../../types/product-category" -import { EventBusServiceMock as eventBusService } from "../__mocks__/event-bus" - -const productCategoryService = new ProductCategoryService({ - manager, - productCategoryRepository, - eventBusService: eventBusService as unknown as EventBusService -}) - -describe("ProductCategoryService", () => { - beforeEach(async () => { jest.clearAllMocks() }) - - describe("retrieve", () => { - it("successfully retrieves a product category", async () => { - const validID = IdMap.getId(validProdCategoryId) - const result = await productCategoryService.retrieve( - validID - ) - - expect(result.id).toEqual(validID) - expect(productCategoryRepository.findOneWithDescendants).toHaveBeenCalledTimes(1) - expect(productCategoryRepository.findOneWithDescendants).toHaveBeenCalledWith({ - where: { id: validID }, - }, {}) - }) - - it("fails on not-found product category id", async () => { - const invalidID = IdMap.getId(invalidProdCategoryId) - const categoryResponse = await productCategoryService - .retrieve(invalidID) - .catch((e) => e) - - expect(categoryResponse.message).toBe( - `ProductCategory with id: ${invalidID} was not found` - ) - }) - }) - - describe("listAndCount", () => { - it("successfully retrieves an array of product category", async () => { - const validID = IdMap.getId(validProdCategoryId) - const [result, count] = await productCategoryService - .listAndCount({ q: validID }) - - expect(count).toEqual(1) - expect(result.length).toEqual(1) - expect(result[0].id).toEqual(validID) - expect(productCategoryRepository.getFreeTextSearchResultsAndCount).toHaveBeenCalledTimes(1) - expect(productCategoryRepository.findDescendantsTree).not.toBeCalled() - expect(productCategoryRepository.getFreeTextSearchResultsAndCount).toHaveBeenCalledWith( - { - skip: 0, - take: 100, - where: {}, - }, - validID, - {}, - false, - ) - }) - - it("returns empty array if query doesn't match database results", async () => { - const [result, count] = await productCategoryService - .listAndCount({ q: IdMap.getId(invalidProdCategoryId) }) - - expect( - productCategoryRepository.getFreeTextSearchResultsAndCount - ).toHaveBeenCalledTimes(1) - expect(result).toEqual([]) - expect(count).toEqual(0) - }) - - it("successfully calls tree descendants when requested to be included", async () => { - const validID = IdMap.getId(validProdCategoryId) - const [result, count] = await productCategoryService - .listAndCount({ include_descendants_tree: true }) - - expect(result[0].id).toEqual(validID) - expect(productCategoryRepository.getFreeTextSearchResultsAndCount).toHaveBeenCalledTimes(1) - expect(productCategoryRepository.getFreeTextSearchResultsAndCount).toHaveBeenCalledWith( - { - skip: 0, - take: 100, - where: {}, - }, - undefined, - {}, - true, - ) - }) - }) - - describe("create", () => { - it("successfully creates a product category", async () => { - await productCategoryService.create({ name: validProdCategoryId }) - - expect(productCategoryRepository.create).toHaveBeenCalledTimes(1) - expect(productCategoryRepository.create).toHaveBeenCalledWith({ - name: validProdCategoryId, - rank: 0, - }) - }) - - it("emits a message on successful create", async () => { - await productCategoryService.create({ name: validProdCategoryId }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "product-category.created", - { - id: IdMap.getId(validProdCategoryId), - } - ) - }) - }) - - describe("delete", () => { - it("successfully deletes a product category", async () => { - const result = await productCategoryService.delete( - IdMap.getId(validProdCategoryId) - ) - - expect(productCategoryRepository.delete).toBeCalledTimes(1) - expect(productCategoryRepository.delete).toBeCalledWith( - IdMap.getId(validProdCategoryId) - ) - }) - - it("returns without failure on not-found product category id", async () => { - const categoryResponse = await productCategoryService - .delete(IdMap.getId(invalidProdCategoryId)) - - expect(categoryResponse).toBe(undefined) - }) - - it("fails on product category with children", async () => { - const categoryResponse = await productCategoryService - .delete(IdMap.getId(validProdCategoryIdWithChildren)) - .catch((e) => e) - - expect(categoryResponse.message).toBe( - `Deleting ProductCategory (${IdMap.getId(validProdCategoryIdWithChildren)}) with category children is not allowed` - ) - }) - - it("emits a message on successful delete", async () => { - const result = await productCategoryService.delete( - IdMap.getId(validProdCategoryId) - ) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "product-category.deleted", - { - id: IdMap.getId(validProdCategoryId), - } - ) - }) - - it("deleting a category shifts its siblings into the correct rank", async () => { - const result = await productCategoryService.delete( - IdMap.getId(validProdCategoryWithSiblings) - ) - - expect(productCategoryRepository.delete).toBeCalledTimes(1) - expect(productCategoryRepository.delete).toBeCalledWith(IdMap.getId(validProdCategoryWithSiblings)) - - expect(productCategoryRepository.save).toBeCalledTimes(1) - expect(productCategoryRepository.save).toBeCalledWith({ - id: IdMap.getId(validProdCategoryId), - category_children: [], - parent_category_id: null, - rank: 0, - }) - }) - }) - - describe("update", () => { - it("successfully updates a product category", async () => { - await productCategoryService.update(IdMap.getId(validProdCategoryId), { - name: "bathrobes", - }) - - expect(productCategoryRepository.save).toHaveBeenCalledTimes(1) - expect(productCategoryRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - id: IdMap.getId(validProdCategoryId), - name: "bathrobes", - }) - ) - }) - - it("successfully updates a product category rank and its siblings", async () => { - await productCategoryService.update( - IdMap.getId(validProdCategoryRankChange), { - rank: 0 - } - ) - - expect(productCategoryRepository.save).toHaveBeenCalledTimes(3) - expect(productCategoryRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - id: IdMap.getId(validProdCategoryRankChange), - rank: tempReorderRank - }) - ) - - expect(productCategoryRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - id: IdMap.getId(validProdCategoryWithSiblings), - rank: 1 - }) - ) - }) - - it("fails on not-found Id product category", async () => { - const error = await productCategoryService - .update(IdMap.getId(invalidProdCategoryId), { - name: "bathrobes", - }) - .catch((e) => e) - - expect(error.message).toBe( - `ProductCategory with id: ${IdMap.getId( - invalidProdCategoryId - )} was not found` - ) - }) - - it("emits a message on successful update", async () => { - const result = await productCategoryService.update( - IdMap.getId(validProdCategoryId), - { - name: "bathrobes", - } - ) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "product-category.updated", - { - id: IdMap.getId(validProdCategoryId), - } - ) - }) - }) - - describe("addProducts", () => { - it("should add a list of product to a category", async () => { - const result = await productCategoryService.addProducts( - IdMap.getId("product-category-id"), - [IdMap.getId("product-id")] - ) - - expect(result).toBeUndefined() - expect(productCategoryRepository.addProducts).toHaveBeenCalledTimes(1) - expect(productCategoryRepository.addProducts).toHaveBeenCalledWith( - IdMap.getId("product-category-id"), - [IdMap.getId("product-id")] - ) - }) - }) - - describe("removeProducts", () => { - it("should remove a list of product from a category", async () => { - const result = await productCategoryService.removeProducts( - IdMap.getId("product-category-id"), - [IdMap.getId("product-id")] - ) - - expect(result).toBeUndefined() - expect(productCategoryRepository.removeProducts).toHaveBeenCalledTimes(1) - expect(productCategoryRepository.removeProducts).toHaveBeenCalledWith( - IdMap.getId("product-category-id"), - [IdMap.getId("product-id")] - ) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/product-collection.js b/packages/medusa/src/services/__tests__/product-collection.js deleted file mode 100644 index e80ede717e..0000000000 --- a/packages/medusa/src/services/__tests__/product-collection.js +++ /dev/null @@ -1,176 +0,0 @@ -import { IdMap, MockRepository, MockManager } from "medusa-test-utils" -import ProductCollectionService from "../product-collection" -import { EventBusServiceMock } from "../__mocks__/event-bus" - -describe("ProductCollectionService", () => { - describe("retrieve", () => { - const productCollectionRepository = MockRepository({ - findOne: query => { - if (query.where.id === "non-existing") { - return Promise.resolve(undefined) - } - return Promise.resolve({ id: IdMap.getId("bathrobe") }) - }, - }) - - const productCollectionService = new ProductCollectionService({ - manager: MockManager, - productCollectionRepository, - eventBusService: EventBusServiceMock, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully retrieves a product collection", async () => { - const result = await productCollectionService.retrieve( - IdMap.getId("bathrobe") - ) - - expect(productCollectionRepository.findOne).toHaveBeenCalledTimes(1) - expect(productCollectionRepository.findOne).toHaveBeenCalledWith({ - where: { id: IdMap.getId("bathrobe") }, - }) - - expect(result.id).toEqual(IdMap.getId("bathrobe")) - }) - - it("fails on non-existing product collection id", async () => { - try { - await productCollectionService.retrieve("non-existing") - } catch (error) { - expect(error.message).toBe( - `Product collection with id: non-existing was not found` - ) - } - }) - }) - - describe("create", () => { - const productCollectionRepository = MockRepository({ - findOne: query => Promise.resolve({ id: IdMap.getId("bathrobe") }), - create: query => Promise.resolve({ id: IdMap.getId("bathrobe") }), - }) - - const productCollectionService = new ProductCollectionService({ - manager: MockManager, - productCollectionRepository, - eventBusService: EventBusServiceMock, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully creates a product collection", async () => { - const entity = await productCollectionService.create({ title: "bathrobe" }) - - expect(productCollectionRepository.create).toHaveBeenCalledTimes(1) - expect(productCollectionRepository.create).toHaveBeenCalledWith({ - title: "bathrobe", - }) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - ProductCollectionService.Events.CREATED, { - id: entity.id, - } - ) - }) - }) - - describe("update", () => { - const productCollectionRepository = MockRepository({ - findOne: query => { - if (query.where.id === "non-existing") { - return Promise.resolve(undefined) - } - return Promise.resolve({ id: IdMap.getId("bathrobe") }) - }, - }) - - const productCollectionService = new ProductCollectionService({ - manager: MockManager, - productCollectionRepository, - eventBusService: EventBusServiceMock, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully updates a product collection", async () => { - await productCollectionService.update(IdMap.getId("bathrobe"), { - title: "bathrobes", - }) - - expect(productCollectionRepository.save).toHaveBeenCalledTimes(1) - expect(productCollectionRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("bathrobe"), - title: "bathrobes", - }) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - ProductCollectionService.Events.UPDATED, { - id: IdMap.getId("bathrobe"), - } - ) - }) - - it("fails on non-existing product collection", async () => { - try { - await productCollectionService.update(IdMap.getId("test"), { - title: "bathrobes", - }) - } catch (error) { - expect(error.message).toBe( - `Product collection with id: ${IdMap.getId("test")} was not found` - ) - } - }) - }) - - describe("delete", () => { - const productCollectionRepository = MockRepository({ - findOne: query => { - if (query.where.id === "non-existing") { - return Promise.resolve(undefined) - } - return Promise.resolve({ id: IdMap.getId("bathrobe") }) - }, - }) - - const productCollectionService = new ProductCollectionService({ - manager: MockManager, - productCollectionRepository, - eventBusService: EventBusServiceMock, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully removes a product collection", async () => { - await productCollectionService.delete(IdMap.getId("bathrobe")) - - expect(productCollectionRepository.softRemove).toHaveBeenCalledTimes(1) - expect(productCollectionRepository.softRemove).toHaveBeenCalledWith({ - id: IdMap.getId("bathrobe"), - }) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - ProductCollectionService.Events.DELETED, { - id: IdMap.getId("bathrobe"), - } - ) - }) - - it("succeeds idempotently", async () => { - const result = await productCollectionService.delete(IdMap.getId("test")) - expect(result).toBe(undefined) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/product-variant.js b/packages/medusa/src/services/__tests__/product-variant.js deleted file mode 100644 index 37d1c2f8f0..0000000000 --- a/packages/medusa/src/services/__tests__/product-variant.js +++ /dev/null @@ -1,1005 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import ProductVariantService from "../product-variant" - -const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - return this - }, -} - -describe("ProductVariantService", () => { - describe("retrieve", () => { - const productVariantRepository = MockRepository({ - findOne: (query) => { - if (query.where.id === IdMap.getId("batman")) { - return Promise.resolve(undefined) - } - return Promise.resolve({ id: IdMap.getId("ironman") }) - }, - }) - - const cartRepository = MockRepository({ - findOne: (data) => { - return Promise.resolve({}) - }, - }) - - const priceSelectionStrategy = { - withTransaction: function (manager) { - return this - }, - } - - const productVariantService = new ProductVariantService({ - manager: MockManager, - productVariantRepository, - cartRepository, - priceSelectionStrategy, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully retrieves a product variant", async () => { - const result = await productVariantService.retrieve( - IdMap.getId("ironman") - ) - - expect(productVariantRepository.findOne).toHaveBeenCalledTimes(1) - expect(productVariantRepository.findOne).toHaveBeenCalledWith({ - where: { id: IdMap.getId("ironman") }, - }) - - expect(result.id).toEqual(IdMap.getId("ironman")) - }) - - it("fails on non-existing product variant id", async () => { - try { - await productVariantService.retrieve(IdMap.getId("batman")) - } catch (error) { - expect(error.message).toBe( - `Variant with id: ${IdMap.getId("batman")} was not found` - ) - } - }) - }) - - describe("create", () => { - const productVariantRepository = MockRepository({ - findOne: (query) => { - return Promise.resolve() - }, - }) - - const productRepository = MockRepository({ - findOne: (query) => { - if (query.where.id === IdMap.getId("ironmans")) { - return Promise.resolve({ - id: IdMap.getId("ironman"), - options: [ - { - id: IdMap.getId("color"), - title: "red", - }, - { - id: IdMap.getId("size"), - title: "size", - }, - ], - variants: [ - { - id: IdMap.getId("v1"), - title: "V1", - options: [ - { - id: IdMap.getId("test"), - option_id: IdMap.getId("color"), - value: "blue", - }, - { - id: IdMap.getId("test"), - option_id: IdMap.getId("size"), - value: "large", - }, - ], - }, - ], - }) - } - return Promise.resolve({ - id: IdMap.getId("ironman"), - options: [ - { - id: IdMap.getId("color"), - title: "red", - }, - ], - variants: [ - { - id: IdMap.getId("v1"), - title: "V1", - options: [ - { - id: IdMap.getId("test"), - option_id: IdMap.getId("color"), - value: "blue", - }, - ], - }, - ], - }) - }, - }) - - const productVariantService = new ProductVariantService({ - manager: MockManager, - eventBusService, - productVariantRepository, - productRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully create product variant", async () => { - await productVariantService.create(IdMap.getId("ironman"), { - id: IdMap.getId("v2"), - options: [ - { - id: IdMap.getId("test"), - option_id: IdMap.getId("color"), - value: "red", - }, - ], - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - - expect(productVariantRepository.create).toHaveBeenCalledTimes(1) - expect(productVariantRepository.create).toHaveBeenCalledWith({ - id: IdMap.getId("v2"), - product_id: IdMap.getId("ironman"), - variant_rank: 1, - options: [ - { - id: IdMap.getId("test"), - option_id: IdMap.getId("color"), - value: "red", - }, - ], - }) - }) - - it("fails if product options and variant options differ in length", async () => { - try { - await productVariantService.create(IdMap.getId("ironmans"), { - id: IdMap.getId("v2"), - options: [ - { - id: IdMap.getId("test"), - option_id: IdMap.getId("color"), - value: "red", - }, - ], - }) - } catch (error) { - expect(error.message).toBe( - "Product options length does not match variant options length. Product has 2 and variant has 1." - ) - } - }) - - it("fails if variants options is missing a product option", async () => { - try { - await productVariantService.create(IdMap.getId("ironmans"), { - id: IdMap.getId("v2"), - options: [ - { - id: IdMap.getId("test"), - option_id: IdMap.getId("color"), - value: "red", - }, - { - id: IdMap.getId("test"), - option_id: IdMap.getId("material"), - value: "carbon", - }, - ], - }) - } catch (error) { - expect(error.message).toBe( - "Variant options do not contain value for size" - ) - } - }) - - it("fails if new option already exists", async () => { - try { - await productVariantService.create(IdMap.getId("ironmans"), { - id: IdMap.getId("v2"), - options: [ - { - id: IdMap.getId("test"), - option_id: IdMap.getId("color"), - value: "blue", - }, - { - id: IdMap.getId("test"), - option_id: IdMap.getId("size"), - value: "large", - }, - ], - }) - } catch (error) { - expect(error.message).toBe( - "Variant with title V1 with provided options already exists" - ) - } - }) - }) - - describe("update", () => { - const cartRepository = MockRepository({ - findOne: (data) => { - return Promise.resolve({}) - }, - }) - - const priceSelectionStrategy = { - withTransaction: function (manager) { - return this - }, - } - - const productVariantRepository = MockRepository({ - findOne: (query) => Promise.resolve({ id: IdMap.getId("ironman") }), - update: (data) => ({ - generatedMaps: [data], - }), - create: (data) => data, - }) - - const moneyAmountRepository = MockRepository({ - findOne: () => Promise.resolve({ id: IdMap.getId("some-amount") }), - }) - - const productOptionValueRepository = MockRepository({ - findOne: () => - Promise.resolve({ id: IdMap.getId("some-value"), value: "blue" }), - }) - - const productVariantService = new ProductVariantService({ - manager: MockManager, - eventBusService, - moneyAmountRepository, - productVariantRepository, - productOptionValueRepository, - cartRepository, - priceSelectionStrategy, - }) - - productVariantService.updateOptionValue = jest - .fn() - .mockReturnValue(() => Promise.resolve()) - - productVariantService.updateVariantPrices = jest - .fn() - .mockReturnValue(() => Promise.resolve()) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully updates variant by id", async () => { - await productVariantService.update(IdMap.getId("ironman"), { - title: "new title", - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith([ - { - eventName: "product-variant.updated", - data: { - id: IdMap.getId("ironman"), - fields: ["title"], - }, - }, - ]) - - expect(productVariantRepository.update).toHaveBeenCalledTimes(1) - expect(productVariantRepository.update).toHaveBeenCalledWith( - { id: IdMap.getId("ironman") }, - { - id: IdMap.getId("ironman"), - title: "new title", - } - ) - }) - - it("successfully updates variant", async () => { - await productVariantService.update( - { id: IdMap.getId("ironman"), title: "new title" }, - { - title: "new title 2", - } - ) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith([ - { - eventName: "product-variant.updated", - data: { - id: IdMap.getId("ironman"), - fields: ["title"], - }, - }, - ]) - - expect(productVariantRepository.update).toHaveBeenCalledTimes(1) - expect(productVariantRepository.update).toHaveBeenCalledWith( - { id: IdMap.getId("ironman") }, - { - id: IdMap.getId("ironman"), - title: "new title 2", - } - ) - }) - - it("successfully avoid to update variant if the data have not changed", async () => { - await productVariantService.update( - { id: IdMap.getId("ironman"), title: "new title" }, - { - title: "new title", - } - ) - - expect(eventBusService.emit).toHaveBeenCalledTimes(0) - - expect(productVariantRepository.save).toHaveBeenCalledTimes(0) - }) - - it("throws if provided variant is missing an id", async () => { - try { - await productVariantService.update( - { title: "new title" }, - { - title: "new title", - } - ) - } catch (error) { - expect(error.message).toBe("Variant id missing") - } - }) - - it("successfully updates variant metadata", async () => { - await productVariantService.update(IdMap.getId("ironman"), { - title: "new title", - metadata: { - testing: "this", - }, - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith([ - { - eventName: "product-variant.updated", - data: { - id: IdMap.getId("ironman"), - fields: ["title", "metadata"], - }, - }, - ]) - - expect(productVariantRepository.update).toHaveBeenCalledTimes(1) - expect(productVariantRepository.update).toHaveBeenCalledWith( - { id: IdMap.getId("ironman") }, - { - id: IdMap.getId("ironman"), - title: "new title", - metadata: { - testing: "this", - }, - } - ) - }) - - it("successfully updates variant inventory_quantity", async () => { - await productVariantService.update(IdMap.getId("ironman"), { - title: "new title", - inventory_quantity: 98, - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith([ - { - eventName: "product-variant.updated", - data: { - id: IdMap.getId("ironman"), - fields: ["title", "inventory_quantity"], - }, - }, - ]) - - expect(productVariantRepository.update).toHaveBeenCalledTimes(1) - expect(productVariantRepository.update).toHaveBeenCalledWith( - { id: IdMap.getId("ironman") }, - { - id: IdMap.getId("ironman"), - inventory_quantity: 98, - title: "new title", - } - ) - }) - - it("successfully updates variant prices", async () => { - await productVariantService.update(IdMap.getId("ironman"), { - title: "new title", - prices: [ - { - currency_code: "dkk", - amount: 1000, - }, - ], - }) - - expect(productVariantService.updateVariantPrices).toHaveBeenCalledTimes(1) - expect(productVariantService.updateVariantPrices).toHaveBeenCalledWith([ - { - variantId: IdMap.getId("ironman"), - prices: [ - { - currency_code: "dkk", - amount: 1000, - }, - ], - }, - ]) - - expect(productVariantRepository.update).toHaveBeenCalledTimes(1) - }) - - it("successfully updates variant options", async () => { - await productVariantService.update(IdMap.getId("ironman"), { - title: "new title", - options: [ - { - option_id: IdMap.getId("color"), - value: "red", - }, - ], - }) - - expect(productVariantService.updateOptionValue).toHaveBeenCalledTimes(1) - expect(productVariantService.updateOptionValue).toHaveBeenCalledWith( - IdMap.getId("ironman"), - IdMap.getId("color"), - "red" - ) - - expect(productVariantRepository.update).toHaveBeenCalledTimes(1) - }) - }) - - describe("updateVariantPrices", () => { - const moneyAmountRepository = MockRepository({ - remove: () => Promise.resolve(), - }) - const oldPrices = [ - { - currency_code: "dkk", - amount: 1000, - variant_id: "ironman", - region_id: null, - }, - ] - - moneyAmountRepository.deleteVariantPricesNotIn = jest - .fn() - .mockImplementation(() => Promise.resolve(oldPrices)) - - moneyAmountRepository.deleteVariantPrices = jest - .fn() - .mockImplementation((variant_id, price_ids) => Promise.resolve({})) - - const productVariantRepository = MockRepository({ - findOne: (query) => Promise.resolve({ id: IdMap.getId("ironman") }), - }) - - const productOptionValueRepository = MockRepository({ - findOne: () => - Promise.resolve({ id: IdMap.getId("some-value"), value: "blue" }), - }) - - const productVariantService = new ProductVariantService({ - manager: MockManager, - eventBusService, - moneyAmountRepository, - productVariantRepository, - productOptionValueRepository, - }) - - productVariantService.updateOptionValue = jest - .fn() - .mockReturnValue(() => Promise.resolve()) - - beforeEach(async () => { - jest.clearAllMocks() - }) - }) - - describe("getRegionPrice", () => { - const regionService = { - retrieve: function () { - return Promise.resolve({ - id: IdMap.getId("california"), - name: "California", - }) - }, - withTransaction: function () { - return this - }, - } - const moneyAmountRepository = MockRepository({ - findOne: (query) => { - if (query.where.variant_id === IdMap.getId("ironmanv2")) { - return Promise.resolve(undefined) - } - if (query.where.variant_id === IdMap.getId("ironman-sale")) { - return Promise.resolve({ - id: IdMap.getId("dkk"), - variant_id: IdMap.getId("ironman-sale"), - currency_code: "dkk", - region_id: IdMap.getId("california"), - amount: 1000, - }) - } - return Promise.resolve({ - id: IdMap.getId("dkk"), - variant_id: IdMap.getId("ironman"), - currency_code: "dkk", - region_id: IdMap.getId("california"), - amount: 1000, - }) - }, - }) - - const cartRepository = MockRepository({ - findOne: (data) => { - return Promise.resolve({}) - }, - }) - - const priceSelectionStrat = { - calculateVariantPrice: async ([{ variantId }], context) => { - return new Map([ - [ - variantId, - { - originalPrice: null, - calculatedPrice: 1000, - prices: [], - }, - ], - ]) - }, - } - - const priceSelectionStrategy = { - withTransaction: (manager) => { - return priceSelectionStrat - }, - } - - const productVariantService = new ProductVariantService({ - manager: MockManager, - eventBusService, - regionService, - moneyAmountRepository, - cartRepository, - priceSelectionStrategy, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully retrieves region price", async () => { - const result = await productVariantService.getRegionPrice( - IdMap.getId("ironman"), - IdMap.getId("california") - ) - - expect(result).toBe(1000) - }) - - it("successfully retrieves region sale price", async () => { - const result = await productVariantService.getRegionPrice( - IdMap.getId("ironman-sale"), - IdMap.getId("california") - ) - - // TODO: Update once PriceStrategy is implemented - expect(result).toBe(1000) - }) - - it("fails if no price is found", async () => { - try { - await productVariantService.getRegionPrice( - IdMap.getId("ironmanv2"), - IdMap.getId("california") - ) - } catch (error) { - expect(error.message).toBe( - "A price for region: California could not be found" - ) - } - }) - }) - - describe("updateVariantPrices", () => { - const moneyAmountRepository = MockRepository({ - findOne: (query) => { - if (query.where.region_id === IdMap.getId("cali")) { - return Promise.resolve(undefined) - } - return Promise.resolve({ - id: IdMap.getId("dkk"), - variant_id: IdMap.getId("ironman"), - currency_code: "dkk", - amount: 750, - }) - }, - find: (query) => { - if (query.where.region_id === IdMap.getId("cali")) { - return Promise.resolve([]) - } - return Promise.resolve([ - { - id: IdMap.getId("dkk"), - variant_id: IdMap.getId("ironman"), - currency_code: "dkk", - amount: 750, - }, - ]) - }, - create: (p) => p, - remove: () => Promise.resolve(), - insertBulk: (data) => data, - }) - - const productVariantRepository = MockRepository({ - find: (query) => { - return Promise.resolve([ - { - id: IdMap.getId("ironman"), - }, - ]) - }, - }) - - const oldPrices = [ - { - currency_code: "dkk", - amount: 1000, - variant_id: "ironman", - region_id: null, - }, - ] - - moneyAmountRepository.deleteVariantPricesNotIn = jest - .fn() - .mockImplementation(() => Promise.resolve(oldPrices)) - - moneyAmountRepository.upsertVariantCurrencyPrice = jest - .fn() - .mockImplementation(() => Promise.resolve()) - moneyAmountRepository.findCurrencyMoneyAmounts = jest - .fn() - .mockImplementation(() => - Promise.resolve([ - { - id: IdMap.getId("dkk"), - variant_id: IdMap.getId("ironman"), - currency_code: "dkk", - }, - ]) - ) - moneyAmountRepository.findRegionMoneyAmounts = jest - .fn() - .mockImplementation(() => Promise.resolve([])) - - const priceSelectionStrategy = { - withTransaction: function () { - return this - }, - onVariantsPricesUpdate: (variantIds) => Promise.resolve(), - } - - const regionService = { - list: jest.fn().mockImplementation((config) => { - const idOrIds = config.id - - if (Array.isArray(idOrIds)) { - return Promise.resolve( - idOrIds.map((id) => ({ id, currency_code: "usd" })) - ) - } else { - return Promise.resolve([{ id: idOrIds, currency_code: "usd" }]) - } - }), - retrieve: function () { - return Promise.resolve({ - id: IdMap.getId("california"), - name: "California", - }) - }, - withTransaction: function () { - return this - }, - } - - const productVariantService = new ProductVariantService({ - manager: MockManager, - eventBusService, - regionService, - priceSelectionStrategy, - moneyAmountRepository, - productVariantRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully removes obsolete prices and create new prices", async () => { - await productVariantService.updateVariantPrices(IdMap.getId("ironman"), [ - { - currency_code: "usd", - amount: 4000, - }, - ]) - - expect( - moneyAmountRepository.deleteVariantPricesNotIn - ).toHaveBeenCalledTimes(1) - - expect(moneyAmountRepository.insertBulk).toHaveBeenCalledTimes(1) - expect(moneyAmountRepository.insertBulk).toHaveBeenCalledWith([ - { - variant: { id: IdMap.getId("ironman") }, - currency_code: "usd", - amount: 4000, - }, - ]) - }) - - it("successfully creates new a region price", async () => { - await productVariantService.updateVariantPrices(IdMap.getId("ironman"), [ - { - amount: 100, - region_id: IdMap.getId("cali"), - }, - ]) - - expect(moneyAmountRepository.create).toHaveBeenCalledTimes(1) - expect(moneyAmountRepository.create).toHaveBeenCalledWith({ - variant: { id: IdMap.getId("ironman") }, - region_id: IdMap.getId("cali"), - currency_code: "usd", - amount: 100, - }) - - expect(moneyAmountRepository.insertBulk).toHaveBeenCalledTimes(1) - }) - - it("successfully updates a currency price", async () => { - await productVariantService.updateVariantPrices(IdMap.getId("ironman"), [ - { - id: IdMap.getId("dkk"), - currency_code: "dkk", - amount: 850, - }, - ]) - - expect(moneyAmountRepository.create).toHaveBeenCalledTimes(0) - - expect(moneyAmountRepository.update).toHaveBeenCalledTimes(1) - expect(moneyAmountRepository.update).toHaveBeenCalledWith( - { id: IdMap.getId("dkk") }, - { - amount: 850, - } - ) - }) - }) - - describe("updateOptionValue", () => { - const productOptionValueRepository = MockRepository({ - findOne: (query) => { - if (query.where.variant_id === IdMap.getId("jibberish")) { - return Promise.resolve(undefined) - } - return Promise.resolve({ - id: IdMap.getId("red"), - option_id: IdMap.getId("color"), - value: "red", - }) - }, - }) - - const productVariantService = new ProductVariantService({ - manager: MockManager, - eventBusService, - productOptionValueRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully updates", async () => { - await productVariantService.updateOptionValue( - IdMap.getId("ironman"), - IdMap.getId("color"), - "more red" - ) - - expect(productOptionValueRepository.save).toHaveBeenCalledTimes(1) - expect(productOptionValueRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("red"), - option_id: IdMap.getId("color"), - value: "more red", - }) - }) - - it("fails if product option value does not exist", async () => { - try { - await productVariantService.updateOptionValue( - IdMap.getId("jibberish"), - IdMap.getId("color"), - "red" - ) - } catch (error) { - expect(error.message).toBe("Product option value not found") - } - }) - }) - - describe("addOptionValue", () => { - const productOptionValueRepository = MockRepository({}) - - const productVariantService = new ProductVariantService({ - manager: MockManager, - eventBusService, - productOptionValueRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully add an option value", async () => { - await productVariantService.addOptionValue( - IdMap.getId("ironman"), - IdMap.getId("color"), - "black" - ) - - expect(productOptionValueRepository.create).toHaveBeenCalledTimes(1) - expect(productOptionValueRepository.create).toHaveBeenCalledWith({ - variant_id: IdMap.getId("ironman"), - option_id: IdMap.getId("color"), - value: "black", - }) - - expect(productOptionValueRepository.save).toBeCalledTimes(1) - }) - }) - - describe("deleteOptionValue", () => { - const productOptionValueRepository = MockRepository({ - findOne: (query) => { - if (query.where.option_id === IdMap.getId("size")) { - return Promise.resolve(undefined) - } - return Promise.resolve({ - variant_id: IdMap.getId("ironman"), - option_id: IdMap.getId("color"), - id: IdMap.getId("test"), - }) - }, - }) - - const productVariantService = new ProductVariantService({ - manager: MockManager, - eventBusService, - productOptionValueRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully deletes option value from variant", async () => { - await productVariantService.deleteOptionValue( - IdMap.getId("ironman"), - IdMap.getId("color") - ) - - expect(productOptionValueRepository.softRemove).toBeCalledTimes(1) - expect(productOptionValueRepository.softRemove).toBeCalledWith({ - variant_id: IdMap.getId("ironman"), - option_id: IdMap.getId("color"), - id: IdMap.getId("test"), - }) - }) - - it("successfully resolves if product option value does not exist", async () => { - const result = await productVariantService.deleteOptionValue( - IdMap.getId("ironman"), - IdMap.getId("size") - ) - - expect(result).toBe(undefined) - }) - }) - - describe("delete", () => { - const productVariantRepository = MockRepository({ - find: (query) => { - if (query.where.id === IdMap.getId("ironmanv2")) { - return Promise.resolve([]) - } - return Promise.resolve([ - { - id: IdMap.getId("ironman"), - product_id: IdMap.getId("product-test"), - }, - ]) - }, - }) - - const productVariantService = new ProductVariantService({ - manager: MockManager, - eventBusService, - productVariantRepository, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully deletes variant", async () => { - await productVariantService.delete(IdMap.getId("ironman")) - - expect(productVariantRepository.softRemove).toBeCalledTimes(1) - expect(productVariantRepository.softRemove).toBeCalledWith([ - expect.objectContaining({ - id: IdMap.getId("ironman"), - }), - ]) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith([ - { - eventName: "product-variant.deleted", - data: { - id: IdMap.getId("ironman"), - product_id: IdMap.getId("product-test"), - }, - }, - ]) - }) - - it("successfully resolves if variant does not exist", async () => { - const result = await productVariantService.delete( - IdMap.getId("ironmanv2") - ) - - expect(result).toBe(undefined) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/product.js b/packages/medusa/src/services/__tests__/product.js deleted file mode 100644 index 89683f2757..0000000000 --- a/packages/medusa/src/services/__tests__/product.js +++ /dev/null @@ -1,719 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import ProductService from "../product" -import { FlagRouter } from "@medusajs/utils" - -const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - return this - }, -} - -const mockUpsertTags = jest.fn().mockImplementation((data) => - Promise.resolve( - data.map(({ value, id }) => ({ - value, - id: id || (value === "title" ? "tag-1" : "tag-2"), - })) - ) -) - -const mockUpsertType = jest.fn().mockImplementation((value) => { - const productType = { - id: "type", - value: value, - } - return Promise.resolve(productType) -}) - -describe("ProductService", () => { - describe("retrieve", () => { - const productRepo = MockRepository({ - findOneWithRelations: (rels, query) => { - if (query.where.id === "test id with variants") { - return { - id: "test id with variants", - variants: [ - { id: "test_321", title: "Green" }, - { id: "test_123", title: "Blue" }, - ], - } - } - if (query.where.id === "test id one variant") { - return { - id: "test id one variant", - variants: [{ id: "test_123", title: "Blue" }], - } - } - return Promise.resolve({ id: IdMap.getId("ironman") }) - }, - }) - - const productService = new ProductService({ - manager: MockManager, - productRepository: productRepo, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully retrieves a product", async () => { - const result = await productService.retrieve(IdMap.getId("ironman")) - - expect(productRepo.findOneWithRelations).toHaveBeenCalledTimes(1) - expect(productRepo.findOneWithRelations).toHaveBeenCalledWith([], { - where: { id: IdMap.getId("ironman") }, - }) - - expect(result.id).toEqual(IdMap.getId("ironman")) - }) - }) - - describe("create", () => { - const productRepository = MockRepository({ - create: (product) => ({ - id: IdMap.getId("ironman"), - title: "Suit", - options: [], - collection: { id: IdMap.getId("cat"), title: "Suits" }, - variants: product.variants ?? [], - }), - findOneWithRelations: () => ({ - id: IdMap.getId("ironman"), - title: "Suit", - options: [], - collection: { id: IdMap.getId("cat"), title: "Suits" }, - }), - }) - - const productTagRepository = MockRepository({ - findOne: () => Promise.resolve(undefined), - create: (data) => { - if (data.value === "title") { - return { id: "tag-1", value: "title" } - } - - if (data.value === "title2") { - return { id: "tag-2", value: "title2" } - } - }, - }) - productTagRepository.upsertTags = mockUpsertTags - const productTypeRepository = MockRepository({ - findOne: () => Promise.resolve(undefined), - create: (data) => { - return { id: "type", value: "type1" } - }, - }) - productTypeRepository.upsertType = mockUpsertType - - const productCollectionService = { - withTransaction: function () { - return this - }, - retrieve: (id) => - Promise.resolve({ id: IdMap.getId("cat"), title: "Suits" }), - } - - const productVariantService = { - withTransaction: function () { - return this - }, - create: (id, data) => Promise.resolve(data), - } - - const productService = new ProductService({ - manager: MockManager, - productRepository, - eventBusService, - productCollectionService, - productTagRepository, - productTypeRepository, - productVariantService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("should successfully create a product", async () => { - await productService.create({ - title: "Suit", - options: [], - tags: [{ value: "title" }, { value: "title2" }], - type: "type-1", - variants: [ - { - id: "test1", - title: "green", - }, - { - id: "test2", - title: "blue", - }, - ], - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "product.created", - expect.any(Object) - ) - - expect(productRepository.create).toHaveBeenCalledTimes(1) - expect(productRepository.create).toHaveBeenCalledWith({ - title: "Suit", - }) - - expect(productTagRepository.upsertTags).toHaveBeenCalledTimes(1) - - expect(productTypeRepository.upsertType).toHaveBeenCalledTimes(1) - - expect(productRepository.save).toHaveBeenCalledTimes(1) - expect(productRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("ironman"), - title: "Suit", - options: [], - tags: [ - { - id: "tag-1", - value: "title", - }, - { - id: "tag-2", - value: "title2", - }, - ], - type_id: "type", - collection: { - id: IdMap.getId("cat"), - title: "Suits", - }, - variants: [ - { - id: "test1", - options: [], - title: "green", - }, - { - id: "test2", - options: [], - title: "blue", - }, - ], - }) - }) - }) - - describe("update", () => { - const productRepository = MockRepository({ - findOneWithRelations: (rels, query) => { - if (query.where.id === IdMap.getId("ironman&co")) { - return Promise.resolve({ - id: IdMap.getId("ironman&co"), - variants: [{ id: IdMap.getId("green"), title: "Green" }], - }) - } - if (query.where.id === "prod_status") { - return Promise.resolve({ - id: "prod_status", - status: "draft", - }) - } - if (query.where.id === "123") { - return undefined - } - if (query.where.id === "ranking test") { - return Promise.resolve({ - id: "ranking test", - variants: [ - { id: "test_321", title: "Greener", variant_rank: 1 }, - { id: "test_123", title: "Blueer", variant_rank: 0 }, - ], - }) - } - return Promise.resolve({ id: IdMap.getId("ironman") }) - }, - }) - - const productTypeRepository = MockRepository({ - findOne: () => Promise.resolve(undefined), - create: (data) => { - return { id: "type", value: "type1" } - }, - }) - productTypeRepository.upsertType = mockUpsertType - - const productTagRepository = MockRepository({ - findOne: (data) => { - if (data.where.value === "test") { - return Promise.resolve({ id: IdMap.getId("test"), value: "test" }) - } - if (data.where.value === "test2") { - return Promise.resolve({ id: IdMap.getId("test2"), value: "test2" }) - } - }, - }) - productTagRepository.upsertTags = mockUpsertTags - - const cartRepository = MockRepository({ - findOne: (data) => { - return Promise.resolve({}) - }, - }) - - const priceSelectionStrategy = { - withTransaction: (manager) => { - return this - }, - calculateVariantPrice: (variantId, context) => { - return { - originalPrice: null, - calculatedPrice: null, - prices: [], - } - }, - } - - const productService = new ProductService({ - manager: MockManager, - productRepository, - productTagRepository, - productTypeRepository, - eventBusService, - cartRepository, - priceSelectionStrategy, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully updates product metadata", async () => { - await productService.update(IdMap.getId("ironman"), { - metadata: { some_key: "some_value" }, - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "product.updated", - expect.any(Object) - ) - - expect(productRepository.save).toHaveBeenCalledTimes(1) - expect(productRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("ironman"), - metadata: { some_key: "some_value" }, - }) - }) - - it("successfully updates product status", async () => { - await productService.update(IdMap.getId("ironman"), { - status: "published", - }) - - expect(productRepository.save).toHaveBeenCalledTimes(1) - expect(productRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("ironman"), - status: "published", - }) - }) - - it("successfully updates product", async () => { - await productService.update(IdMap.getId("ironman"), { - title: "Full suit", - collection: { - id: IdMap.getId("test"), - value: "test", - }, - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "product.updated", - expect.any(Object) - ) - - expect(productRepository.save).toHaveBeenCalledTimes(1) - expect(productRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("ironman"), - title: "Full suit", - collection: { - id: IdMap.getId("test"), - value: "test", - }, - }) - }) - - it("successfully updates tags", async () => { - await productService.update(IdMap.getId("ironman"), { - tags: [ - { id: IdMap.getId("test"), value: "test" }, - { id: IdMap.getId("test2"), value: "test2" }, - ], - }) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "product.updated", - expect.any(Object) - ) - - expect(productRepository.save).toHaveBeenCalledTimes(1) - expect(productRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("ironman"), - tags: [ - { id: IdMap.getId("test"), value: "test" }, - { id: IdMap.getId("test2"), value: "test2" }, - ], - }) - }) - - it("throws on non existing product", async () => { - try { - await productService.update("123", { title: "new title" }) - } catch (err) { - expect(err.message).toEqual("Product with id: 123 was not found") - } - }) - }) - - describe("delete", () => { - const productRepository = MockRepository({ - findOne: () => Promise.resolve({ id: IdMap.getId("ironman") }), - }) - - const productService = new ProductService({ - manager: MockManager, - eventBusService, - productRepository, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - it("successfully deletes product", async () => { - await productService.delete(IdMap.getId("ironman")) - - expect(productRepository.softRemove).toBeCalledTimes(1) - expect(productRepository.softRemove).toBeCalledWith({ - id: IdMap.getId("ironman"), - }) - - expect(eventBusService.emit).toBeCalledTimes(1) - expect(eventBusService.emit).toBeCalledWith("product.deleted", { - id: IdMap.getId("ironman"), - }) - }) - }) - - describe("addOption", () => { - const productRepository = MockRepository({ - findOneWithRelations: (query) => - Promise.resolve({ - id: IdMap.getId("ironman"), - options: [{ title: "Color" }], - variants: [{ id: IdMap.getId("green") }], - }), - }) - - const productVariantService = { - withTransaction: function () { - return this - }, - addOptionValue: jest.fn(), - } - - const productOptionRepository = MockRepository({ - create: () => ({ id: IdMap.getId("Material"), title: "Material" }), - }) - - const productService = new ProductService({ - manager: MockManager, - productRepository, - productOptionRepository, - productVariantService, - eventBusService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("creates product option", async () => { - await productService.addOption(IdMap.getId("ironman"), "Material") - - expect(productOptionRepository.create).toHaveBeenCalledWith({ - title: "Material", - product_id: IdMap.getId("ironman"), - }) - expect(productOptionRepository.create).toHaveBeenCalledTimes(1) - - expect(productOptionRepository.save).toHaveBeenCalledTimes(1) - - expect(productVariantService.addOptionValue).toHaveBeenCalledTimes(1) - expect(productVariantService.addOptionValue).toHaveBeenCalledWith( - IdMap.getId("green"), - IdMap.getId("Material"), - "Default Value" - ) - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - expect(eventBusService.emit).toHaveBeenCalledWith( - "product.updated", - expect.any(Object) - ) - }) - - it("throws on duplicate option", async () => { - try { - await productService.addOption( - IdMap.getId("productWithVariantsFail"), - "Color" - ) - } catch (err) { - expect(err.message).toBe( - "An option with the title: Color already exists" - ) - } - }) - }) - - describe("reorderVariants", () => { - const productRepository = MockRepository({ - findOneWithRelations: (query) => - Promise.resolve({ - id: IdMap.getId("ironman"), - variants: [{ id: IdMap.getId("green") }, { id: IdMap.getId("blue") }], - }), - }) - - const productService = new ProductService({ - manager: MockManager, - productRepository, - eventBusService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("reorders variants", async () => { - await productService.reorderVariants(IdMap.getId("ironman"), [ - IdMap.getId("blue"), - IdMap.getId("green"), - ]) - - expect(productRepository.save).toBeCalledTimes(1) - expect(productRepository.save).toBeCalledWith({ - id: IdMap.getId("ironman"), - variants: [{ id: IdMap.getId("blue") }, { id: IdMap.getId("green") }], - }) - }) - - it("throws if a variant id is not in the products variants", async () => { - try { - await productService.reorderVariants(IdMap.getId("ironman"), [ - IdMap.getId("yellow"), - IdMap.getId("blue"), - ]) - } catch (err) { - expect(err.message).toEqual( - `Product has no variant with id: ${IdMap.getId("yellow")}` - ) - } - }) - - it("throws if order length and product variant lengths differ", async () => { - try { - await productService.reorderVariants(IdMap.getId("ironman"), [ - IdMap.getId("blue"), - ]) - } catch (err) { - expect(err.message).toEqual( - `Product variants and new variant order differ in length.` - ) - } - }) - }) - - describe("updateOption", () => { - const productRepository = MockRepository({ - findOneWithRelations: (query) => - Promise.resolve({ - id: IdMap.getId("ironman"), - options: [ - { id: IdMap.getId("material"), title: "Material" }, - { id: IdMap.getId("color"), title: "Color" }, - ], - }), - }) - - const productOptionRepository = MockRepository({ - findOne: () => - Promise.resolve({ id: IdMap.getId("color"), title: "Color" }), - }) - - const productService = new ProductService({ - manager: MockManager, - productRepository, - productOptionRepository, - eventBusService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("updates option title", async () => { - await productService.updateOption( - IdMap.getId("ironman"), - IdMap.getId("color"), - { - title: "Suit color", - } - ) - - expect(productOptionRepository.save).toBeCalledTimes(1) - expect(productOptionRepository.save).toBeCalledWith({ - id: IdMap.getId("color"), - title: "Suit color", - }) - }) - - it("throws if option title exists", async () => { - try { - await productService.updateOption( - IdMap.getId("ironman"), - IdMap.getId("color"), - { - title: "Color", - } - ) - } catch (err) { - expect(err.message).toEqual("An option with title Color already exists") - } - }) - - it("throws if option doesn't exist", async () => { - try { - await productService.updateOption( - IdMap.getId("ironman"), - IdMap.getId("material"), - { - title: "Size", - } - ) - } catch (err) { - expect(err.message).toEqual( - `Product has no option with id: ${IdMap.getId("material")}` - ) - } - }) - }) - - describe("deleteOption", () => { - const productRepository = MockRepository({ - findOneWithRelations: (query) => - Promise.resolve({ - id: IdMap.getId("ironman"), - variants: [ - { - id: IdMap.getId("red"), - options: [ - { - id: IdMap.getId("option1"), - option_id: IdMap.getId("color"), - value: "red", - }, - { - id: IdMap.getId("option2"), - option_id: IdMap.getId("size"), - value: "large", - }, - ], - }, - { - id: IdMap.getId("red2"), - options: [ - { - id: IdMap.getId("option2"), - option_id: IdMap.getId("color"), - value: "red", - }, - { - id: IdMap.getId("option1"), - option_id: IdMap.getId("size"), - value: "small", - }, - ], - }, - ], - }), - }) - - const productOptionRepository = MockRepository({ - findOne: (query) => { - if (query.where.id === IdMap.getId("material")) { - return undefined - } - return Promise.resolve({ id: IdMap.getId("color"), title: "Color" }) - }, - }) - - const productService = new ProductService({ - manager: MockManager, - productRepository, - productOptionRepository, - eventBusService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("deletes an option from a product", async () => { - await productService.deleteOption( - IdMap.getId("ironman"), - IdMap.getId("color") - ) - - expect(productOptionRepository.softRemove).toBeCalledTimes(1) - expect(productOptionRepository.softRemove).toBeCalledWith({ - id: IdMap.getId("color"), - title: "Color", - }) - }) - - it("resolve if product option does not exist", async () => { - await productService.deleteOption( - IdMap.getId("ironman"), - IdMap.getId("material") - ) - - expect(productOptionRepository.save).not.toBeCalled() - }) - - it("throw if variant option values are not equal", async () => { - try { - await productService.deleteOption( - IdMap.getId("ironman"), - IdMap.getId("color") - ) - } catch (error) { - expect(error.message).toBe( - "To delete an option, first delete all variants, such that when option is deleted, no duplicate variants will exist." - ) - } - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/publishable-api-key.ts b/packages/medusa/src/services/__tests__/publishable-api-key.ts deleted file mode 100644 index 453930090c..0000000000 --- a/packages/medusa/src/services/__tests__/publishable-api-key.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import EventBusService from "../event-bus" - -import PublishableApiKeyService from "../publishable-api-key" -import { EventBusServiceMock } from "../__mocks__/event-bus" - -const pubKeyToRetrieve = { - id: IdMap.getId("pub-key-to-retrieve"), - created_at: new Date(), - created_by: IdMap.getId("admin_user"), - revoked_by: null, - revoked_at: null, -} - -describe("PublishableApiKeyService", () => { - afterEach(() => { - jest.clearAllMocks() - }) - - const publishableApiKeyRepository = MockRepository({ - findOne: (data) => ({ ...pubKeyToRetrieve, ...data }), - create: (data) => { - return { - ...pubKeyToRetrieve, - ...data, - } - }, - }) - - const publishableApiKeySalesChannelRepository = MockRepository({}) - - const publishableApiKeyService = new PublishableApiKeyService({ - manager: MockManager, - publishableApiKeySalesChannelRepository: - publishableApiKeySalesChannelRepository, - publishableApiKeyRepository: publishableApiKeyRepository, - eventBusService: EventBusServiceMock as unknown as EventBusService, - }) - - it("should retrieve a publishable api key and call the repository with the right arguments", async () => { - await publishableApiKeyService.retrieve( - IdMap.getId("order-edit-with-changes") - ) - expect(publishableApiKeyRepository.findOne).toHaveBeenCalledTimes(1) - expect(publishableApiKeyRepository.findOne).toHaveBeenCalledWith({ - relationLoadStrategy: "query", - where: { - id: IdMap.getId("order-edit-with-changes"), - }, - }) - }) - - it("should create a publishable api key and call the repository with the right arguments as well as the event bus service", async () => { - await publishableApiKeyService.create( - { title: "API key title" }, - { - loggedInUserId: IdMap.getId("admin_user"), - } - ) - - expect(publishableApiKeyRepository.create).toHaveBeenCalledTimes(1) - expect(publishableApiKeyRepository.create).toHaveBeenCalledWith({ - created_by: IdMap.getId("admin_user"), - title: "API key title", - }) - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - PublishableApiKeyService.Events.CREATED, - { id: expect.any(String) } - ) - }) - - it("should update a publishable api key", async () => { - await publishableApiKeyService.update(pubKeyToRetrieve.id, { - title: "new title", - }) - - expect(publishableApiKeyRepository.save).toHaveBeenLastCalledWith( - expect.objectContaining({ - id: pubKeyToRetrieve.id, - title: "new title", - }) - ) - }) - - it("should revoke a publishable api key", async () => { - await publishableApiKeyService.revoke("id", { - loggedInUserId: IdMap.getId("admin_user"), - }) - - expect(publishableApiKeyRepository.save).toHaveBeenLastCalledWith( - expect.objectContaining({ - revoked_by: IdMap.getId("admin_user"), - }) - ) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenCalledWith( - PublishableApiKeyService.Events.REVOKED, - { id: expect.any(String) } - ) - }) -}) diff --git a/packages/medusa/src/services/__tests__/region.ts b/packages/medusa/src/services/__tests__/region.ts deleted file mode 100644 index f82b0c14e0..0000000000 --- a/packages/medusa/src/services/__tests__/region.ts +++ /dev/null @@ -1,697 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { CreateRegionInput } from "../../types/region" -import EventBusService from "../event-bus" -import { - FulfillmentProviderService, - PaymentProviderService, - StoreService, -} from "../index" -import RegionService from "../region" - -const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - return this - }, -} as unknown as EventBusService - -describe("RegionService", () => { - const regionRepository = MockRepository({}) - - const ppRepository = MockRepository({ - findOne: (query) => { - if (query.where.id === "should_fail") { - return Promise.resolve(undefined) - } - return Promise.resolve({ - id: "default_provider", - }) - }, - }) - const fpRepository = MockRepository({ - findOne: (query) => { - if (query.where.id === "should_fail") { - return Promise.resolve(undefined) - } - return Promise.resolve({ - id: "default_provider", - }) - }, - }) - const countryRepository = MockRepository({ - findOne: (query) => { - if (query.where.iso_2 === "dk") { - return Promise.resolve({ - id: IdMap.getId("dk"), - name: "Denmark", - display_name: "Denmark", - region_id: IdMap.getId("dk-reg"), - }) - } - return Promise.resolve({ - id: IdMap.getId("test-country"), - name: "World", - }) - }, - }) - - const currencyRepository = MockRepository({ - findOne: () => Promise.resolve({ code: "usd" }), - }) - - const storeService = { - withTransaction: function () { - return this - }, - retrieve: () => { - return { - id: IdMap.getId("test-store"), - currencies: [{ code: "dkk" }, { code: "usd" }, { code: "eur" }], - } - }, - } as unknown as StoreService - - const taxProviderRepository = MockRepository({}) - - const fulfillmentProviderService = {} as FulfillmentProviderService - - const paymentProviderService = {} as PaymentProviderService - - describe("create", () => { - const regionService = new RegionService({ - manager: MockManager, - eventBusService, - fulfillmentProviderRepository: fpRepository, - paymentProviderRepository: ppRepository, - currencyRepository, - regionRepository, - countryRepository, - storeService, - featureFlagRouter: new FlagRouter({}), - fulfillmentProviderService, - taxProviderRepository, - paymentProviderService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully creates a new region", async () => { - await regionService.create({ - name: "World", - currency_code: "USD", - tax_rate: 0.25, - countries: ["US"], - } as CreateRegionInput) - - expect(regionRepository.create).toHaveBeenCalledTimes(1) - expect(regionRepository.create).toHaveBeenCalledWith({ - name: "World", - currency_code: "usd", - currency: { - code: "usd", - }, - tax_rate: 0.25, - countries: [{ id: IdMap.getId("test-country"), name: "World" }], - }) - }) - - it("throws if country already is in region", async () => { - try { - await regionService.create({ - name: "World", - currency_code: "EUR", - tax_rate: 0.25, - countries: ["DK"], - } as CreateRegionInput) - } catch (error) { - expect(error.message).toBe( - `Denmark already exists in region ${IdMap.getId("dk-reg")}` - ) - } - }) - - it("successfully creates with payment- and fulfillmentproviders", async () => { - await regionService.create({ - name: "World", - currency_code: "usd", - tax_rate: 0.25, - countries: ["US"], - payment_providers: ["default_provider"], - fulfillment_providers: ["default_provider"], - }) - - expect(ppRepository.findOne).toHaveBeenCalledTimes(1) - expect(fpRepository.findOne).toHaveBeenCalledTimes(1) - - expect(regionRepository.create).toHaveBeenCalledTimes(1) - expect(regionRepository.create).toHaveBeenCalledWith({ - name: "World", - tax_rate: 0.25, - currency_code: "usd", - currency: { - code: "usd", - }, - countries: [{ id: IdMap.getId("test-country"), name: "World" }], - payment_providers: [{ id: "default_provider" }], - fulfillment_providers: [{ id: "default_provider" }], - }) - }) - - it("throws on invalid payment provider", async () => { - try { - await regionService.create({ - name: "World", - currency_code: "EUR", - tax_rate: 0.25, - countries: ["US"], - payment_providers: ["should_fail"], - } as CreateRegionInput) - } catch (error) { - expect(error.message).toBe("Payment provider not found") - } - }) - - it("throws on invalid fulfillment provider", async () => { - try { - await regionService.create({ - name: "World", - currency_code: "EUR", - tax_rate: 0.25, - countries: ["US"], - fulfillment_providers: ["should_fail"], - } as CreateRegionInput) - } catch (error) { - expect(error.message).toBe("Fulfillment provider not found") - } - }) - }) - - describe("retrieve", () => { - const regionRepository = MockRepository({ - findOne: () => Promise.resolve({ id: IdMap.getId("region") }), - }) - - const regionService = new RegionService({ - manager: MockManager, - eventBusService, - regionRepository, - featureFlagRouter: new FlagRouter({}), - fulfillmentProviderService, - taxProviderRepository, - paymentProviderService, - fulfillmentProviderRepository: fpRepository, - paymentProviderRepository: ppRepository, - currencyRepository, - countryRepository, - storeService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully retrieves a region", async () => { - await regionService.retrieve(IdMap.getId("region")) - - expect(regionRepository.findOne).toHaveBeenCalledTimes(1) - expect(regionRepository.findOne).toHaveBeenCalledWith({ - where: { id: IdMap.getId("region") }, - }) - }) - }) - - describe("validateFields_", () => { - const countryRepository = MockRepository({ - findOne: (query) => { - if (query.where.iso_2 === "dk") { - return Promise.resolve({ - id: IdMap.getId("dk"), - name: "Denmark", - display_name: "Denmark", - region_id: IdMap.getId("dk-reg"), - }) - } - return Promise.resolve({ - id: IdMap.getId("test-country"), - name: "World", - }) - }, - }) - - const regionService = new RegionService({ - manager: MockManager, - eventBusService, - regionRepository, - fulfillmentProviderService, - taxProviderRepository, - paymentProviderService, - fulfillmentProviderRepository: fpRepository, - paymentProviderRepository: ppRepository, - currencyRepository, - countryRepository, - storeService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("throws on invalid country code", async () => { - await expect( - // @ts-ignore - regionService.validateFields({ - countries: ["ddd"], - } as CreateRegionInput) - ).rejects.toThrow("Invalid country code") - }) - - it("throws on in use country code", async () => { - await expect( - // @ts-ignore - regionService.validateFields({ - countries: ["DK"], - } as CreateRegionInput) - ).rejects.toThrow( - `Denmark already exists in region ${IdMap.getId("dk-reg")}` - ) - }) - - it("throws on unknown payment providers", async () => { - await expect( - // @ts-ignore - regionService.validateFields({ - payment_providers: ["should_fail"], - } as CreateRegionInput) - ).rejects.toThrow("Payment provider not found") - }) - - it("throws on unknown fulfillment providers", async () => { - await expect( - // @ts-ignore - regionService.validateFields({ - fulfillment_providers: ["should_fail"], - } as CreateRegionInput) - ).rejects.toThrow("Fulfillment provider not found") - }) - }) - - describe("update", () => { - const regionRepository = MockRepository({ - findOne: () => Promise.resolve({ id: IdMap.getId("test-region") }), - }) - - const regionService = new RegionService({ - manager: MockManager, - eventBusService, - regionRepository, - fulfillmentProviderService, - taxProviderRepository, - paymentProviderService, - fulfillmentProviderRepository: fpRepository, - paymentProviderRepository: ppRepository, - currencyRepository, - countryRepository, - storeService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully updates a region", async () => { - await regionService.update(IdMap.getId("test-region"), { - name: "New Name", - currency_code: "eur", - tax_rate: 0.25, - countries: ["US"], - payment_providers: ["default_provider"], - fulfillment_providers: ["default_provider"], - }) - - expect(ppRepository.findOne).toHaveBeenCalledTimes(1) - expect(fpRepository.findOne).toHaveBeenCalledTimes(1) - - expect(regionRepository.save).toHaveBeenCalledTimes(1) - expect(regionRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("test-region"), - name: "New Name", - currency_code: "eur", - tax_rate: 0.25, - countries: [{ id: IdMap.getId("test-country"), name: "World" }], - payment_providers: [{ id: "default_provider" }], - fulfillment_providers: [{ id: "default_provider" }], - }) - }) - }) - - describe("delete", () => { - const regionRepository = MockRepository({ - findOne: () => - Promise.resolve({ - id: IdMap.getId("region"), - countries: [{ id: "us" }], - }), - }) - const countryRepository = MockRepository({ - findOne: () => Promise.resolve(), - }) - - const regionService = new RegionService({ - manager: MockManager, - eventBusService, - regionRepository, - fulfillmentProviderService, - taxProviderRepository, - paymentProviderService, - fulfillmentProviderRepository: fpRepository, - paymentProviderRepository: ppRepository, - currencyRepository, - countryRepository, - featureFlagRouter: new FlagRouter({}), - storeService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully deletes", async () => { - await regionService.delete(IdMap.getId("region")) - - expect(regionRepository.softRemove).toHaveBeenCalledTimes(1) - expect(regionRepository.softRemove).toHaveBeenCalledWith({ - id: IdMap.getId("region"), - countries: [{ id: "us" }], - }) - }) - }) - - describe("addCountry", () => { - const regionRepository = MockRepository({ - findOne: (query) => { - if (query.where.id === IdMap.getId("region-with-country")) { - return Promise.resolve({ - id: IdMap.getId("region-with-country"), - countries: [ - { id: IdMap.getId("dk"), name: "Denmark", iso_2: "DK" }, - ], - }) - } - return Promise.resolve({ id: IdMap.getId("region") }) - }, - }) - - const countryRepository = MockRepository({ - findOne: (query) => { - if (query.where.iso_2 === "dk") { - return Promise.resolve({ - id: IdMap.getId("dk"), - name: "Denmark", - iso_2: "DK", - }) - } - return Promise.resolve({ - id: IdMap.getId("test-country"), - name: "World", - }) - }, - }) - - const regionService = new RegionService({ - manager: MockManager, - eventBusService, - regionRepository, - fulfillmentProviderService, - taxProviderRepository, - paymentProviderService, - fulfillmentProviderRepository: fpRepository, - paymentProviderRepository: ppRepository, - currencyRepository, - countryRepository, - featureFlagRouter: new FlagRouter({}), - storeService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully adds to the countries array", async () => { - await regionService.addCountry(IdMap.getId("region"), "us") - - expect(regionRepository.findOne).toHaveBeenCalledTimes(1) - expect(regionRepository.findOne).toHaveBeenCalledWith({ - where: { id: IdMap.getId("region") }, - relations: { countries: true }, - }) - - expect(regionRepository.save).toHaveBeenCalledTimes(1) - expect(regionRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("region"), - countries: [{ id: IdMap.getId("test-country"), name: "World" }], - }) - }) - - it("resolves if exists", async () => { - await regionService.addCountry(IdMap.getId("region-with-country"), "DK") - - expect(regionRepository.findOne).toHaveBeenCalledTimes(1) - expect(regionRepository.save).toHaveBeenCalledTimes(0) - }) - }) - - describe("removeCountry", () => { - const regionRepository = MockRepository({ - findOne: (query) => { - return Promise.resolve({ - id: IdMap.getId("region"), - countries: [{ id: IdMap.getId("dk"), name: "Denmark", iso_2: "dk" }], - }) - }, - }) - - const regionService = new RegionService({ - manager: MockManager, - eventBusService, - regionRepository, - featureFlagRouter: new FlagRouter({}), - } as any) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully removes country", async () => { - await regionService.removeCountry(IdMap.getId("region"), "dk") - - expect(regionRepository.save).toHaveBeenCalledTimes(1) - expect(regionRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("region"), - countries: [], - }) - }) - }) - - describe("addPaymentProvider", () => { - const regionRepository = MockRepository({ - findOne: () => - Promise.resolve({ - id: IdMap.getId("region"), - payment_providers: [{ id: "sweden_provider" }], - }), - }) - - const regionService = new RegionService({ - manager: MockManager, - eventBusService, - regionRepository, - fulfillmentProviderService, - taxProviderRepository, - paymentProviderService, - fulfillmentProviderRepository: fpRepository, - paymentProviderRepository: ppRepository, - featureFlagRouter: new FlagRouter({}), - currencyRepository, - countryRepository, - storeService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully adds payment provider", async () => { - await regionService.addPaymentProvider( - IdMap.getId("region"), - "default_provider" - ) - - expect(regionRepository.findOne).toHaveBeenCalledTimes(1) - expect(ppRepository.findOne).toHaveBeenCalledTimes(1) - - expect(regionRepository.save).toHaveBeenCalledTimes(1) - expect(regionRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("region"), - payment_providers: [ - { id: "sweden_provider" }, - { id: "default_provider" }, - ], - }) - }) - - it("resolves if exists", async () => { - await regionService.addPaymentProvider( - IdMap.getId("region"), - "sweden_provider" - ) - - expect(regionRepository.findOne).toHaveBeenCalledTimes(1) - expect(regionRepository.save).toHaveBeenCalledTimes(0) - }) - }) - - describe("addFulfillmentProvider", () => { - const regionRepository = MockRepository({ - findOne: () => - Promise.resolve({ - id: IdMap.getId("region"), - fulfillment_providers: [{ id: "sweden_provider" }], - }), - }) - const fpRepository = MockRepository({ - findOne: (query) => { - if (query.where.id === "should_fail") { - return Promise.resolve(undefined) - } - return Promise.resolve({ - id: "default_provider", - }) - }, - }) - - const regionService = new RegionService({ - manager: MockManager, - eventBusService, - regionRepository, - featureFlagRouter: new FlagRouter({}), - fulfillmentProviderService, - taxProviderRepository, - paymentProviderService, - fulfillmentProviderRepository: fpRepository, - paymentProviderRepository: ppRepository, - currencyRepository, - countryRepository, - storeService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully adds payment provider", async () => { - await regionService.addFulfillmentProvider( - IdMap.getId("region"), - "default_provider" - ) - - expect(regionRepository.findOne).toHaveBeenCalledTimes(1) - expect(fpRepository.findOne).toHaveBeenCalledTimes(1) - - expect(regionRepository.save).toHaveBeenCalledTimes(1) - expect(regionRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("region"), - fulfillment_providers: [ - { id: "sweden_provider" }, - { id: "default_provider" }, - ], - }) - }) - - it("resolves if exists", async () => { - await regionService.addFulfillmentProvider( - IdMap.getId("region"), - "sweden_provider" - ) - - expect(regionRepository.findOne).toHaveBeenCalledTimes(1) - expect(regionRepository.save).toHaveBeenCalledTimes(0) - }) - }) - - describe("removePaymentProvider", () => { - const regionRepository = MockRepository({ - findOne: () => - Promise.resolve({ - id: IdMap.getId("region"), - payment_providers: [{ id: "sweden_provider" }], - }), - }) - - const regionService = new RegionService({ - manager: MockManager, - eventBusService, - regionRepository, - featureFlagRouter: new FlagRouter({}), - } as any) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("removes payment provider", async () => { - await regionService.removePaymentProvider( - IdMap.getId("region"), - "sweden_provider" - ) - - expect(regionRepository.findOne).toHaveBeenCalledTimes(1) - - expect(regionRepository.save).toHaveBeenCalledTimes(1) - expect(regionRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("region"), - payment_providers: [], - }) - }) - }) - - describe("removeFulfillmentProvider", () => { - const regionRepository = MockRepository({ - findOne: () => - Promise.resolve({ - id: IdMap.getId("region"), - fulfillment_providers: [{ id: "sweden_provider" }], - }), - }) - - const regionService = new RegionService({ - manager: MockManager, - eventBusService, - regionRepository, - featureFlagRouter: new FlagRouter({}), - } as any) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("removes payment provider", async () => { - await regionService.removeFulfillmentProvider( - IdMap.getId("region"), - "sweden_provider" - ) - - expect(regionRepository.findOne).toHaveBeenCalledTimes(1) - - expect(regionRepository.save).toHaveBeenCalledTimes(1) - expect(regionRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("region"), - fulfillment_providers: [], - }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/return.js b/packages/medusa/src/services/__tests__/return.js deleted file mode 100644 index 16fd907207..0000000000 --- a/packages/medusa/src/services/__tests__/return.js +++ /dev/null @@ -1,500 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { FlagRouter } from "@medusajs/utils" - -import idMap from "medusa-test-utils/dist/id-map" -import ReturnService from "../return" -import { ProductVariantInventoryServiceMock } from "../__mocks__/product-variant-inventory" -import { ShippingOptionServiceMock } from "../__mocks__/shipping-option" - -import TaxInclusivePricingFeatureFlag from "../../loaders/feature-flags/tax-inclusive-pricing" - -describe("ReturnService", () => { - describe("receive", () => { - const returnRepository = MockRepository({ - findOne: (query) => { - switch (query.where.id) { - case IdMap.getId("test-return-2"): - return Promise.resolve({ - id: IdMap.getId("test-return-2"), - status: "requested", - order: { - id: IdMap.getId("test-order"), - items: [ - { id: IdMap.getId("test-line"), quantity: 10 }, - { id: IdMap.getId("test-line-2"), quantity: 10 }, - ], - }, - items: [ - { - item_id: IdMap.getId("test-line"), - quantity: 10, - }, - ], - }) - case IdMap.getId("test-return-3"): - return Promise.resolve({ - status: "canceled", - }) - default: - return Promise.resolve({ - id: IdMap.getId("test-return"), - status: "requested", - order: { - id: IdMap.getId("test-order"), - items: [{ id: IdMap.getId("test-line"), quantity: 10 }], - }, - items: [ - { - item_id: IdMap.getId("test-line"), - quantity: 10, - }, - ], - }) - } - }, - }) - - const totalsService = { - getTotal: jest.fn().mockImplementation((cart) => { - return 1000 - }), - getRefundedTotal: jest.fn().mockImplementation((order, lineItems) => { - return 0 - }), - } - - const orderService = { - retrieve: jest.fn().mockImplementation(() => { - return Promise.resolve({ - items: [ - { - id: IdMap.getId("test-line"), - quantity: 10, - returned_quantity: 0, - variant_id: "test-variant", - }, - { - id: IdMap.getId("test-line-2"), - quantity: 10, - returned_quantity: 0, - variant_id: "test-variant-2", - }, - ], - payments: [{ id: "payment_test" }], - }) - }), - withTransaction: function () { - return this - }, - } - - const lineItemService = { - retrieve: jest.fn().mockImplementation((data) => { - return Promise.resolve({ ...data, returned_quantity: 0 }) - }), - update: jest.fn(), - withTransaction: function () { - return this - }, - } - - // const inventoryService = { - // adjustInventory: jest.fn((variantId, quantity) => { - // return Promise.resolve({}) - // }), - // confirmInventory: jest.fn((variantId, quantity) => { - // if (quantity < 10) { - // return true - // } else { - // return false - // } - // }), - // withTransaction: function () { - // return this - // }, - // } - - const returnService = new ReturnService({ - manager: MockManager, - totalsService, - lineItemService, - orderService, - returnRepository, - productVariantInventoryService: ProductVariantInventoryServiceMock, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully receives a return", async () => { - await returnService.receive( - IdMap.getId("test-return"), - [{ item_id: IdMap.getId("test-line"), quantity: 10 }], - 1000 - ) - - expect(returnRepository.save).toHaveBeenCalledTimes(1) - expect(returnRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("test-return"), - order: { - id: IdMap.getId("test-order"), - items: [{ id: IdMap.getId("test-line"), quantity: 10 }], - }, - status: "received", - items: [ - { - item_id: IdMap.getId("test-line"), - quantity: 10, - is_requested: true, - received_quantity: 10, - requested_quantity: 10, - }, - ], - refund_amount: 1000, - received_at: expect.anything(), - }) - - expect(lineItemService.update).toHaveBeenCalledTimes(1) - expect(lineItemService.update).toHaveBeenCalledWith( - IdMap.getId("test-line"), - { - returned_quantity: 10, - } - ) - - expect( - ProductVariantInventoryServiceMock.adjustInventory - ).toHaveBeenCalledTimes(1) - expect( - ProductVariantInventoryServiceMock.adjustInventory - ).toHaveBeenCalledWith("test-variant", undefined, 10) - }) - - it("successfully receives a return with requires_action status", async () => { - await returnService.receive( - IdMap.getId("test-return-2"), - [ - { item_id: IdMap.getId("test-line"), quantity: 10 }, - { item_id: IdMap.getId("test-line-2"), quantity: 10 }, - ], - 1000 - ) - - expect( - ProductVariantInventoryServiceMock.adjustInventory - ).toHaveBeenCalledTimes(2) - expect( - ProductVariantInventoryServiceMock.adjustInventory - ).toHaveBeenCalledWith("test-variant", undefined, 10) - expect( - ProductVariantInventoryServiceMock.adjustInventory - ).toHaveBeenCalledWith("test-variant-2", undefined, 10) - - expect(returnRepository.save).toHaveBeenCalledTimes(1) - expect(returnRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("test-return-2"), - order: { - id: IdMap.getId("test-order"), - items: [ - { id: IdMap.getId("test-line"), quantity: 10 }, - { id: IdMap.getId("test-line-2"), quantity: 10 }, - ], - }, - status: "requires_action", - items: [ - { - item_id: IdMap.getId("test-line"), - quantity: 10, - is_requested: true, - received_quantity: 10, - requested_quantity: 10, - }, - { - return_id: IdMap.getId("test-return-2"), - item_id: IdMap.getId("test-line-2"), - quantity: 10, - is_requested: false, - received_quantity: 10, - metadata: {}, - }, - ], - refund_amount: 1000, - received_at: expect.anything(), - }) - }) - - it("fails to receive a return which has been canceled", async () => { - await expect( - returnService.receive(IdMap.getId("test-return-3"), [ - { item_id: IdMap.getId("test-line"), quantity: 10 }, - { item_id: IdMap.getId("test-line-2"), quantity: 10 }, - ]) - ).rejects.toThrow("Cannot receive a canceled return") - }) - }) - - describe("canceled", () => { - const returnRepository = MockRepository({ - findOne: (query) => { - switch (query.where.id) { - case IdMap.getId("test-return"): - return Promise.resolve({ - status: "pending", - refund_amount: 0, - }) - case IdMap.getId("test-return-2"): - return Promise.resolve({ - status: "received", - refund_amount: 0, - }) - default: - return Promise.resolve({}) - } - }, - save: (f) => f, - }) - - const returnService = new ReturnService({ - manager: MockManager, - returnRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully cancels return", async () => { - await returnService.cancel(IdMap.getId("test-return")) - - expect(returnRepository.save).toHaveBeenCalledTimes(1) - expect(returnRepository.save).toHaveBeenCalledWith({ - status: "canceled", - refund_amount: 0, - }) - }) - - it("fails to cancel return when already received", async () => { - await expect( - returnService.cancel(IdMap.getId("test-return-2")) - ).rejects.toThrow("Can't cancel a return which has been returned") - }) - }) - - describe("fulfilled", () => { - const returnRepository = MockRepository({ - findOne: (query) => { - switch (query.where.id) { - case IdMap.getId("test-return"): - return Promise.resolve({ - status: "canceled", - }) - default: - return Promise.resolve({}) - } - }, - }) - - const returnService = new ReturnService({ - manager: MockManager, - returnRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("fails to fulfill when return is canceled", async () => { - await expect( - returnService.fulfill(IdMap.getId("test-return")) - ).rejects.toThrow("Cannot fulfill a canceled return") - }) - }) - - describe("update", () => { - const returnRepository = MockRepository({ - findOne: (query) => { - switch (query.where.id) { - case IdMap.getId("test-return"): - return Promise.resolve({ - status: "canceled", - }) - default: - return Promise.resolve({}) - } - }, - }) - - const returnService = new ReturnService({ - manager: MockManager, - returnRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("fails to update when return is canceled", async () => { - await expect( - returnService.update(IdMap.getId("test-return"), {}) - ).rejects.toThrow("Cannot update a canceled return") - }) - }) - - describe("create", () => { - const returnRepository = MockRepository({ - findOne: (query) => { - switch (query.where.id) { - case IdMap.getId("test-return"): - return Promise.resolve({ - status: "canceled", - }) - default: - return Promise.resolve({}) - } - }, - create: (data) => data, - save: (data) => data, - }) - - const returnItemRepository = MockRepository({ - create: (data) => data, - }) - - const totalsService = { - getTotal: jest.fn().mockImplementation((cart) => { - return 1000 - }), - getRefundTotal: jest.fn().mockImplementation((order, lineItems) => { - return 100 - }), - getCalculationContext: jest - .fn() - .mockImplementation((order, lineItems) => { - return Promise.resolve({}) - }), - } - - const orderService = { - retrieve: jest.fn().mockImplementation(() => { - return Promise.resolve({ - items: [ - { - id: IdMap.getId("test-line"), - quantity: 10, - returned_quantity: 0, - variant_id: "test-variant", - }, - { - id: IdMap.getId("test-line-2"), - quantity: 10, - returned_quantity: 0, - variant_id: "test-variant-2", - }, - ], - payments: [{ id: "payment_test" }], - }) - }), - withTransaction: function () { - return this - }, - } - - const lineItemService = { - retrieve: jest.fn().mockImplementation((data) => { - return Promise.resolve({ ...data, returned_quantity: 0 }) - }), - update: jest.fn(), - withTransaction: function () { - return this - }, - } - - const returnReasonService = { - withTransaction: function () { - return this - }, - list: jest.fn().mockImplementation(() => { - return Promise.resolve([ - { - id: IdMap.getId("test-return-reason"), - value: "test-return-reason", - label: "Test Return Reason", - description: null, - parent_return_reason_id: null, - return_reason_children: [], - metadata: {}, - }, - ]) - }, {}), - } - - const shippingOptionService = ShippingOptionServiceMock - const taxProviderService = { - withTransaction: function () { - return this - }, - createShippingTaxLines: jest.fn().mockImplementation((shippingMethod) => { - return Promise.resolve([ - { - rate: 25, - }, - ]) - }), - } - - const featureFlagRouter = new FlagRouter({ - [TaxInclusivePricingFeatureFlag.key]: false, - }) - - const returnService = new ReturnService({ - manager: MockManager, - lineItemService, - orderService, - totalsService, - returnReasonService, - returnRepository, - returnItemRepository, - shippingOptionService, - taxProviderService, - featureFlagRouter, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully creates a return", async () => { - await returnService.create({ - order_id: IdMap.getId("test-order"), - items: [ - { - item_id: IdMap.getId("test-line"), - quantity: 10, - }, - ], - shipping_method: { - option_id: "taxincl-option", - price: 80, - }, - }) - - expect(returnRepository.save).toHaveBeenCalledTimes(2) - expect(returnRepository.save).toHaveBeenCalledWith({ - order_id: IdMap.getId("test-order"), - items: [ - { - item_id: IdMap.getId("test-line"), - quantity: 10, - metadata: undefined, - note: undefined, - reason_id: undefined, - requested_quantity: 10, - }, - ], - status: "requested", - refund_amount: 0, - }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/sales-channel.ts b/packages/medusa/src/services/__tests__/sales-channel.ts deleted file mode 100644 index 107bb25fc6..0000000000 --- a/packages/medusa/src/services/__tests__/sales-channel.ts +++ /dev/null @@ -1,379 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { EventBusService, StoreService } from "../index" -import SalesChannelService from "../sales-channel" -import { EventBusServiceMock } from "../__mocks__/event-bus" -import { store, StoreServiceMock } from "../__mocks__/store" -import { FlagRouter } from "@medusajs/utils" - -describe("SalesChannelService", () => { - const salesChannelData = { - name: "sales channel 1 name", - description: "sales channel 1 description", - is_disabled: false, - } - - const salesChannelRepositoryMock = { - ...MockRepository({ - findOne: jest.fn().mockImplementation((query) => { - return Promise.resolve({ - id: query.where.id, - ...salesChannelData, - }) - }), - findAndCount: jest.fn().mockImplementation(() => - Promise.resolve([ - { - id: IdMap.getId("sales_channel_1"), - ...salesChannelData, - }, - ]) - ), - create: jest.fn().mockImplementation((data) => data), - save: (salesChannel) => - Promise.resolve({ - id: IdMap.getId("sales_channel_1"), - ...salesChannel, - }), - softRemove: jest.fn().mockImplementation((id: string): any => { - return Promise.resolve() - }), - }), - getFreeTextSearchResultsAndCount: jest.fn().mockImplementation(() => - Promise.resolve([ - { - id: IdMap.getId("sales_channel_1"), - ...salesChannelData, - }, - ]) - ), - removeProducts: jest - .fn() - .mockImplementation((id: string, productIds: string[]): any => { - Promise.resolve([ - { - id: IdMap.getId("sales_channel_1"), - ...salesChannelData, - }, - ]) - }), - addProducts: jest - .fn() - .mockImplementation((id: string, productIds: string[]): any => { - return Promise.resolve() - }), - } - - describe("create default", () => { - const salesChannelService = new SalesChannelService({ - manager: MockManager, - eventBusService: EventBusServiceMock as unknown as EventBusService, - salesChannelRepository: salesChannelRepositoryMock, - storeService: StoreServiceMock as unknown as StoreService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("should call the save method if the store does not have a default sales channel", async () => { - await salesChannelService.createDefault() - - expect(salesChannelRepositoryMock.save).toHaveBeenCalledTimes(1) - expect(salesChannelRepositoryMock.save).toHaveBeenCalledWith({ - description: "Created by Medusa", - name: "Default Sales Channel", - is_disabled: false, - }) - }) - - it("should return the default sales channel if it already exists", async () => { - const localSalesChannelService = new SalesChannelService({ - manager: MockManager, - eventBusService: EventBusServiceMock as unknown as EventBusService, - salesChannelRepository: salesChannelRepositoryMock, - featureFlagRouter: new FlagRouter({}), - storeService: { - ...StoreServiceMock, - retrieve: jest.fn().mockImplementation(() => { - return Promise.resolve({ - ...store, - default_sales_channel_id: IdMap.getId("sales_channel_1"), - default_sales_channel: { - id: IdMap.getId("sales_channel_1"), - ...salesChannelData, - }, - }) - }), - } as any, - }) - - const salesChannel = await localSalesChannelService.createDefault() - - expect(salesChannelRepositoryMock.save).toHaveBeenCalledTimes(0) - expect(salesChannelRepositoryMock.save).not.toHaveBeenCalledTimes(1) - expect(salesChannel).toEqual({ - id: IdMap.getId("sales_channel_1"), - ...salesChannelData, - }) - }) - }) - - describe("retrieve", () => { - const salesChannelService = new SalesChannelService({ - manager: MockManager, - featureFlagRouter: new FlagRouter({}), - eventBusService: EventBusServiceMock as unknown as EventBusService, - salesChannelRepository: salesChannelRepositoryMock, - storeService: StoreServiceMock as unknown as StoreService, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("should retrieve a sales channel", async () => { - const salesChannel = await salesChannelService.retrieve( - IdMap.getId("sales_channel_1") - ) - - expect(salesChannel).toBeTruthy() - expect(salesChannel).toEqual({ - id: IdMap.getId("sales_channel_1"), - ...salesChannelData, - }) - - expect(salesChannelRepositoryMock.findOne).toHaveBeenLastCalledWith({ - where: { id: IdMap.getId("sales_channel_1") }, - relationLoadStrategy: "query", - }) - }) - }) - - describe("update", () => { - const salesChannelService = new SalesChannelService({ - manager: MockManager, - featureFlagRouter: new FlagRouter({}), - eventBusService: EventBusServiceMock as unknown as EventBusService, - salesChannelRepository: salesChannelRepositoryMock, - storeService: StoreServiceMock as unknown as StoreService, - }) - - const update = { - name: "updated name", - description: "updated description", - is_disabled: true, - } - - beforeAll(async () => { - jest.clearAllMocks() - }) - - it("calls save with the updated sales channel", async () => { - await salesChannelService.update(IdMap.getId("sc"), update) - expect(salesChannelRepositoryMock.save).toHaveBeenCalledWith({ - id: IdMap.getId("sc"), - ...update, - }) - }) - - it("returns the saved sales channel", async () => { - const res = await salesChannelService.update(IdMap.getId("sc"), update) - expect(res).toEqual({ - id: IdMap.getId("sc"), - ...update, - }) - }) - }) - - describe("list", () => { - const salesChannelService = new SalesChannelService({ - manager: MockManager, - featureFlagRouter: new FlagRouter({}), - eventBusService: EventBusServiceMock as unknown as EventBusService, - salesChannelRepository: salesChannelRepositoryMock, - storeService: StoreServiceMock as unknown as StoreService, - }) - - afterEach(() => { - jest.clearAllMocks() - }) - - it("should retrieve a sales channel using free text search", async () => { - const q = "free search text" - - const salesChannel = await salesChannelService.listAndCount({ q }) - - expect(salesChannel).toBeTruthy() - expect(salesChannel).toEqual( - expect.arrayContaining([ - { - id: IdMap.getId("sales_channel_1"), - ...salesChannelData, - }, - ]) - ) - - expect(salesChannelRepositoryMock.findAndCount).toHaveBeenCalledTimes(0) - expect( - salesChannelRepositoryMock.getFreeTextSearchResultsAndCount - ).toHaveBeenCalledTimes(1) - expect( - salesChannelRepositoryMock.getFreeTextSearchResultsAndCount - ).toHaveBeenLastCalledWith(q, { - skip: 0, - take: 20, - where: {}, - }) - }) - - it("should retrieve a sales channel using find and count", async () => { - const salesChannel = await salesChannelService.listAndCount({ - id: IdMap.getId("sales_channel_1"), - }) - - expect(salesChannel).toBeTruthy() - expect(salesChannel).toEqual( - expect.arrayContaining([ - { - id: IdMap.getId("sales_channel_1"), - ...salesChannelData, - }, - ]) - ) - - expect( - salesChannelRepositoryMock.getFreeTextSearchResultsAndCount - ).toHaveBeenCalledTimes(0) - expect(salesChannelRepositoryMock.findAndCount).toHaveBeenCalledTimes(1) - expect(salesChannelRepositoryMock.findAndCount).toHaveBeenLastCalledWith({ - skip: 0, - take: 20, - where: { - id: IdMap.getId("sales_channel_1"), - }, - }) - }) - }) - - describe("delete", () => { - const salesChannelService = new SalesChannelService({ - manager: MockManager, - featureFlagRouter: new FlagRouter({}), - eventBusService: EventBusServiceMock as unknown as EventBusService, - salesChannelRepository: salesChannelRepositoryMock, - storeService: { - ...StoreServiceMock, - retrieve: jest.fn().mockImplementation(() => { - return Promise.resolve({ - ...store, - default_sales_channel_id: "default_channel", - default_sales_channel: { - id: "default_channel", - ...salesChannelData, - }, - }) - }), - } as any, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("should soft remove a sales channel", async () => { - const res = await salesChannelService.delete( - IdMap.getId("sales_channel_1") - ) - - expect(res).toBeUndefined() - - expect(salesChannelRepositoryMock.softRemove).toHaveBeenCalledTimes(1) - expect(salesChannelRepositoryMock.softRemove).toHaveBeenLastCalledWith({ - id: IdMap.getId("sales_channel_1"), - ...salesChannelData, - }) - - expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) - expect(EventBusServiceMock.emit).toHaveBeenLastCalledWith( - SalesChannelService.Events.DELETED, - { id: IdMap.getId("sales_channel_1") } - ) - }) - - it("should fail if delete of the default channel is attempted", async () => { - try { - await salesChannelService.delete("default_channel") - } catch (error) { - expect(error.message).toEqual( - "You cannot delete the default sales channel" - ) - } - }) - }) - - describe("Remove products", () => { - const salesChannelService = new SalesChannelService({ - manager: MockManager, - featureFlagRouter: new FlagRouter({}), - eventBusService: EventBusServiceMock as unknown as EventBusService, - salesChannelRepository: salesChannelRepositoryMock, - storeService: StoreServiceMock as unknown as StoreService, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("should remove a list of product to a sales channel", async () => { - const salesChannel = await salesChannelService.removeProducts( - IdMap.getId("sales_channel_1"), - [IdMap.getId("sales_channel_1_product_1")] - ) - - expect(salesChannelRepositoryMock.removeProducts).toHaveBeenCalledTimes(1) - expect(salesChannelRepositoryMock.removeProducts).toHaveBeenCalledWith( - IdMap.getId("sales_channel_1"), - [IdMap.getId("sales_channel_1_product_1")] - ) - expect(salesChannel).toBeTruthy() - expect(salesChannel).toEqual({ - id: IdMap.getId("sales_channel_1"), - ...salesChannelData, - }) - }) - }) - - describe("Add products", () => { - const salesChannelService = new SalesChannelService({ - manager: MockManager, - featureFlagRouter: new FlagRouter({}), - eventBusService: EventBusServiceMock as unknown as EventBusService, - salesChannelRepository: salesChannelRepositoryMock, - storeService: StoreServiceMock as unknown as StoreService, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("should add a list of product to a sales channel", async () => { - const salesChannel = await salesChannelService.addProducts( - IdMap.getId("sales_channel_1"), - [IdMap.getId("sales_channel_1_product_1")] - ) - - expect(salesChannelRepositoryMock.addProducts).toHaveBeenCalledTimes(1) - expect(salesChannelRepositoryMock.addProducts).toHaveBeenCalledWith( - IdMap.getId("sales_channel_1"), - [IdMap.getId("sales_channel_1_product_1")], - false - ) - expect(salesChannel).toBeTruthy() - expect(salesChannel).toEqual({ - id: IdMap.getId("sales_channel_1"), - ...salesChannelData, - }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/shipping-option.js b/packages/medusa/src/services/__tests__/shipping-option.js deleted file mode 100644 index 58c2f4927c..0000000000 --- a/packages/medusa/src/services/__tests__/shipping-option.js +++ /dev/null @@ -1,702 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import TaxInclusivePricingFeatureFlag from "../../loaders/feature-flags/tax-inclusive-pricing" -import { FlagRouter } from "@medusajs/utils" -import ShippingOptionService from "../shipping-option" - -describe("ShippingOptionService", () => { - describe("retrieve", () => { - afterAll(() => { - jest.clearAllMocks() - }) - const shippingOptionRepository = MockRepository({ - findOne: () => Promise.resolve({}), - }) - const optionService = new ShippingOptionService({ - manager: MockManager, - shippingOptionRepository, - featureFlagRouter: new FlagRouter({}), - }) - - it("successfully gets shipping option", async () => { - await optionService.retrieve(IdMap.getId("validId")) - - expect(shippingOptionRepository.findOne).toHaveBeenCalledWith({ - where: { id: IdMap.getId("validId") }, - }) - }) - }) - - describe("update", () => { - const shippingOptionRepository = MockRepository({ - findOne: (q) => { - switch (q.where.id) { - case IdMap.getId("noCalc"): - return Promise.resolve({ - provider_id: "no_calc", - }) - case IdMap.getId("validId"): - return Promise.resolve({ - provider_id: "provider", - amount: 100, - data: { - provider_data: "true", - }, - }) - case "flat-rate-no-amount": - return Promise.resolve({ - provider_id: "provider", - data: { - provider_data: "true", - }, - }) - default: - return Promise.resolve({}) - } - }, - }) - - const fulfillmentProviderService = { - canCalculate: jest - .fn() - .mockImplementation((option) => option.provider_id !== "no_calc"), - } - - const shippingOptionRequirementRepository = MockRepository({ - create: (r) => r, - }) - const optionService = new ShippingOptionService({ - manager: MockManager, - shippingOptionRepository, - shippingOptionRequirementRepository, - fulfillmentProviderService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("calls updateOne with correct params", async () => { - await optionService.update(IdMap.getId("option"), { name: "new title" }) - - expect(shippingOptionRepository.save).toBeCalledTimes(1) - expect(shippingOptionRepository.save).toBeCalledWith({ - name: "new title", - }) - }) - - it("sets requirements", async () => { - const requirements = [ - { - type: "min_subtotal", - amount: 1, - }, - ] - - await optionService.update(IdMap.getId("option"), { requirements }) - - expect(shippingOptionRepository.save).toHaveBeenCalledTimes(1) - expect(shippingOptionRequirementRepository.save).toHaveBeenCalledTimes(1) - expect(shippingOptionRequirementRepository.save).toHaveBeenCalledWith({ - shipping_option_id: IdMap.getId("option"), - type: "min_subtotal", - amount: 1, - }) - }) - - it("fails on invalid req", async () => { - const requirements = [ - { - type: "_", - amount: 2, - }, - { - type: "min_subtotal", - amount: 1, - }, - ] - - await expect( - optionService.update(IdMap.getId("option"), { requirements }) - ).rejects.toThrow( - "Requirement type must be one of min_subtotal, max_subtotal" - ) - }) - - it("fails on duplicate reqs", async () => { - const requirements = [ - { - type: "min_subtotal", - amount: 2, - }, - { - type: "min_subtotal", - amount: 1, - }, - ] - - await expect( - optionService.update(IdMap.getId("validId"), { requirements }) - ).rejects.toThrow("Only one requirement of each type is allowed") - }) - - it("sets flat rate price", async () => { - await optionService.update(IdMap.getId("validId"), { - price_type: "flat_rate", - amount: 200, - }) - - expect(shippingOptionRepository.save).toHaveBeenCalledTimes(1) - expect(shippingOptionRepository.save).toHaveBeenCalledWith({ - provider_id: "provider", - data: { - provider_data: "true", - }, - price_type: "flat_rate", - amount: 200, - }) - }) - - it("throws on flat rate but no amount", async () => { - expect.assertions(1) - try { - await optionService.update(IdMap.getId("flat-rate-no-amount"), { - price_type: "flat_rate", - }) - } catch (error) { - expect(error.message).toEqual( - "Shipping options of type `flat_rate` must have an `amount`" - ) - } - }) - - it("sets a price to", async () => { - await optionService.update(IdMap.getId("validId"), { - price_type: "flat_rate", - amount: 0, - }) - - expect(shippingOptionRepository.save).toHaveBeenCalledTimes(1) - expect(shippingOptionRepository.save).toHaveBeenCalledWith({ - provider_id: "provider", - data: { - provider_data: "true", - }, - price_type: "flat_rate", - amount: 0, - }) - }) - - it("sets calculated price", async () => { - await optionService.update(IdMap.getId("validId"), { - price_type: "calculated", - }) - - expect(fulfillmentProviderService.canCalculate).toHaveBeenCalledTimes(1) - expect(fulfillmentProviderService.canCalculate).toHaveBeenCalledWith({ - data: { provider_data: "true" }, - provider_id: "provider", - }) - - expect(shippingOptionRepository.save).toHaveBeenCalledTimes(1) - expect(shippingOptionRepository.save).toHaveBeenCalledWith({ - provider_id: "provider", - data: { - provider_data: "true", - }, - price_type: "calculated", - amount: null, - }) - }) - - it("fails on invalid type", async () => { - await expect( - optionService.update(IdMap.getId("validId"), { - price_type: "non", - }) - ).rejects.toThrow("The price must be of type flat_rate or calculated") - }) - - it("fails if provider cannot calculate", async () => { - await expect( - optionService.update(IdMap.getId("noCalc"), { - price_type: "calculated", - }) - ).rejects.toThrow( - "The fulfillment provider cannot calculate prices for this option" - ) - }) - - it("throws error when trying to update region_id", async () => { - const id = IdMap.getId("validId") - await expect( - optionService.update(`${id}`, { region_id: "id" }) - ).rejects.toThrow("Region and Provider cannot be updated after creation") - }) - - it("throws error when trying to update provider_id", async () => { - const id = IdMap.getId("validId") - await expect( - optionService.update(`${id}`, { provider_id: "id" }) - ).rejects.toThrow("Region and Provider cannot be updated after creation") - }) - }) - - describe("delete", () => { - const shippingOptionRepository = MockRepository({ - findOne: (i) => - i.where.id === IdMap.getId("validId") - ? { id: IdMap.getId("validId") } - : null, - }) - const optionService = new ShippingOptionService({ - manager: MockManager, - shippingOptionRepository, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("deletes the option successfully", async () => { - await optionService.delete(IdMap.getId("validId")) - - expect(shippingOptionRepository.softRemove).toBeCalledTimes(1) - expect(shippingOptionRepository.softRemove).toBeCalledWith({ - id: IdMap.getId("validId"), - }) - }) - - it("is idempotent", async () => { - await expect(optionService.delete(IdMap.getId("delete"))).resolves - - expect(shippingOptionRepository.softRemove).toBeCalledTimes(0) - }) - }) - - describe("addRequirement", () => { - const shippingOptionRepository = MockRepository({ - findOne: (q) => { - switch (q.where.id) { - case IdMap.getId("has-min"): - return Promise.resolve({ - requirements: [ - { - type: "min_subtotal", - amount: 1234, - }, - ], - }) - default: - return Promise.resolve({ requirements: [] }) - } - }, - }) - - const shippingOptionRequirementRepository = MockRepository({ - create: (r) => r, - }) - const optionService = new ShippingOptionService({ - manager: MockManager, - shippingOptionRepository, - shippingOptionRequirementRepository, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("add product to profile successfully", async () => { - await optionService.addRequirement(IdMap.getId("validId"), { - type: "max_subtotal", - amount: 10, - }) - - expect(shippingOptionRequirementRepository.create).toBeCalledTimes(0) - - expect(shippingOptionRepository.save).toBeCalledTimes(1) - expect(shippingOptionRepository.save).toBeCalledWith({ - requirements: [ - { - type: "max_subtotal", - amount: 10, - }, - ], - }) - }) - - it("fails if type exists", async () => { - await expect( - optionService.addRequirement(IdMap.getId("has-min"), { - type: "min_subtotal", - amount: 100, - }) - ).rejects.toThrow("A requirement with type: min_subtotal already exists") - }) - }) - - describe("removeRequirement", () => { - const shippingOptionRequirementRepository = MockRepository({ - softRemove: (q) => { - return Promise.resolve() - }, - findOne: (i) => { - if (i.where.id === IdMap.getId("requirement_id")) { - return { id: IdMap.getId("requirement_id") } - } else { - return null - } - } - }) - - const optionService = new ShippingOptionService({ - manager: MockManager, - shippingOptionRequirementRepository, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("remove requirement successfully", async () => { - await optionService.removeRequirement(IdMap.getId("requirement_id")) - - expect(shippingOptionRequirementRepository.findOne).toBeCalledTimes(1) - expect(shippingOptionRequirementRepository.findOne).toBeCalledWith({ - where: { id: IdMap.getId("requirement_id") }, - }) - expect(shippingOptionRequirementRepository.softRemove).toBeCalledTimes(1) - }) - - it("is idempotent", async () => { - await optionService.removeRequirement(IdMap.getId("validId"), "something") - - expect(shippingOptionRequirementRepository.softRemove).toBeCalledTimes(0) - }) - }) - - describe("create", () => { - const shippingOptionRepository = MockRepository({ - create: (r) => r, - }) - - const fulfillmentProviderService = { - validateOption: jest.fn().mockImplementation((o) => { - return Promise.resolve(o.data.res) - }), - } - - const regionService = { - withTransaction: function () { - return this - }, - retrieve: () => { - return Promise.resolve({ fulfillment_providers: [{ id: "provider" }] }) - }, - } - - const shippingOptionRequirementRepository = MockRepository({ - create: (r) => r, - }) - const optionService = new ShippingOptionService({ - manager: MockManager, - shippingOptionRepository, - shippingOptionRequirementRepository, - fulfillmentProviderService, - regionService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("creates a shipping option", async () => { - const option = { - name: "Test Option", - provider_id: "provider", - data: { - res: true, - }, - region_id: IdMap.getId("reg"), - requirements: [ - { - type: "min_subtotal", - amount: 1, - }, - ], - price_type: "flat_rate", - amount: 13, - } - - await optionService.create(option) - - expect(shippingOptionRepository.create).toHaveBeenCalledTimes(1) - expect(shippingOptionRepository.create).toHaveBeenCalledWith(option) - - expect(fulfillmentProviderService.validateOption).toHaveBeenCalledTimes(1) - expect(fulfillmentProviderService.validateOption).toHaveBeenCalledWith( - option - ) - - expect(shippingOptionRepository.save).toHaveBeenCalledTimes(1) - expect(shippingOptionRepository.save).toHaveBeenCalledWith(option) - }) - - it("fails if region doesn't have fulfillment provider", async () => { - const option = { - name: "Test Option", - provider_id: "testshipper", - data: { - id: "new", - }, - region_id: IdMap.getId("region-france"), - requirements: [ - { - type: "min_subtotal", - amount: 1, - }, - ], - price_type: "flat_rate", - amount: 13, - } - - await expect(optionService.create(option)).rejects.toThrow( - "The fulfillment provider is not available in the provided region" - ) - }) - - it("fails if fulfillment provider cannot validate", async () => { - const option = { - name: "Test Option", - provider_id: "provider", - data: { - res: false, - }, - region_id: IdMap.getId("region-france"), - price_type: "flat_rate", - amount: 13, - } - - await expect(optionService.create(option)).rejects.toThrow( - "The fulfillment provider cannot validate the shipping option" - ) - }) - - it("fails if requirement is not validated", async () => { - const option = { - name: "Test Option", - provider_id: "provider", - data: { - res: true, - }, - requirements: [ - { - type: "_subtotal", - value: 100, - }, - ], - region_id: IdMap.getId("region-france"), - price_type: "flat_rate", - amount: 13, - } - - await expect(optionService.create(option)).rejects.toThrow( - "Requirement type must be one of min_subtotal, max_subtotal" - ) - }) - - it("fails if price is not validated", async () => { - const option = { - name: "Test Option", - provider_id: "provider", - data: { - res: true, - }, - region_id: IdMap.getId("region-france"), - price_type: "nonon", - amount: 13, - } - - await expect(optionService.create(option)).rejects.toThrow( - "The price must be of type flat_rate or calculated" - ) - }) - }) - - describe("createShippingMethod", () => { - const option = (id) => ({ - id, - region_id: IdMap.getId("region"), - price_type: "flat_rate", - amount: 10, - data: { - something: "yes", - }, - requirements: [ - { - type: "min_subtotal", - amount: 100, - }, - ], - }) - const shippingOptionRepository = MockRepository({ - findOne: (q) => { - switch (q.where.id) { - default: - return Promise.resolve(option(q.where.id)) - } - }, - }) - const shippingMethodRepository = MockRepository({ create: (r) => r }) - const totalsService = { - getSubtotal: (c) => { - return c.subtotal - }, - } - - const providerService = { - validateFulfillmentData: jest - .fn() - .mockImplementation((r) => Promise.resolve(r.data)), - getPrice: (d) => d.price, - } - - const optionService = new ShippingOptionService({ - manager: MockManager, - shippingMethodRepository, - shippingOptionRepository, - totalsService, - fulfillmentProviderService: providerService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("validates", async () => { - const cart = { - id: IdMap.getId("cart"), - region_id: IdMap.getId("region"), - subtotal: 400, - } - - await optionService.createShippingMethod( - IdMap.getId("option"), - { provider_data: "dat" }, - { cart } - ) - - expect(providerService.validateFulfillmentData).toHaveBeenCalledTimes(1) - expect(providerService.validateFulfillmentData).toHaveBeenCalledWith( - option(IdMap.getId("option")), - { provider_data: "dat" }, - cart - ) - - expect(shippingMethodRepository.save).toHaveBeenCalledTimes(1) - expect(shippingMethodRepository.save).toHaveBeenCalledWith({ - cart_id: IdMap.getId("cart"), - shipping_option_id: IdMap.getId("option"), - price: 10, - data: { something: "yes" }, - }) - }) - - it("fails on invalid req", async () => { - const id = IdMap.getId("option") - const d = { some: "thing" } - const c = { region_id: IdMap.getId("nomatch") } - - await expect( - optionService.createShippingMethod(id, d, { cart: c }) - ).rejects.toThrow( - "The shipping option is not available in the cart's region" - ) - }) - - it("fails if reqs are not satisfied", async () => { - const data = { some: "thing" } - const cart = { - region_id: IdMap.getId("region"), - subtotal: 2, - } - - await expect( - optionService.createShippingMethod(IdMap.getId("validId"), data, { - cart, - }) - ).rejects.toThrow( - "The Cart does not satisfy the shipping option's requirements" - ) - }) - }) - - describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] createShippingMethod", () => { - const option = (id) => ({ - id, - region_id: IdMap.getId("region"), - price_type: "flat_rate", - amount: 10, - includes_tax: true, - data: { - something: "yes", - }, - requirements: [ - { - type: "min_subtotal", - amount: 100, - }, - ], - }) - const shippingOptionRepository = MockRepository({ - findOne: (q) => { - switch (q.where.id) { - default: - return Promise.resolve(option(q.where.id)) - } - }, - }) - const shippingMethodRepository = MockRepository({ create: (r) => r }) - const totalsService = { - getSubtotal: (c) => { - return c.subtotal - }, - } - - const providerService = { - validateFulfillmentData: jest - .fn() - .mockImplementation((r) => Promise.resolve(r.data)), - getPrice: (d) => d.price, - } - - const optionService = new ShippingOptionService({ - manager: MockManager, - shippingMethodRepository, - shippingOptionRepository, - totalsService, - fulfillmentProviderService: providerService, - featureFlagRouter: new FlagRouter({ - [TaxInclusivePricingFeatureFlag.key]: true, - }), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("should create a shipping method that also includes the taxes", async () => { - await optionService.createShippingMethod("random_id", {}, { price: 10 }) - expect(shippingMethodRepository.save).toHaveBeenCalledWith( - expect.objectContaining({ - includes_tax: true, - }) - ) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/shipping-profile.js b/packages/medusa/src/services/__tests__/shipping-profile.js deleted file mode 100644 index 8df12303c2..0000000000 --- a/packages/medusa/src/services/__tests__/shipping-profile.js +++ /dev/null @@ -1,374 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import ShippingProfileService from "../shipping-profile" - -describe("ShippingProfileService", () => { - describe("retrieve", () => { - describe("successfully get profile", () => { - afterAll(() => { - jest.clearAllMocks() - }) - - it("calls model layer findOne", async () => { - const profRepo = MockRepository({ - findOne: () => Promise.resolve({}), - }) - const profileService = new ShippingProfileService({ - manager: MockManager, - shippingProfileRepository: profRepo, - featureFlagRouter: new FlagRouter({}), - }) - - await profileService.retrieve(IdMap.getId("validId")) - - expect(profRepo.findOne).toHaveBeenCalledTimes(1) - expect(profRepo.findOne).toHaveBeenCalledWith({ - where: { id: IdMap.getId("validId") }, - }) - }) - }) - }) - - describe("update", () => { - const profRepo = MockRepository({ - findOne: (q) => { - return Promise.resolve({ id: q.where.id }) - }, - }) - - const productService = { - updateShippingProfile: jest.fn(), - withTransaction: function () { - return this - }, - } - - const shippingOptionService = { - updateShippingProfile: jest.fn(), - withTransaction: function () { - return this - }, - } - - const profileService = new ShippingProfileService({ - manager: MockManager, - shippingProfileRepository: profRepo, - productService, - shippingOptionService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("calls updateOne with correct params", async () => { - const id = IdMap.getId("validId") - - await profileService.update(id, { name: "new title" }) - - expect(profRepo.save).toBeCalledTimes(1) - expect(profRepo.save).toBeCalledWith({ id, name: "new title" }) - }) - - it("calls updateOne products", async () => { - const id = IdMap.getId("validId") - - await profileService.update(id, { - products: [IdMap.getId("product1")], - }) - - expect(productService.updateShippingProfile).toBeCalledTimes(1) - expect(productService.updateShippingProfile).toBeCalledWith( - [IdMap.getId("product1")], - id - ) - }) - - it("calls updateOne with shipping options", async () => { - const id = IdMap.getId("profile1") - - await profileService.update(id, { - shipping_options: [IdMap.getId("validId")], - }) - - expect(shippingOptionService.updateShippingProfile).toBeCalledTimes(1) - expect(shippingOptionService.updateShippingProfile).toBeCalledWith( - [IdMap.getId("validId")], - id - ) - }) - }) - - describe("delete", () => { - const profRepo = MockRepository({ - findOne: (q) => { - return Promise.resolve({ id: q.where.id }) - }, - }) - const profileService = new ShippingProfileService({ - manager: MockManager, - shippingProfileRepository: profRepo, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("deletes the profile successfully", async () => { - await profileService.delete(IdMap.getId("validId")) - - expect(profRepo.softRemove).toBeCalledTimes(1) - expect(profRepo.softRemove).toBeCalledWith({ - id: IdMap.getId("validId"), - }) - }) - }) - - describe("addProduct", () => { - const profRepo = MockRepository({ findOne: () => Promise.resolve({}) }) - - const productService = { - updateShippingProfile: jest.fn(), - withTransaction: function () { - return this - }, - } - - const profileService = new ShippingProfileService({ - manager: MockManager, - shippingProfileRepository: profRepo, - productService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("add product to profile successfully", async () => { - await profileService.addProduct(IdMap.getId("validId"), [ - IdMap.getId("product2"), - ]) - - expect(productService.updateShippingProfile).toBeCalledTimes(1) - expect(productService.updateShippingProfile).toBeCalledWith( - [IdMap.getId("product2")], - IdMap.getId("validId") - ) - }) - }) - - describe("fetchCartOptions", () => { - const profRepo = MockRepository({ - find: (q) => { - switch (q.where.id) { - default: - return Promise.resolve([ - { - shipping_options: [], - }, - ]) - } - }, - }) - - const shippingOptionService = { - list: jest.fn().mockImplementation(({ id }) => { - if (id && id.includes("test-option")) { - return Promise.resolve([ - { - id: "test-option", - amount: 1000, - name: "Test option", - }, - ]) - } - return Promise.resolve([ - { - id: "ship_1", - }, - { - id: "ship_2", - }, - ]) - }), - validateCartOption: jest.fn().mockImplementation(async (s) => s), - withTransaction: function () { - return this - }, - } - - const customShippingOptionService = { - withTransaction: function () { - return this - }, - list: jest.fn().mockImplementation(({ cart_id }, config) => { - if (cart_id === "cso-cart") { - return Promise.resolve([ - { - id: "cso_1", - cart_id: "cso-cart", - shipping_option_id: "test-option", - price: 0, - }, - ]) - } - return Promise.resolve([]) - }), - } - - const profileService = new ShippingProfileService({ - manager: MockManager, - shippingProfileRepository: profRepo, - shippingOptionService, - customShippingOptionService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("given a cart with custom shipping options, should return correct custom shipping options ", async () => { - const cart = { - id: "cso-cart", - items: [ - { - variant: { - product: { - _id: IdMap.getId("product_1"), - profile_id: IdMap.getId("profile"), - }, - }, - }, - { - variant: { - product: { - _id: IdMap.getId("product_2"), - profile_id: IdMap.getId("profile"), - }, - }, - }, - ], - type: "swap", - } - - await expect(profileService.fetchCartOptions(cart)).resolves.toEqual([ - expect.objectContaining({ - id: "test-option", - amount: 0, - name: "Test option", - }), - ]) - }) - - it("given a cart with no custom shipping options, should return normal shipping options", async () => { - const cart = { - items: [ - { - variant: { - product: { - _id: IdMap.getId("product_1"), - profile_id: IdMap.getId("profile"), - }, - }, - }, - { - variant: { - product: { - _id: IdMap.getId("product_2"), - profile_id: IdMap.getId("profile"), - }, - }, - }, - ], - } - - await expect(profileService.fetchCartOptions(cart)).resolves.toEqual([ - { id: "ship_1" }, - { id: "ship_2" }, - ]) - - expect(shippingOptionService.validateCartOption).toBeCalledTimes(2) - expect(shippingOptionService.validateCartOption).toBeCalledWith( - { id: "ship_1" }, - cart - ) - expect(shippingOptionService.validateCartOption).toBeCalledWith( - { id: "ship_2" }, - cart - ) - }) - }) - - describe("addShippingOption", () => { - const profRepo = MockRepository({ findOne: () => Promise.resolve({}) }) - - const shippingOptionService = { - updateShippingProfile: jest.fn(), - withTransaction: function () { - return this - }, - } - - const profileService = new ShippingProfileService({ - manager: MockManager, - shippingProfileRepository: profRepo, - shippingOptionService, - featureFlagRouter: new FlagRouter({}), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("add shipping option to profile successfully", async () => { - await profileService.addShippingOption(IdMap.getId("validId"), [ - IdMap.getId("freeShipping"), - ]) - - expect(shippingOptionService.updateShippingProfile).toBeCalledTimes(1) - expect(shippingOptionService.updateShippingProfile).toBeCalledWith( - [IdMap.getId("freeShipping")], - IdMap.getId("validId") - ) - }) - }) - - describe("create", () => { - const profRepo = MockRepository() - const profileService = new ShippingProfileService({ - manager: MockManager, - shippingProfileRepository: profRepo, - featureFlagRouter: new FlagRouter({}), - }) - - afterEach(() => { - jest.clearAllMocks() - }) - - it("successfully creates a new shipping profile", async () => { - await profileService.create({ - name: "New Profile", - }) - - expect(profRepo.create).toHaveBeenCalledTimes(1) - expect(profRepo.create).toHaveBeenCalledWith({ - name: "New Profile", - }) - }) - - it("throws if trying to create with products", async () => { - await expect( - profileService.create({ - name: "New Profile", - products: ["144"], - }) - ).rejects.toThrow( - "Please add products and shipping_options after creating Shipping Profiles" - ) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/store.js b/packages/medusa/src/services/__tests__/store.js deleted file mode 100644 index ca25598874..0000000000 --- a/packages/medusa/src/services/__tests__/store.js +++ /dev/null @@ -1,214 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import StoreService from "../store" - -describe("StoreService", () => { - describe("create", () => { - const storeRepository = MockRepository({}) - const currencyRepository = MockRepository({ - findOne: () => Promise.resolve({ code: "usd" }), - }) - - const storeService = new StoreService({ - manager: MockManager, - storeRepository, - currencyRepository, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully creates store with default currency", async () => { - await storeService.create() - - expect(storeRepository.create).toHaveBeenCalledTimes(1) - expect(storeRepository.save).toHaveBeenCalledTimes(1) - expect(currencyRepository.findOne).toHaveBeenCalledTimes(1) - - expect(storeRepository.save).toHaveBeenCalledWith({ - currencies: [{ code: "usd" }], - }) - }) - }) - - describe("retrieve", () => { - const storeRepository = MockRepository({}) - - const storeService = new StoreService({ - manager: MockManager, - storeRepository, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully retrieve store", async () => { - await storeService.retrieve().catch(() => void 0) - - expect(storeRepository.find).toHaveBeenCalledTimes(1) - }) - }) - - describe("update", () => { - const storeRepository = MockRepository({ - find: () => - Promise.resolve([ - { - id: IdMap.getId("store"), - name: "Medusa", - default_currency_code: "usd", - }, - ]), - }) - - const currencyRepository = MockRepository({}) - - const storeService = new StoreService({ - manager: MockManager, - storeRepository, - currencyRepository, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully updates store", async () => { - await storeService.update({ - name: "Medusa Commerce", - }) - - expect(storeRepository.find).toHaveBeenCalledTimes(1) - - expect(storeRepository.save).toHaveBeenCalledTimes(1) - expect(storeRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("store"), - name: "Medusa Commerce", - default_currency_code: "usd", - }) - }) - - it("fails if currency not ok", async () => { - await expect( - storeService.update({ - currencies: ["1cd", "usd"], - }) - ).rejects.toThrow("Currency with code 1cd does not exist") - - expect(storeRepository.find).toHaveBeenCalledTimes(1) - }) - }) - - describe("addCurrency", () => { - const storeRepository = MockRepository({ - find: () => - Promise.resolve([ - { - id: IdMap.getId("store"), - name: "Medusa", - currencies: [{ code: "dkk" }], - }, - ]), - }) - - const currencyRepository = MockRepository({ - findOne: (query) => { - if (query.where.code === "sek") { - return Promise.resolve({ code: "sek" }) - } - - if (query.where.code === "dkk") { - return Promise.resolve({ code: "dkk" }) - } - return Promise.resolve() - }, - }) - - const storeService = new StoreService({ - manager: MockManager, - storeRepository, - currencyRepository, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully adds currency", async () => { - await storeService.addCurrency("sek") - - expect(storeRepository.find).toHaveBeenCalledTimes(1) - - expect(storeRepository.save).toHaveBeenCalledTimes(1) - expect(storeRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("store"), - name: "Medusa", - currencies: [{ code: "dkk" }, { code: "sek" }], - }) - }) - - it("fails if currency not ok", async () => { - await expect(storeService.addCurrency("1cd")).rejects.toThrow( - "Currency 1cd not found" - ) - }) - - it("fails if currency already existis", async () => { - await expect(storeService.addCurrency("dkk")).rejects.toThrow( - "Currency already added" - ) - - expect(storeRepository.find).toHaveBeenCalledTimes(1) - }) - }) - - describe("removeCurrency", () => { - const storeRepository = MockRepository({ - find: () => - Promise.resolve([ - { - id: IdMap.getId("store"), - name: "Medusa", - currencies: [{ code: "dkk" }], - }, - ]), - }) - - const currencyRepository = MockRepository({ - findOne: (query) => { - if (query.where.code === "sek") { - return Promise.resolve({ code: "sek" }) - } - - if (query.where.code === "dkk") { - return Promise.resolve({ code: "dkk" }) - } - return Promise.resolve() - }, - }) - - const storeService = new StoreService({ - manager: MockManager, - storeRepository, - currencyRepository, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("successfully removes currency", async () => { - await storeService.removeCurrency("dkk") - - expect(storeRepository.find).toHaveBeenCalledTimes(1) - - expect(storeRepository.save).toHaveBeenCalledTimes(1) - expect(storeRepository.save).toHaveBeenCalledWith({ - id: IdMap.getId("store"), - currencies: [], - name: "Medusa", - }) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/swap.ts b/packages/medusa/src/services/__tests__/swap.ts deleted file mode 100644 index 5f787586dd..0000000000 --- a/packages/medusa/src/services/__tests__/swap.ts +++ /dev/null @@ -1,1285 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { Order, Swap } from "../../models" -import { SwapRepository } from "../../repositories/swap" -import CartService from "../cart" -import EventBusService from "../event-bus" -import { - CustomShippingOptionService, - FulfillmentService, - LineItemService, - OrderService, - PaymentProviderService, - ProductVariantInventoryService, - ReturnService, - ShippingOptionService, - TotalsService, -} from "../index" -import LineItemAdjustmentService from "../line-item-adjustment" -import SwapService from "../swap" -import { LineItemAdjustmentServiceMock } from "../__mocks__/line-item-adjustment" -import { ProductVariantInventoryServiceMock } from "../__mocks__/product-variant-inventory" - -/* ******************** DEFAULT REPOSITORY MOCKS ******************** */ - -const swapRepo = MockRepository({ - findOne: (existing) => Promise.resolve(existing), - create: jest.fn().mockImplementation((data) => { - return Object.assign(new Swap(), data) - }), -}) - -/* ******************** DEFAULT SERVICE MOCKS ******************** */ - -const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - return this - }, -} as unknown as EventBusService - -const cartService = { - create: jest.fn().mockReturnValue(Promise.resolve({ id: "cart" })), - retrieve: jest - .fn() - .mockReturnValue( - Promise.resolve({ id: "cart", items: [{ id: "test-item" }] }) - ), - update: jest.fn().mockReturnValue(Promise.resolve()), - withTransaction: function () { - return this - }, - retrieveWithTotals: jest - .fn() - .mockReturnValue(Promise.resolve({ id: "cart" })), -} as unknown as CartService - -const customShippingOptionService = { - create: jest.fn().mockReturnValue(Promise.resolve({ id: "cso-test" })), - update: jest.fn().mockReturnValue(Promise.resolve()), - withTransaction: function () { - return this - }, -} as unknown as CustomShippingOptionService - -const lineItemService = { - create: jest.fn().mockImplementation((d) => Promise.resolve(d)), - update: jest.fn().mockImplementation((d) => Promise.resolve(d)), - retrieve: () => Promise.resolve({}), - list: () => Promise.resolve([]), - createReturnLines: jest.fn(() => Promise.resolve()), - withTransaction: function () { - return this - }, -} as unknown as LineItemService - -const totalsService = { - getTotal: () => { - return Promise.resolve(100) - }, -} as unknown as TotalsService - -const shippingOptionService = { - updateShippingMethod: () => { - return Promise.resolve() - }, - withTransaction: function () { - return this - }, -} as unknown as ShippingOptionService - -const paymentProviderService = { - getStatus: jest.fn(() => { - return Promise.resolve("authorized") - }), - updatePayment: jest.fn(() => { - return Promise.resolve() - }), - cancelPayment: jest.fn(() => { - return Promise.resolve() - }), - withTransaction: function () { - return this - }, -} as unknown as PaymentProviderService - -const orderService = {} as unknown as OrderService -const returnService = {} as unknown as ReturnService -const productVariantInventoryService = - {} as unknown as ProductVariantInventoryService -const fulfillmentService = {} as unknown as FulfillmentService -const lineItemAdjustmentService = {} as unknown as LineItemAdjustmentService - -const defaultProps = { - manager: MockManager, - swapRepository: swapRepo, - - cartService: cartService, - eventBus: eventBusService, - orderService: orderService, - returnService: returnService, - totalsService: totalsService, - eventBusService: eventBusService, - lineItemService: lineItemService, - productVariantInventoryService: productVariantInventoryService, - fulfillmentService: fulfillmentService, - shippingOptionService: shippingOptionService, - paymentProviderService: paymentProviderService, - lineItemAdjustmentService: lineItemAdjustmentService, - customShippingOptionService: customShippingOptionService, -} - -const generateOrder = (orderId, items, additional = {}): Order => { - return { - id: IdMap.getId(orderId), - items: items.map( - ({ - id, - product_id, - variant_id, - fulfilled, - returned, - quantity, - price, - }) => ({ - id: IdMap.getId(id), - variant_id: IdMap.getId(variant_id), - variant: { - id: IdMap.getId(variant_id), - product: { - id: IdMap.getId(product_id), - }, - }, - unit_price: price, - quantity, - fulfilled_quantity: fulfilled || 0, - returned_quantity: returned || 0, - }) - ), - ...additional, - } as Order -} - -const testOrder = generateOrder( - "test", - [ - { - id: "line", - product_id: "product", - variant_id: "variant", - price: 100, - quantity: 2, - fulfilled: 1, - }, - ], - { - fulfillment_status: "fulfilled", - payment_status: "captured", - currency_code: "dkk", - region_id: IdMap.getId("region"), - tax_rate: 0, - no_notification: true, - shipping_address: { - first_name: "test", - last_name: "testson", - address_1: "1800 test st", - city: "testville", - province: "test", - country_code: "us", - postal_code: "12345", - phone: "+18001231234", - }, - } -) - -describe("SwapService", () => { - describe("createCart", () => { - beforeEach(() => { - jest.clearAllMocks() - }) - - describe("success", () => { - const existing = { - id: IdMap.getId("test-swap"), - order_id: IdMap.getId("test"), - order: testOrder, - return_order: { - id: IdMap.getId("return-swap"), - test: "notreceived", - refund_amount: 11, - items: [{ item_id: IdMap.getId("line"), quantity: 1 }], - }, - additional_items: [{ id: "test" }], - other: "data", - } - - const cartService = { - create: jest.fn().mockReturnValue(Promise.resolve({ id: "cart" })), - retrieve: jest - .fn() - .mockReturnValue( - Promise.resolve({ id: "cart", items: [{ id: "test-item" }] }) - ), - update: jest.fn().mockReturnValue(Promise.resolve()), - withTransaction: function () { - return this - }, - } as unknown as CartService - - const swapRepo = MockRepository({ - findOne: () => Promise.resolve(existing), - }) - - const customShippingOptionService = { - create: jest.fn().mockReturnValue(Promise.resolve({ id: "cso-test" })), - update: jest.fn().mockReturnValue(Promise.resolve()), - withTransaction: function () { - return this - }, - } as unknown as CustomShippingOptionService - - const lineItemService = { - create: jest.fn().mockImplementation((d) => Promise.resolve(d)), - update: jest.fn().mockImplementation((d) => Promise.resolve(d)), - retrieve: () => Promise.resolve({}), - list: () => Promise.resolve([]), - createReturnLines: jest.fn(() => Promise.resolve()), - withTransaction: function () { - return this - }, - } as unknown as LineItemService - - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - eventBusService, - swapRepository: swapRepo, - cartService, - lineItemService, - customShippingOptionService, - lineItemAdjustmentService: - LineItemAdjustmentServiceMock as unknown as LineItemAdjustmentService, - }) - - it("finds swap and calls return create cart", async () => { - await swapService.createCart(IdMap.getId("swap-1"), [ - { option_id: "test-option", price: 10 }, - ]) - - expect(swapRepo.findOne).toHaveBeenCalledTimes(1) - expect(swapRepo.findOne).toHaveBeenCalledWith({ - relations: { - additional_items: { - variant: true, - }, - order: { - claims: { - additional_items: true, - }, - discounts: { - rule: true, - }, - items: { - variant: { - product: { - profiles: true, - }, - }, - }, - swaps: { - additional_items: true, - }, - }, - return_order: { - items: true, - shipping_method: { - shipping_option: true, - tax_lines: true, - }, - }, - }, - where: { id: IdMap.getId("swap-1") }, - }) - - expect(lineItemService.createReturnLines).toHaveBeenCalledTimes(1) - expect(lineItemService.createReturnLines).toHaveBeenCalledWith( - expect.any(String), - "cart" - ) - - expect(cartService.create).toHaveBeenCalledTimes(1) - expect(cartService.create).toHaveBeenCalledWith({ - email: testOrder.email, - discounts: testOrder.discounts, - region_id: testOrder.region_id, - customer_id: testOrder.customer_id, - type: "swap", - metadata: { - swap_id: IdMap.getId("test-swap"), - parent_order_id: IdMap.getId("test"), - }, - }) - - expect(cartService.create).toHaveBeenCalledTimes(1) - // expect(cartService.update).toHaveBeenCalledTimes(1) - - expect(lineItemService.update).toHaveBeenCalledTimes(1) - expect(lineItemService.update).toHaveBeenCalledWith("test", { - cart_id: "cart", - }) - - expect( - LineItemAdjustmentServiceMock.createAdjustmentForLineItem - ).toHaveBeenCalledTimes(1) - expect( - LineItemAdjustmentServiceMock.createAdjustmentForLineItem - ).toHaveBeenCalledWith( - { - id: "cart", - items: [ - { - id: "test-item", - }, - ], - }, - { - id: "test-item", - } - ) - - expect(swapRepo.save).toHaveBeenCalledTimes(1) - expect(swapRepo.save).toHaveBeenCalledWith({ - ...existing, - cart_id: "cart", - }) - }) - }) - - describe("failure", () => { - const existing = { - return_order: { - id: IdMap.getId("return-swap"), - test: "notreceived", - refund_amount: 11, - }, - additional_items: [{ data: "lines" }], - other: "data", - } - - const swapRepo = MockRepository({ - findOne: (query) => { - switch (query.where.id) { - case IdMap.getId("canceled"): - return Promise.resolve({ - canceled_at: new Date(), - }) - default: - return Promise.resolve({ - ...existing, - order_id: IdMap.getId("test"), - cart_id: IdMap.getId("swap-cart"), - }) - } - }, - }) - - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - eventBusService, - swapRepository: swapRepo, - }) - - it("fails if cart already created", async () => { - const res = swapService.createCart(IdMap.getId("swap-1")) - - await expect(res).rejects.toThrow( - "A cart has already been created for the swap" - ) - }) - - it("fails if swap is canceled", async () => { - await expect( - swapService.createCart(IdMap.getId("canceled")) - ).rejects.toThrow("Canceled swap cannot be used to create a cart") - }) - }) - }) - - describe("create", () => { - beforeEach(() => { - jest.clearAllMocks() - }) - - describe("success", () => { - const lineItemService = { - generate: jest.fn().mockImplementation(({ variantId, quantity }) => { - return { - unit_price: 100, - variant_id: variantId, - quantity, - } - }), - retrieve: () => Promise.resolve({}), - list: () => Promise.resolve([]), - withTransaction: function () { - return this - }, - } as unknown as LineItemService - - const returnService = { - create: jest.fn().mockReturnValue(Promise.resolve({ id: "ret" })), - withTransaction: function () { - return this - }, - } as unknown as ReturnService - - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - eventBusService, - swapRepository: swapRepo, - returnService, - lineItemService, - }) - - it("generates lines items", async () => { - await swapService.create( - testOrder, - [{ item_id: IdMap.getId("line"), quantity: 1 }], - [{ variant_id: IdMap.getId("new-variant"), quantity: 1 }], - { - option_id: IdMap.getId("return-shipping"), - price: 20, - } - ) - - expect(lineItemService.generate).toHaveBeenCalledTimes(1) - expect(lineItemService.generate).toHaveBeenCalledWith( - { - quantity: 1, - variantId: IdMap.getId("new-variant"), - }, - { - cart: undefined, - region_id: IdMap.getId("region"), - } - ) - }) - - it("creates swap", async () => { - await swapService.create( - testOrder, - [{ item_id: IdMap.getId("line"), quantity: 1 }], - [{ variant_id: IdMap.getId("new-variant"), quantity: 1 }], - { - option_id: IdMap.getId("return-shipping"), - price: 20, - } - ) - - expect(swapRepo.create).toHaveBeenCalledWith({ - order_id: IdMap.getId("test"), - fulfillment_status: "not_fulfilled", - payment_status: "not_paid", - no_notification: true, - additional_items: [ - { - unit_price: 100, - variant_id: IdMap.getId("new-variant"), - quantity: 1, - }, - ], - }) - - expect(returnService.create).toHaveBeenCalledTimes(1) - }) - - it.each([ - [true, true], - [false, false], - [undefined, true], - ])( - "passes correct no_notification to eventBus with %s", - async (input, expected) => { - await swapService.create( - testOrder, - [{ item_id: IdMap.getId("line"), quantity: 1 }], - [{ variant_id: IdMap.getId("new-variant"), quantity: 1 }], - { - option_id: IdMap.getId("return-shipping"), - price: 20, - }, - { no_notification: input } - ) - - expect(eventBusService.emit).toHaveBeenCalledWith( - expect.any(String), - { id: undefined, no_notification: expected } - ) - } - ) - }) - }) - - describe("createFulfillment", () => { - beforeEach(() => { - jest.clearAllMocks() - }) - - describe("success", () => { - const fulfillmentService = { - createFulfillment: jest - .fn() - .mockReturnValue( - Promise.resolve([ - { items: [{ item_id: "1234", quantity: 2 }], data: "new" }, - ]) - ), - withTransaction: function () { - return this - }, - } as unknown as FulfillmentService - - const existing = { - fulfillment_status: "not_fulfilled", - order: testOrder, - additional_items: [ - { - id: "1234", - quantity: 2, - }, - ], - shipping_methods: [{ method: "1" }], - other: "data", - } - - const lineItemService = { - update: jest.fn(), - retrieve: () => Promise.resolve({}), - list: () => Promise.resolve([]), - withTransaction: function () { - return this - }, - } as unknown as LineItemService - - const swapRepo = MockRepository({ - findOne: () => Promise.resolve({ ...existing }), - }) - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - eventBusService, - swapRepository: swapRepo, - fulfillmentService, - lineItemService, - }) - - it("creates a fulfillment", async () => { - await swapService.createFulfillment(IdMap.getId("swap")) - - expect(lineItemService.update).toHaveBeenCalledTimes(1) - expect(lineItemService.update).toHaveBeenCalledWith("1234", { - fulfilled_quantity: 2, - }) - - expect(swapRepo.save).toHaveBeenCalledWith({ - ...existing, - fulfillment_status: "fulfilled", - fulfillments: [ - { items: [{ item_id: "1234", quantity: 2 }], data: "new" }, - ], - }) - - expect(fulfillmentService.createFulfillment).toHaveBeenCalledWith( - { - ...existing, - email: testOrder.email, - discounts: testOrder.discounts, - currency_code: testOrder.currency_code, - tax_rate: testOrder.tax_rate, - region_id: testOrder.region_id, - display_id: testOrder.display_id, - is_swap: true, - billing_address: testOrder.billing_address, - items: existing.additional_items, - shipping_methods: existing.shipping_methods, - }, - [{ item_id: "1234", quantity: 2 }], - { swap_id: IdMap.getId("swap"), metadata: {} } - ) - }) - }) - - describe("failure", () => { - const swapRepo = MockRepository({ - findOne: () => - Promise.resolve({ - canceled_at: new Date(), - }), - }) - - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - swapRepository: swapRepo, - }) - - it("fails when swap has been canceled", async () => { - await expect( - swapService.createFulfillment(IdMap.getId("swap"), {}) - ).rejects.toThrow("Canceled swap cannot be fulfilled") - }) - }) - }) - - describe("cancelFulfillment", () => { - const swapRepo = MockRepository({ - findOne: () => Promise.resolve({}), - save: (f) => Promise.resolve(f), - }) - - const fulfillmentService = { - cancelFulfillment: jest.fn().mockImplementation((f) => { - switch (f) { - case IdMap.getId("no-swap"): - return Promise.resolve({}) - default: - return Promise.resolve({ - swap_id: IdMap.getId("swap-id"), - }) - } - }), - withTransaction: function () { - return this - }, - } as unknown as FulfillmentService - - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - swapRepository: swapRepo, - fulfillmentService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully cancels fulfillment and corrects swap status", async () => { - await swapService.cancelFulfillment(IdMap.getId("swap")) - - expect(fulfillmentService.cancelFulfillment).toHaveBeenCalledTimes(1) - expect(fulfillmentService.cancelFulfillment).toHaveBeenCalledWith( - IdMap.getId("swap") - ) - - expect(swapRepo.save).toHaveBeenCalledTimes(1) - expect(swapRepo.save).toHaveBeenCalledWith({ - fulfillment_status: "canceled", - }) - }) - - it("fails to cancel fulfillment when not related to a swap", async () => { - await expect( - swapService.cancelFulfillment(IdMap.getId("no-swap")) - ).rejects.toThrow(`Fufillment not related to a swap`) - }) - }) - - describe("createShipment", () => { - beforeEach(() => { - jest.clearAllMocks() - }) - - describe("success", () => { - const fulfillmentService = { - createShipment: jest.fn().mockImplementation((o, f) => { - return Promise.resolve({ - items: [ - { - item_id: IdMap.getId("1234-1"), - quantity: 2, - }, - ], - data: "new", - }) - }), - withTransaction: function () { - return this - }, - } as unknown as FulfillmentService - - const existing = { - fulfillment_status: "not_fulfilled", - additional_items: [ - { - id: IdMap.getId("1234-1"), - quantity: 2, - shipped_quantity: 0, - }, - ], - fulfillments: [ - { - id: IdMap.getId("f1"), - items: [ - { - item_id: IdMap.getId("1234-1"), - quantity: 2, - }, - ], - }, - { - id: IdMap.getId("f2"), - items: [ - { - item_id: IdMap.getId("1234-2"), - quantity: 2, - }, - ], - }, - ], - shipping_methods: [{ method: "1" }], - other: "data", - } - - const cartService = { - update: jest.fn(), - retrieve: jest - .fn() - .mockReturnValue( - Promise.resolve({ id: "cart", items: [{ id: "test-item" }] }) - ), - withTransaction: function () { - return this - }, - } as unknown as CartService - - const swapRepo = MockRepository({ - findOne: () => Promise.resolve(existing), - }) - - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - eventBusService, - swapRepository: swapRepo, - lineItemService, - fulfillmentService, - cartService, - }) - - it("creates a shipment", async () => { - await swapService.createShipment( - IdMap.getId("swap"), - IdMap.getId("f1"), - [{ tracking_number: "1234" }], - {} - ) - - expect(lineItemService.update).toHaveBeenCalledWith( - IdMap.getId("1234-1"), - { - shipped_quantity: 2, - } - ) - - expect(swapRepo.save).toHaveBeenCalledWith({ - ...existing, - fulfillment_status: "shipped", - }) - - expect(fulfillmentService.createShipment).toHaveBeenCalledWith( - IdMap.getId("f1"), - [{ tracking_number: "1234" }], - {} - ) - }) - }) - - describe("failure", () => { - const swapRepo = MockRepository({ - findOne: () => Promise.resolve({ canceled_at: new Date() }), - }) - - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - swapRepository: swapRepo, - }) - - it("fails when swap is canceled", async () => { - await expect( - swapService.createShipment( - IdMap.getId("swap"), - IdMap.getId("fulfillment") - ) - ).rejects.toThrow("Canceled swap cannot be fulfilled as shipped") - }) - }) - }) - - describe("registerCartCompletion", () => { - beforeEach(() => { - jest.clearAllMocks() - Date.now = jest.fn(() => 1572393600000) - }) - - const totalsService = { - getTotal: () => { - return Promise.resolve(100) - }, - } as unknown as TotalsService - - const shippingOptionService = { - updateShippingMethod: () => { - return Promise.resolve() - }, - withTransaction: function () { - return this - }, - } as unknown as ShippingOptionService - - const cartService = { - retrieve: jest.fn().mockReturnValue( - Promise.resolve({ - id: "cart", - items: [{ id: "test-item", variant_id: "variant" }], - }) - ), - update: () => { - return Promise.resolve() - }, - withTransaction: function () { - return this - }, - retrieveWithTotals: jest.fn().mockReturnValue( - Promise.resolve({ - id: "cart", - items: [{ id: "test-item", variant_id: "variant" }], - }) - ), - } as unknown as CartService - - const paymentProviderService = { - getStatus: jest.fn(() => { - return Promise.resolve("authorized") - }), - updatePayment: jest.fn(() => { - return Promise.resolve() - }), - cancelPayment: jest.fn(() => { - return Promise.resolve() - }), - withTransaction: function () { - return this - }, - } as unknown as PaymentProviderService - - const productVariantInventoryService = { - ...ProductVariantInventoryServiceMock, - withTransaction: function () { - return this - }, - } as unknown as ProductVariantInventoryService - - describe("success", () => { - const cart = { - items: [{ id: "1", variant_id: "variant", quantity: 2 }], - shipping_methods: [{ id: "method_1" }], - payment: { - good: "yes", - }, - shipping_address_id: 1234, - total: 1, - } - const existing = { - other: "data", - } - - cartService.retrieveWithTotals = (() => - cart) as unknown as CartService["retrieveWithTotals"] - - const swapRepo = MockRepository({ - findOne: () => Promise.resolve(existing), - }) - - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - eventBusService, - swapRepository: swapRepo, - totalsService, - cartService, - paymentProviderService, - shippingOptionService, - productVariantInventoryService, - }) - - it("creates a shipment", async () => { - await swapService.registerCartCompletion(IdMap.getId("swap")) - - expect(paymentProviderService.getStatus).toHaveBeenCalledWith({ - good: "yes", - }) - - expect( - productVariantInventoryService.reserveQuantity - ).toHaveBeenCalledWith("variant", 2, { - lineItemId: "1", - salesChannelId: undefined, - }) - - expect(swapRepo.save).toHaveBeenCalledWith({ - ...existing, - difference_due: 1, - shipping_address_id: 1234, - confirmed_at: expect.anything(), - }) - }) - }) - - describe("failure", () => { - const existing = { - cart: { - items: [{ id: "1", variant_id: "variant", quantity: 25 }], - shipping_methods: [{ id: "method_1" }], - payment: { - good: "yes", - }, - shipping_address_id: 1234, - }, - other: "data", - } - - const swapRepo = MockRepository({ - findOne: (q) => { - switch (q.where.id) { - case IdMap.getId("canceled"): - return Promise.resolve({ canceled_at: new Date() }) - default: - return Promise.resolve(existing) - } - }, - }) as unknown as typeof SwapRepository - - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - eventBusService, - swapRepository: swapRepo, - totalsService, - cartService, - paymentProviderService, - shippingOptionService, - productVariantInventoryService, - }) - - it("fails to register cart completion when swap is canceled", async () => { - await expect( - swapService.registerCartCompletion(IdMap.getId("canceled")) - ).rejects.toThrow("Cart related to canceled swap cannot be completed") - }) - it("throws an error because inventory is to low", async () => { - try { - await swapService.registerCartCompletion(IdMap.getId("swap")) - } catch (e) { - expect(e.message).toEqual( - `Variant with id: variant does not have the required inventory` - ) - } - }) - }) - }) - - describe("processDifference", () => { - beforeEach(() => { - jest.clearAllMocks() - }) - - describe("success", () => { - const paymentProviderService = { - capturePayment: jest.fn((g) => - g.id === "good" ? Promise.resolve() : Promise.reject() - ), - refundPayment: jest.fn((g) => - g[0].id === "good" ? Promise.resolve() : Promise.reject() - ), - withTransaction: function () { - return this - }, - } as unknown as PaymentProviderService - - const existing = (dif, fail, conf = true) => ({ - confirmed_at: conf ? "1234" : null, - difference_due: dif, - payment: { id: fail ? "f" : "good" }, - order: { - payments: [{ id: fail ? "f" : "good" }], - }, - }) - - const swapRepo = MockRepository({ - findOne: (q) => { - switch (q.where.id) { - case "refund": - return Promise.resolve(existing(-1, false)) - case "refund_fail": - return Promise.resolve(existing(-1, true)) - case "capture_fail": - return Promise.resolve(existing(1, true)) - case "0": - return Promise.resolve(existing(0, false)) - case "not_conf": - return Promise.resolve(existing(1, false, false)) - case "canceled": - return Promise.resolve({ canceled_at: new Date() }) - default: - return Promise.resolve(existing(1, false)) - } - }, - create: jest.fn().mockImplementation((data) => { - return Object.assign(new Swap(), data) - }), - save: jest.fn().mockImplementation((data) => { - return Object.assign(new Swap(), data) - }), - }) - - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - swapRepository: swapRepo, - paymentProviderService, - eventBusService, - }) - - it("capture success", async () => { - await swapService.processDifference(IdMap.getId("swap")) - expect(paymentProviderService.capturePayment).toHaveBeenCalledWith({ - id: "good", - }) - - expect(swapRepo.save).toHaveBeenCalledWith({ - ...existing(1, false), - payment_status: "captured", - }) - }) - - it("capture fail", async () => { - await swapService.processDifference("capture_fail") - expect(paymentProviderService.capturePayment).toHaveBeenCalledWith({ - id: "f", - }) - - expect(swapRepo.save).toHaveBeenCalledWith({ - ...existing(1, true), - payment_status: "requires_action", - }) - }) - - it("refund success", async () => { - await swapService.processDifference("refund") - expect(paymentProviderService.refundPayment).toHaveBeenCalledWith( - [ - { - id: "good", - }, - ], - 1, - "swap" - ) - - expect(swapRepo.save).toHaveBeenCalledWith({ - ...existing(-1, false), - payment_status: "difference_refunded", - }) - }) - - it("refund fail", async () => { - await swapService.processDifference("refund_fail") - - expect(paymentProviderService.refundPayment).toHaveBeenCalledWith( - [ - { - id: "f", - }, - ], - 1, - "swap" - ) - - expect(swapRepo.save).toHaveBeenCalledWith({ - ...existing(-1, true), - payment_status: "requires_action", - }) - }) - - it("fails as swap is canceled", async () => { - await expect(swapService.processDifference("canceled")).rejects.toThrow( - "Canceled swap cannot be processed" - ) - }) - - it("zero", async () => { - await swapService.processDifference("0") - expect(swapRepo.save).toHaveBeenCalledWith({ - ...existing(0, false), - payment_status: "difference_refunded", - }) - }) - - it("not confirmed", async () => { - await expect(swapService.processDifference("not_conf")).rejects.toThrow( - "Cannot process a swap that hasn't been confirmed by the customer" - ) - }) - }) - - describe("registerReceived", () => { - beforeEach(async () => { - jest.clearAllMocks() - }) - - const swapRepo = MockRepository({ - findOne: (q) => { - switch (q.where.id) { - case "requested": - return Promise.resolve({ - id: "requested", - order_id: IdMap.getId("order"), - return_order: { status: "requested" }, - }) - case "received": - return Promise.resolve({ - id: "received", - order_id: IdMap.getId("order"), - return_order: { status: "received" }, - }) - case "canceled": - return Promise.resolve({ - canceled_at: new Date(), - }) - default: - return Promise.resolve() - } - }, - }) - - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - swapRepository: swapRepo, - eventBusService, - }) - - it("fails if swap doesn't have status received", async () => { - const res = swapService.registerReceived("requested") - await expect(res).rejects.toThrow("Swap is not received") - }) - - it("registers a swap as received", async () => { - await swapService.registerReceived("received") - - expect(eventBusService.emit).toHaveBeenCalledTimes(1) - }) - - it("fails to register as received when swap is canceled", async () => { - await expect(swapService.registerReceived("canceled")).rejects.toThrow( - "Canceled swap cannot be registered as received" - ) - }) - }) - }) - - describe("cancel", () => { - const now = new Date() - const payment = { id: IdMap.getId("payment") } - const return_order = { status: "canceled" } - const fulfillment = { canceled_at: now } - - const swapRepo = MockRepository({ - findOne: (q) => { - const swap: any = { - payment: { ...payment }, - return_order: { ...return_order }, - fulfillments: [{ ...fulfillment }, { ...fulfillment }], - } - - switch (q.where.id) { - case IdMap.getId("fail-fulfillment"): - swap.fulfillments[1].canceled_at = undefined - return Promise.resolve(swap) - case IdMap.getId("fail-return"): - swap.return_order.status = "received" - return Promise.resolve(swap) - case IdMap.getId("fail-refund-1"): - swap.payment_status = "difference_refunded" - return Promise.resolve(swap) - case IdMap.getId("fail-refund-2"): - swap.payment_status = "partially_refunded" - return Promise.resolve(swap) - case IdMap.getId("fail-refund-3"): - swap.payment_status = "refunded" - return Promise.resolve(swap) - default: - return Promise.resolve(swap) - } - }, - save: (f) => f, - }) - - const swapService = new SwapService({ - ...defaultProps, - manager: MockManager, - swapRepository: swapRepo, - paymentProviderService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully cancels valid swap", async () => { - await swapService.cancel(IdMap.getId("complete")) - - expect(swapRepo.save).toHaveBeenCalledTimes(1) - expect(swapRepo.save).toHaveBeenCalledWith({ - payment_status: "canceled", - fulfillment_status: "canceled", - canceled_at: expect.any(Date), - fulfillments: expect.anything(), - payment: expect.anything(), - return_order: expect.anything(), - }) - expect(paymentProviderService.cancelPayment).toHaveBeenCalledTimes(1) - expect(paymentProviderService.cancelPayment).toHaveBeenCalledWith({ - id: IdMap.getId("payment"), - }) - }) - - it("fails to cancel swap when fulfillment not canceled", async () => { - await expect( - swapService.cancel(IdMap.getId("fail-fulfillment")) - ).rejects.toThrow( - "All fulfillments must be canceled before the swap can be canceled" - ) - }) - - it("fails to cancel swap when return not canceled", async () => { - await expect( - swapService.cancel(IdMap.getId("fail-return")) - ).rejects.toThrow( - "Return must be canceled before the swap can be cancele" - ) - }) - - it.each([["fail-refund-1"], ["fail-refund-2"], ["fail-refund-3"]])( - "fails to cancel swap when contains refund", - async (input) => { - await expect(swapService.cancel(IdMap.getId(input))).rejects.toThrow( - "Swap with a refund cannot be canceled" - ) - } - ) - }) -}) diff --git a/packages/medusa/src/services/__tests__/system-tax.js b/packages/medusa/src/services/__tests__/system-tax.js deleted file mode 100644 index b032163790..0000000000 --- a/packages/medusa/src/services/__tests__/system-tax.js +++ /dev/null @@ -1,85 +0,0 @@ -import SystemTaxService from "../system-tax" - -describe("SystemTaxService", () => { - describe("getTaxLines", () => { - const taxService = new SystemTaxService() - - const calculationContext = { - region: {}, - customer: {}, - allocation_map: {}, - shipping_address: {}, - } - - test("success", async () => { - const lines = await taxService.getTaxLines( - [ - { - item: { id: "line_id" }, - rates: [ - { rate: 20, name: "test", code: "test" }, - { rate: 5.5, name: "test_2", code: "test_2" }, - ], - }, - ], - [], - calculationContext - ) - expect(lines).toEqual([ - { - item_id: "line_id", - rate: 20, - name: "test", - code: "test", - }, - { - item_id: "line_id", - rate: 5.5, - name: "test_2", - code: "test_2", - }, - ]) - }) - - test("success w. shipping", async () => { - const lines = await taxService.getTaxLines( - [ - { - item: { id: "line_id" }, - rates: [ - { rate: 20, name: "test", code: "test" }, - { rate: 5.5, name: "test_2", code: "test_2" }, - ], - }, - ], - [ - { - shipping_method: { id: "sm_id" }, - rates: [{ rate: 20, name: "test", code: "test" }], - }, - ], - calculationContext - ) - expect(lines).toEqual([ - { - item_id: "line_id", - rate: 20, - name: "test", - code: "test", - }, - { - item_id: "line_id", - rate: 5.5, - name: "test_2", - code: "test_2", - }, - { - shipping_method_id: "sm_id", - rate: 20, - name: "test", - code: "test", - }, - ]) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/tax-provider.js b/packages/medusa/src/services/__tests__/tax-provider.js deleted file mode 100644 index a17e3b7c97..0000000000 --- a/packages/medusa/src/services/__tests__/tax-provider.js +++ /dev/null @@ -1,257 +0,0 @@ -import { asValue, createContainer } from "awilix" -import { - defaultContainer, - getCacheKey, - getTaxLineFactory, -} from "../__fixtures__/tax-provider" - -describe("TaxProviderService", () => { - afterEach(() => { - jest.clearAllMocks() - }) - - describe("retrieveProvider", () => { - const providerService = defaultContainer.resolve("taxProviderService") - - it("successfully retrieves system provider", () => { - const provider = providerService.retrieveProvider({ - tax_provider_id: null, - }) - expect(provider).toEqual("system") - }) - - it("successfully retrieves external provider", () => { - const provider = providerService.retrieveProvider({ - tax_provider_id: "test", - }) - expect(provider).toEqual("good") - }) - - it("fails when payment provider not found", () => { - expect.assertions(1) - - try { - providerService.retrieveProvider({ tax_provider_id: "unregistered" }) - } catch (err) { - expect(err.message).toEqual( - "Could not find a tax provider with id: unregistered" - ) - } - }) - }) - - describe("getTaxLines", () => { - const mockCalculateLineItemTaxes = jest.fn(() => [ - { - rate: 5, - name: "test vat", - code: "test_vat", - item_id: "item_1", - }, - ]) - const container = createContainer({}, defaultContainer) - container.register( - "systemTaxService", - asValue({ - getTaxLines: mockCalculateLineItemTaxes, - }) - ) - - test("success", async () => { - const providerService = container.resolve("taxProviderService") - providerService.getRegionRatesForProduct = jest.fn(() => new Map()) - - const region = { id: "test", tax_provider_id: null } - const { cart, calculationContext: calcContext } = getTaxLineFactory({ - items: [{ id: "item_1", product_id: "prod_1" }], - region, - }) - - const expected = [ - { - item_id: "item_1", - rate: 5, - name: "test vat", - code: "test_vat", - metadata: undefined, - }, - ] - - const rates = await providerService.getTaxLines(cart.items, calcContext) - - expect(rates).toEqual(expected) - - const lineItemTaxLineRepository = container.resolve( - "lineItemTaxLineRepository" - ) - expect(lineItemTaxLineRepository.create).toHaveBeenCalledTimes(1) - expect(lineItemTaxLineRepository.create).toHaveBeenCalledWith(expected[0]) - - expect(providerService.getRegionRatesForProduct).toHaveBeenCalledTimes(1) - expect(providerService.getRegionRatesForProduct).toHaveBeenCalledWith( - ["prod_1"], - region - ) - - expect(mockCalculateLineItemTaxes).toHaveBeenCalledTimes(1) - expect(mockCalculateLineItemTaxes).toHaveBeenCalledWith( - [ - { - item: cart.items[0], - rates: [], - }, - ], - [], - calcContext - ) - }) - }) - - describe("getRegionRatesForProduct", () => { - const container = createContainer({}, defaultContainer) - container.register( - "taxRateService", - asValue({ - withTransaction: function () { - return this - }, - listByProduct: jest.fn(() => Promise.resolve([])), - }) - ) - - test("success", async () => { - const providerService = container.resolve("taxProviderService") - - const productId = "prod_id" - - const rates = await providerService.getRegionRatesForProduct(productId, { - id: "reg_id", - tax_rates: [], - tax_rate: 12.5, - }) - - const expected = [ - { - rate: 12.5, - name: "default", - code: "default", - }, - ] - expect(rates.get(productId)).toEqual(expected) - - const cacheService = container.resolve("cacheService") - const cacheKey = getCacheKey(productId, "reg_id") - - expect(cacheService.get).toHaveBeenCalledTimes(1) - expect(cacheService.get).toHaveBeenCalledWith(cacheKey) - - expect(cacheService.set).toHaveBeenCalledTimes(1) - expect(cacheService.set).toHaveBeenCalledWith(cacheKey, expected) - }) - - test("success - without product rates", async () => { - const providerService = container.resolve("taxProviderService") - - const productId = "prod_id" - - const rates = await providerService.getRegionRatesForProduct(productId, { - id: "reg_id", - tax_rates: [{ id: "reg_rate", rate: 20, name: "PTR", code: "ptr" }], - tax_rate: 12.5, - }) - - const expected = [ - { - rate: 12.5, - name: "default", - code: "default", - }, - ] - - const taxRateService = container.resolve("taxRateService") - - expect(taxRateService.listByProduct).toHaveBeenCalledTimes(1) - expect(taxRateService.listByProduct).toHaveBeenCalledWith(productId, { - region_id: "reg_id", - }) - - const cacheService = container.resolve("cacheService") - const cacheKey = getCacheKey(productId, "reg_id") - - expect(cacheService.get).toHaveBeenCalledTimes(1) - expect(cacheService.get).toHaveBeenCalledWith(cacheKey) - - expect(cacheService.set).toHaveBeenCalledTimes(1) - expect(cacheService.set).toHaveBeenCalledWith(cacheKey, expected) - - expect(rates.get(productId)).toEqual(expected) - }) - - test("success - with product rates", async () => { - const container = createContainer({}, defaultContainer) - container.register( - "taxRateService", - asValue({ - withTransaction: function () { - return this - }, - listByProduct: jest.fn(() => - Promise.resolve([ - { - rate: 20, - name: "PTR", - code: "ptr", - }, - ]) - ), - }) - ) - - const providerService = container.resolve("taxProviderService") - - const productId = "prod_id" - - const rates = await providerService.getRegionRatesForProduct(productId, { - id: "reg_id", - tax_rates: [{ id: "reg_rate", rate: 20, name: "PTR", code: "ptr" }], - tax_rate: 12.5, - }) - - const expected = [ - { - rate: 20, - name: "PTR", - code: "ptr", - }, - ] - - const taxRateService = container.resolve("taxRateService") - - expect(taxRateService.listByProduct).toHaveBeenCalledTimes(1) - expect(taxRateService.listByProduct).toHaveBeenCalledWith(productId, { - region_id: "reg_id", - }) - - const cacheService = container.resolve("cacheService") - const cacheKey = getCacheKey(productId, "reg_id") - - expect(cacheService.get).toHaveBeenCalledTimes(1) - expect(cacheService.get).toHaveBeenCalledWith(cacheKey) - - expect(cacheService.set).toHaveBeenCalledTimes(1) - expect(cacheService.set).toHaveBeenCalledWith(cacheKey, expected) - - expect(rates.get(productId)).toEqual(expected) - }) - }) - - describe("getCacheKey", () => { - const providerService = defaultContainer.resolve("taxProviderService") - - test("formats correctly", () => { - expect(providerService.getCacheKey("product", "region")).toEqual( - "txrtcache:product:region" - ) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/totals.js b/packages/medusa/src/services/__tests__/totals.js deleted file mode 100644 index f2813ffeae..0000000000 --- a/packages/medusa/src/services/__tests__/totals.js +++ /dev/null @@ -1,1224 +0,0 @@ -import { IdMap } from "medusa-test-utils" -import TotalsService from "../totals" -import { FlagRouter } from "@medusajs/utils" - -import TaxInclusivePricingFeatureFlag from "../../loaders/feature-flags/tax-inclusive-pricing" -import { calculatePriceTaxAmount } from "../../utils" - -const discounts = { - total10Percent: { - id: "total10", - code: "10%OFF", - rule: { - type: "percentage", - allocation: "total", - value: 10, - }, - regions: [{ id: "fr" }], - }, - item2Fixed: { - id: "item2Fixed", - code: "MEDUSA", - rule: { - type: "fixed", - allocation: "item", - value: 2, - // TODO: Add conditions relation - }, - regions: [{ id: "fr" }], - }, - item10Percent: { - id: "item10Percent", - code: "MEDUSA", - rule: { - type: "percentage", - allocation: "item", - value: 10, - // TODO: Add conditions relation - }, - regions: [{ id: "fr" }], - }, - total10Fixed: { - id: "total10Fixed", - code: "MEDUSA", - rule: { - type: "fixed", - allocation: "total", - value: 10, - // TODO: Add conditions relation - }, - regions: [{ id: "fr" }], - }, - expiredDiscount: { - id: "expired", - code: "MEDUSA", - ends_at: new Date("December 17, 1995 03:24:00"), - rule: { - type: "fixed", - allocation: "item", - value: 10, - // TODO: Add conditions relation - }, - regions: [{ id: "fr" }], - }, -} - -const applyDiscount = (cart, discount) => { - let newCart = { ...cart } - if (newCart.items) { - newCart.items = cart.items.map((item) => { - return { - ...item, - adjustments: [ - { - item_id: item.id, - amount: calculateAdjustment(newCart, item, discount), - description: "discount", - discount_id: discount.id, - }, - ], - } - }) - } - - return newCart -} - -const calculateAdjustment = (cart, lineItem, discount) => { - let amount = discount.rule.value * lineItem.quantity - - const taxAmountIncludedInPrice = !lineItem.includes_tax - ? 0 - : Math.round( - calculatePriceTaxAmount({ - price: lineItem.unit_price, - taxRate: cart.tax_rate / 100, - includesTax: lineItem.includes_tax, - }) - ) - let price = lineItem.unit_price - taxAmountIncludedInPrice - const lineItemPrice = price * lineItem.quantity - - if (discount.rule.type === "fixed" && discount.rule.allocation === "total") { - let subtotal = cart.items.reduce( - (total, item) => total + price * item.quantity, - 0 - ) - const nominator = Math.min(discount.rule.value, subtotal) - amount = Math.round((lineItemPrice / subtotal) * nominator) - } else if (discount.rule.type === "percentage") { - amount = Math.round((lineItemPrice * discount.rule.value) / 100) - } - return amount > lineItemPrice ? lineItemPrice : amount -} - -describe("TotalsService", () => { - const getTaxLinesMock = jest.fn((items) => { - const taxLines = items.some((item) => item.id === "line1") - ? [{ id: "line1" }] - : [] - return Promise.resolve(taxLines) - }) - const featureFlagRouter = new FlagRouter({ - [TaxInclusivePricingFeatureFlag.key]: false, - }) - const container = { - taxProviderService: { - withTransaction: function () { - return this - }, - getTaxLines: getTaxLinesMock, - }, - newTotalsService: { - getGiftCardTotals: jest.fn(() => { - return { - total: 0, - tax_total: 0, - } - }), - }, - taxCalculationStrategy: {}, - featureFlagRouter, - } - - describe("getAllocationItemDiscounts", () => { - let res - - const totalsService = new TotalsService(container) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("calculates item with percentage discount", async () => { - const cart = { - items: [ - { - id: "test", - allow_discounts: true, - unit_price: 10, - quantity: 10, - variant: { - id: "testv", - product_id: "testp", - }, - adjustments: [{ amount: 10 }], - }, - ], - } - - const discount = { - rule: { - type: "percentage", - value: 10, - }, - } - - res = totalsService.getAllocationItemDiscounts(discount, cart) - - expect(res).toEqual([ - { - lineItem: { - id: "test", - allow_discounts: true, - unit_price: 10, - quantity: 10, - variant: { - id: "testv", - product_id: "testp", - }, - adjustments: [{ amount: 10 }], - }, - variant: "testv", - amount: 10, - }, - ]) - }) - - it("calculates item with fixed discount", async () => { - const cart = { - items: [ - { - id: "exists", - allow_discounts: true, - unit_price: 10, - variant: { - id: "testv", - product_id: "testp", - }, - quantity: 10, - adjustments: [{ amount: 90 }], - }, - ], - } - - const discount = { - rule: { - type: "fixed", - value: 9, - // TODO: Add conditions relation - }, - } - - res = totalsService.getAllocationItemDiscounts(discount, cart) - - expect(res).toEqual([ - { - lineItem: { - id: "exists", - allow_discounts: true, - unit_price: 10, - variant: { - id: "testv", - product_id: "testp", - }, - quantity: 10, - adjustments: [{ amount: 90 }], - }, - variant: "testv", - amount: 90, - }, - ]) - }) - - // not relevant anymore - // it("does not apply discount if no valid variants are provided", async () => { - // const cart = { - // items: [ - // { - // id: "exists", - // allow_discounts: true, - // unit_price: 10, - // variant: { - // id: "testv", - // product_id: "testp", - // }, - // quantity: 10, - // }, - // ], - // } - - // const discount = { - // rule: { - // type: "fixed", - // value: 9, - // // TODO: Add conditions relation - // }, - // } - // res = totalsService.getAllocationItemDiscounts(discount, cart) - - // expect(res).toEqual([]) - // }) - }) - - describe("getDiscountTotal", () => { - let res - const totalsService = new TotalsService(container) - - const discountCart = { - id: "discount_cart", - discounts: [], - region_id: "fr", - items: [ - { - id: "line", - allow_discounts: true, - unit_price: 18, - variant: { - id: "testv1", - product_id: "testp1", - }, - quantity: 10, - }, - { - id: "line2", - allow_discounts: true, - unit_price: 10, - variant: { - id: "testv2", - product_id: "testp2", - }, - quantity: 10, - }, - ], - } - - beforeEach(() => { - jest.clearAllMocks() - discountCart.discounts = [] - }) - - it("calculate total percentage discount", async () => { - discountCart.discounts.push(discounts.total10Percent) - let cart = applyDiscount(discountCart, discounts.total10Percent) - res = await totalsService.getDiscountTotal(cart) - - expect(res).toEqual(28) - }) - - // TODO: Redo tests to include new line item adjustments - - it("calculate item fixed discount", async () => { - discountCart.discounts.push(discounts.item2Fixed) - let cart = applyDiscount(discountCart, discounts.item2Fixed) - res = await totalsService.getDiscountTotal(cart) - - expect(res).toEqual(40) - }) - - it("calculate item percentage discount", async () => { - discountCart.discounts.push(discounts.item10Percent) - let cart = applyDiscount(discountCart, discounts.item10Percent) - res = await totalsService.getDiscountTotal(cart) - - expect(res).toEqual(28) - }) - - it("calculate total fixed discount", async () => { - discountCart.discounts.push(discounts.total10Fixed) - let cart = applyDiscount(discountCart, discounts.total10Fixed) - res = await totalsService.getDiscountTotal(cart) - - expect(res).toEqual(10) - }) - - it("ignores discount if expired", async () => { - discountCart.discounts.push(discounts.expiredDiscount) - res = await totalsService.getDiscountTotal(discountCart) - - expect(res).toEqual(0) - }) - - it("returns 0 if no discounts are applied", async () => { - res = await totalsService.getDiscountTotal(discountCart) - - expect(res).toEqual(0) - }) - - it("returns 0 if no items are in cart", async () => { - res = await totalsService.getDiscountTotal({ - items: [], - discounts: [discounts.total10Fixed], - }) - - expect(res).toEqual(0) - }) - }) - - describe("getLineDiscounts", () => { - let res - const totalsService = new TotalsService(container) - - const mockCart = { - swaps: [], - claims: [], - items: [], - } - let cart - - beforeEach(() => { - jest.clearAllMocks() - cart = { ...mockCart } - }) - - it("returns [] if items is empty in cart", async () => { - res = totalsService.getLineDiscounts(cart, discounts.total10Fixed) - - expect(res).toEqual([]) - }) - - it("returns [] if items is undefined in cart", async () => { - cart.items = undefined - res = totalsService.getLineDiscounts(cart, discounts.total10Fixed) - - expect(res).toEqual([]) - }) - - it("returns flat list of discount amounts for a cart with multiple items, swaps, claims for a given discount", async () => { - const discountId = discounts.total10Fixed.id - const discountValue = discounts.total10Fixed.rule.value - const item1 = { - allow_discounts: true, - unit_price: 18, - adjustments: [ - { - discount_id: discountId, - amount: discountValue, - }, - ], - } - const item2 = { ...item1, unit_price: 19 } - const item3 = { ...item1, unit_price: 20 } - const item4 = { ...item1, unit_price: 21 } - const item5 = { ...item1, unit_price: 22 } - const item6 = { ...item1, unit_price: 23 } - const item7 = { ...item1, unit_price: 24 } - const item8 = { ...item1, unit_price: 25 } - - const swap1 = { - additional_items: [item3, item4], - } - const swap2 = { - additional_items: [item5], - } - const claim1 = { - additional_items: [item6, item7], - } - const claim2 = { - additional_items: [item8], - } - - cart.items = [item1, item2] - cart.swaps = [swap1, swap2] - cart.claims = [claim1, claim2] - - res = totalsService.getLineDiscounts(cart, discounts.total10Fixed) - - expect(res).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - amount: discountValue, - item: item1, - }), - expect.objectContaining({ - amount: discountValue, - item: item2, - }), - expect.objectContaining({ - amount: discountValue, - item: item3, - }), - expect.objectContaining({ - amount: discountValue, - item: item4, - }), - expect.objectContaining({ - amount: discountValue, - item: item5, - }), - expect.objectContaining({ - amount: discountValue, - item: item6, - }), - expect.objectContaining({ - amount: discountValue, - item: item7, - }), - expect.objectContaining({ - amount: discountValue, - item: item8, - }), - ]) - ) - }) - }) - - describe("getRefundTotal", () => { - let res - const totalsService = new TotalsService(container) - const orderToRefund = { - id: "refund-order", - tax_rate: 25, - items: [ - { - id: "line", - unit_price: 100, - allow_discounts: true, - variant: { - id: "variant", - product_id: "testp1", - }, - quantity: 10, - returned_quantity: 0, - }, - { - id: "line2", - unit_price: 100, - allow_discounts: true, - variant: { - id: "variant", - product_id: "testp2", - }, - quantity: 10, - returned_quantity: 0, - metadata: {}, - }, - { - id: "non-discount", - unit_price: 100, - allow_discounts: false, - variant: { - id: "variant", - product_id: "testp2", - }, - quantity: 1, - returned_quantity: 0, - metadata: {}, - }, - ], - region_id: "fr", - discounts: [], - } - - beforeEach(() => { - jest.clearAllMocks() - orderToRefund.discounts = [] - }) - - it("calculates refund", async () => { - res = await totalsService.getRefundTotal(orderToRefund, [ - { - id: "line2", - unit_price: 100, - allow_discounts: true, - variant: { - id: "variant", - product_id: "product2", - }, - quantity: 10, - returned_quantity: 0, - metadata: {}, - }, - ]) - - expect(res).toEqual(1250) - }) - - // TODO: Redo tests to include new line item adjustments - - // it("calculates refund with total precentage discount", async () => { - // orderToRefund.discounts.push(discounts.total10Percent) - // res = totalsService.getRefundTotal(orderToRefund, [ - // { - // id: "line2", - // unit_price: 100, - // allow_discounts: true, - // variant: { - // id: "variant", - // product_id: "product2", - // }, - // returned_quantity: 0, - // metadata: {}, - // quantity: 10, - // }, - // ]) - - // expect(res).toEqual(1125) - // }) - - // it("calculates refund with total fixed discount", async () => { - // orderToRefund.discounts.push(discounts.total10Fixed) - // res = totalsService.getRefundTotal(orderToRefund, [ - // { - // id: "line", - // unit_price: 100, - // allow_discounts: true, - // variant: { - // id: "variant", - // product_id: "product", - // }, - // quantity: 10, - // returned_quantity: 0, - // }, - // ]) - - // expect(res).toEqual(1244) - // }) - - it("calculates refund with item fixed discount", async () => { - orderToRefund.discounts.push(discounts.item2Fixed) - let order = applyDiscount(orderToRefund, discounts.item2Fixed) - res = await totalsService.getRefundTotal(order, [ - { - id: "line2", - unit_price: 100, - allow_discounts: true, - variant: { - id: "variant", - product_id: "testp2", - }, - quantity: 10, - returned_quantity: 0, - }, - ]) - - expect(res).toEqual(1225) - }) - - it("calculates refund with item percentage discount", async () => { - orderToRefund.discounts.push(discounts.item10Percent) - let order = applyDiscount(orderToRefund, discounts.item10Percent) - res = await totalsService.getRefundTotal(order, [ - { - id: "line2", - unit_price: 100, - allow_discounts: true, - variant: { - id: "variant", - product_id: "testp2", - }, - quantity: 10, - returned_quantity: 0, - }, - ]) - - expect(res).toEqual(1125) - }) - - it("throws if line items to return is not in order", async () => { - let errMsg - await totalsService - .getRefundTotal(orderToRefund, [ - { - id: "notInOrder", - unit_price: 123, - allow_discounts: true, - variant: { - id: "variant", - product_id: "pid", - }, - quantity: 1, - }, - ]) - .catch((e) => (errMsg = e.message)) - - expect(errMsg).toBe("Line item does not exist on order") - }) - }) - - describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] getRefundTotal", () => { - let res - const totalsService = new TotalsService({ - ...container, - featureFlagRouter: new FlagRouter({ - [TaxInclusivePricingFeatureFlag.key]: true, - }), - }) - - const orderToRefund = { - id: "refund-order", - tax_rate: 25, - items: [ - { - id: "line", - unit_price: 125, - includes_tax: true, - allow_discounts: true, - variant: { - id: "variant", - product_id: "testp1", - }, - quantity: 10, - returned_quantity: 0, - }, - { - id: "line2", - unit_price: 100, - allow_discounts: true, - variant: { - id: "variant", - product_id: "testp2", - }, - quantity: 10, - returned_quantity: 0, - metadata: {}, - }, - { - id: "non-discount", - unit_price: 100, - allow_discounts: false, - variant: { - id: "variant", - product_id: "testp2", - }, - quantity: 1, - returned_quantity: 0, - metadata: {}, - }, - ], - region_id: "fr", - discounts: [], - } - - beforeEach(() => { - jest.clearAllMocks() - orderToRefund.discounts = [] - }) - - it("calculates refund", async () => { - res = await totalsService.getRefundTotal(orderToRefund, [ - { - id: "line2", - unit_price: 100, - allow_discounts: true, - variant: { - id: "variant", - product_id: "product2", - }, - quantity: 10, - returned_quantity: 0, - metadata: {}, - }, - ]) - - expect(res).toEqual(1250) - }) - - it("calculates refund with line that includes tax", async () => { - res = await totalsService.getRefundTotal(orderToRefund, [ - { - id: "line", - unit_price: 125, - includes_tax: true, - allow_discounts: true, - variant: { - id: "variant", - product_id: "product2", - }, - quantity: 10, - returned_quantity: 0, - metadata: {}, - }, - ]) - - expect(res).toEqual(1250) - }) - - it("calculates refund with item fixed discount", async () => { - orderToRefund.discounts.push(discounts.item2Fixed) - let order = applyDiscount(orderToRefund, discounts.item2Fixed) - res = await totalsService.getRefundTotal(order, [ - { - id: "line2", - unit_price: 100, - allow_discounts: true, - variant: { - id: "variant", - product_id: "testp2", - }, - quantity: 10, - returned_quantity: 0, - }, - ]) - - expect(res).toEqual(1225) - }) - - it("calculates refund with item fixed discount and a line that includes tax", async () => { - orderToRefund.discounts.push(discounts.item2Fixed) - let order = applyDiscount(orderToRefund, discounts.item2Fixed) - res = await totalsService.getRefundTotal(order, [ - { - id: "line", - unit_price: 125, - includes_tax: true, - allow_discounts: true, - variant: { - id: "variant", - product_id: "testp2", - }, - quantity: 10, - returned_quantity: 0, - }, - ]) - - expect(res).toEqual(1225) - }) - - it("calculates refund with item percentage discount", async () => { - orderToRefund.discounts.push(discounts.item10Percent) - let order = applyDiscount(orderToRefund, discounts.item10Percent) - res = await totalsService.getRefundTotal(order, [ - { - id: "line2", - unit_price: 100, - allow_discounts: true, - variant: { - id: "variant", - product_id: "testp2", - }, - quantity: 10, - returned_quantity: 0, - }, - ]) - - expect(res).toEqual(1125) - }) - - it("calculates refund with item percentage discount and a line that includes tax", async () => { - orderToRefund.discounts.push(discounts.item10Percent) - let order = applyDiscount(orderToRefund, discounts.item10Percent) - res = await totalsService.getRefundTotal(order, [ - { - id: "line", - unit_price: 125, - includes_tax: true, - allow_discounts: true, - variant: { - id: "variant", - product_id: "testp2", - }, - quantity: 10, - returned_quantity: 0, - }, - ]) - - expect(res).toEqual(1125) - }) - }) - - describe("getShippingTotal", () => { - const getTaxLinesMock = jest.fn(() => - Promise.resolve([ - { shipping_method_id: IdMap.getId("expensiveShipping") }, - ]) - ) - const calculateMock = jest.fn(() => Promise.resolve(20)) - - const totalsService = new TotalsService({ - ...container, - taxProviderService: { - withTransaction: function () { - return this - }, - getTaxLines: getTaxLinesMock, - }, - taxCalculationStrategy: { - calculate: calculateMock, - }, - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("calculates shipping", async () => { - const order = { - shipping_methods: [ - { - id: IdMap.getId("expensiveShipping"), - name: "Expensive Shipping", - price: 100, - provider_id: "default_provider", - profile_id: IdMap.getId("default"), - data: { - extra: "hi", - }, - }, - ], - } - const total = await totalsService.getShippingTotal(order) - - expect(total).toEqual(100) - }) - }) - - describe("getTaxTotal", () => { - let res - let totalsService - - const getTaxLinesMock = jest.fn((items) => { - const taxLines = items.some((item) => item.id === "line1") - ? [{ id: "line1" }] - : [] - return Promise.resolve(taxLines) - }) - const calculateMock = jest.fn(() => Promise.resolve(20.3)) - const getAllocationMapMock = jest.fn(() => ({})) - - const cradle = { - taxProviderService: { - withTransaction: function () { - return this - }, - getTaxLines: getTaxLinesMock, - }, - taxCalculationStrategy: { - calculate: calculateMock, - }, - newTotalsService: { - getGiftCardTotals: jest.fn(() => { - return { - total: 0, - tax_total: 0, - } - }), - }, - featureFlagRouter, - } - - beforeEach(() => { - jest.clearAllMocks() - - totalsService = new TotalsService(cradle) - totalsService.getAllocationMap = getAllocationMapMock - }) - - it("uses order tax lines", async () => { - const order = { - object: "order", - tax_rate: null, - region: { - tax_rate: 25, - }, - customer: { - test: "test", - }, - shipping_address: { - test: "test", - }, - items: [ - { - unit_price: 20, - quantity: 2, - tax_lines: [{ id: "orderline1" }], - }, - ], - shipping_methods: [ - { - id: IdMap.getId("expensiveShipping"), - name: "Expensive Shipping", - price: 100, - provider_id: "default_provider", - profile_id: IdMap.getId("default"), - tax_lines: [], - data: { - extra: "hi", - }, - }, - ], - } - - res = await totalsService.getTaxTotal(order) - - expect(res).toEqual(20) - - expect(getAllocationMapMock).toHaveBeenCalledTimes(2) - expect(getAllocationMapMock).toHaveBeenNthCalledWith(1, order, {}) - - expect(getTaxLinesMock).toHaveBeenCalledTimes(0) - - expect(calculateMock).toHaveBeenCalledTimes(3) - expect(calculateMock).toHaveBeenNthCalledWith( - 3, - order.items, - [{ id: "orderline1" }], - { - shipping_address: order.shipping_address, - shipping_methods: order.shipping_methods, - is_return: false, - customer: order.customer, - region: order.region, - allocation_map: {}, - } - ) - }) - - it("calculates tax", async () => { - const order = { - region: { - tax_rate: 25, - }, - customer: { - test: "test", - }, - shipping_address: { - test: "test", - }, - items: [ - { - id: "line1", - unit_price: 20, - quantity: 2, - }, - ], - shipping_methods: [ - { - id: IdMap.getId("expensiveShipping"), - name: "Expensive Shipping", - price: 100, - provider_id: "default_provider", - profile_id: IdMap.getId("default"), - data: { - extra: "hi", - }, - }, - ], - } - - res = await totalsService.getTaxTotal(order) - - expect(res).toEqual(20) - - expect(getAllocationMapMock).toHaveBeenCalledTimes(2) - expect(getAllocationMapMock).toHaveBeenNthCalledWith(2, order, { - exclude_discounts: undefined, - exclude_gift_cards: true, - }) - - expect(getTaxLinesMock).toHaveBeenCalledTimes(2) - expect(getTaxLinesMock).toHaveBeenNthCalledWith( - 2, - [{ id: "line1", quantity: 2, unit_price: 20 }], - { - shipping_address: order.shipping_address, - shipping_methods: order.shipping_methods, - is_return: false, - customer: order.customer, - region: order.region, - allocation_map: {}, - } - ) - - expect(calculateMock).toHaveBeenCalledTimes(3) - expect(calculateMock).toHaveBeenCalledWith( - order.items, - [{ id: "line1" }], - { - shipping_address: order.shipping_address, - shipping_methods: order.shipping_methods, - is_return: false, - customer: order.customer, - region: order.region, - allocation_map: {}, - } - ) - }) - }) - - describe("getTotal", () => { - let res - const totalsService = new TotalsService(container) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("calculates total", async () => { - const order = { - region: { - tax_rate: 25, - }, - items: [ - { - unit_price: 20, - quantity: 2, - }, - ], - shipping_methods: [ - { - _id: IdMap.getId("expensiveShipping"), - name: "Expensive Shipping", - price: 100, - provider_id: "default_provider", - profile_id: IdMap.getId("default"), - data: { - extra: "hi", - }, - }, - ], - } - const getTaxTotalMock = jest.fn(() => Promise.resolve(35)) - totalsService.getTaxTotal = getTaxTotalMock - res = await totalsService.getTotal(order) - - expect(getTaxTotalMock).toHaveBeenCalledTimes(1) - expect(getTaxTotalMock).toHaveBeenCalledWith(order, undefined) - - expect(res).toEqual(175) - }) - }) - - describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] getTotal", () => { - let res - const totalsService = new TotalsService({ - ...container, - featureFlagRouter: new FlagRouter({ - [TaxInclusivePricingFeatureFlag.key]: true, - }), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("calculates total", async () => { - const order = { - region: { - tax_rate: 25, - }, - items: [ - { - unit_price: 20, - quantity: 2, - }, - { - unit_price: 25, - quantity: 2, - includes_tax: true, - }, - ], - shipping_methods: [ - { - _id: IdMap.getId("expensiveShipping"), - name: "Expensive Shipping", - price: 100, - provider_id: "default_provider", - profile_id: IdMap.getId("default"), - data: { - extra: "hi", - }, - }, - ], - } - const getTaxTotalMock = jest.fn(() => Promise.resolve(45)) - totalsService.getTaxTotal = getTaxTotalMock - res = await totalsService.getTotal(order) - - expect(getTaxTotalMock).toHaveBeenCalledTimes(1) - expect(getTaxTotalMock).toHaveBeenCalledWith(order, undefined) - - expect(res).toEqual(185) - }) - }) - - describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] getShippingTotal ", () => { - const shippingMethodData = { - id: IdMap.getId("expensiveShipping"), - name: "Expensive Shipping", - price: 120, - tax_lines: [{ shipping_method_id: IdMap.getId("expensiveShipping") }], - provider_id: "default_provider", - profile_id: IdMap.getId("default"), - data: { - extra: "hi", - }, - } - const calculateMock = jest.fn(() => Promise.resolve(20)) - const totalsService = new TotalsService({ - ...container, - taxCalculationStrategy: { - calculate: calculateMock, - }, - featureFlagRouter: new FlagRouter({ - [TaxInclusivePricingFeatureFlag.key]: true, - }), - }) - - beforeEach(() => { - jest.clearAllMocks() - }) - - it("calculates total with tax lines and being tax inclusive", async () => { - const order = { - object: "order", - shipping_methods: [ - { - ...shippingMethodData, - includes_tax: true, - }, - ], - } - - const total = await totalsService.getShippingTotal(order) - - expect(total).toEqual(100) - }) - - it("calculates total with tax lines and not being tax inclusive", async () => { - const order = { - object: "order", - shipping_methods: [ - { - ...shippingMethodData, - price: 100, - includes_tax: false, - }, - ], - } - - const total = await totalsService.getShippingTotal(order) - - expect(total).toEqual(100) - }) - - it("calculates total with the old system and not being tax inclusive", async () => { - const order = { - object: "order", - tax_rate: 20, - shipping_methods: [ - { - ...shippingMethodData, - price: 100, - includes_tax: false, - tax_lines: [], - }, - ], - } - - const total = await totalsService.getShippingTotal(order) - - expect(total).toEqual(100) - }) - }) -}) diff --git a/packages/medusa/src/services/__tests__/user.js b/packages/medusa/src/services/__tests__/user.js deleted file mode 100644 index bc3d84c643..0000000000 --- a/packages/medusa/src/services/__tests__/user.js +++ /dev/null @@ -1,186 +0,0 @@ -import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import UserService from "../user" - -const eventBusService = { - emit: jest.fn(), - withTransaction: function () { - return this - }, -} - -describe("UserService", () => { - describe("retrieve", () => { - const userRepository = MockRepository({ - find: () => Promise.resolve([{ id: IdMap.getId("ironman") }]), - }) - const userService = new UserService({ - manager: MockManager, - userRepository, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully retrieves a user", async () => { - const result = await userService.retrieve(IdMap.getId("ironman")) - - expect(userRepository.find).toHaveBeenCalledTimes(1) - expect(userRepository.find).toHaveBeenCalledWith({ - where: { id: IdMap.getId("ironman") }, - }) - - expect(result.id).toEqual(IdMap.getId("ironman")) - }) - }) - - describe("create", () => { - const userRepository = MockRepository({ - create: (any) => Promise.resolve({ id: IdMap.getId("ironman") }), - save: (any) => Promise.resolve({ id: IdMap.getId("ironman") }), - }) - - const userService = new UserService({ - manager: MockManager, - userRepository, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully create a user", async () => { - await userService.create( - { - email: "oliver@test.dk", - name: "Oliver", - password_hash: "hashedpassword", - }, - "password" - ) - - expect(userRepository.create).toHaveBeenCalledTimes(1) - expect(userRepository.create).toHaveBeenCalledWith({ - email: "oliver@test.dk", - name: "Oliver", - password_hash: expect.stringMatching(/.{128}$/), - }) - - expect(eventBusService.emit).toHaveBeenCalledWith( - UserService.Events.CREATED, - { - id: expect.any(String), - } - ) - }) - }) - - describe("update", () => { - const userRepository = MockRepository({ - find: () => Promise.resolve([{ id: IdMap.getId("ironman") }]), - }) - const userService = new UserService({ - manager: MockManager, - userRepository, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("successfully updates user", async () => { - await userService.update(IdMap.getId("ironman"), { - first_name: "Tony", - last_name: "Stark", - }) - - expect(userRepository.save).toBeCalledTimes(1) - expect(userRepository.save).toBeCalledWith({ - id: IdMap.getId("ironman"), - first_name: "Tony", - last_name: "Stark", - }) - - expect(eventBusService.emit).toHaveBeenCalledWith( - UserService.Events.UPDATED, - { - id: IdMap.getId("ironman"), - } - ) - }) - - it("successfully updates user metadata", async () => { - await userService.update(IdMap.getId("ironman"), { - metadata: { - company: "Stark Industries", - }, - }) - - expect(userRepository.save).toBeCalledTimes(1) - expect(userRepository.save).toBeCalledWith({ - id: IdMap.getId("ironman"), - metadata: { - company: "Stark Industries", - }, - }) - - expect(eventBusService.emit).toHaveBeenCalledWith( - UserService.Events.UPDATED, - { - id: IdMap.getId("ironman"), - } - ) - }) - - it("fails on email update", async () => { - try { - await userService.update(IdMap.getId("ironman"), { - email: "tony@stark.com", - }) - } catch (error) { - expect(error.message).toBe("You are not allowed to update email") - } - }) - - it("fails on password update", async () => { - try { - await userService.update(IdMap.getId("ironman"), { - password_hash: "lol", - }) - } catch (error) { - expect(error.message).toBe( - "Use dedicated methods, `setPassword`, `generateResetPasswordToken` for password operations" - ) - } - }) - }) - - describe("generateResetPasswordToken", () => { - const userRepository = MockRepository({ - find: () => - Promise.resolve([{ id: IdMap.getId("ironman"), password_hash: "lol" }]), - }) - - const userService = new UserService({ - manager: MockManager, - userRepository, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("generates a token successfully", async () => { - const token = await userService.generateResetPasswordToken( - IdMap.getId("ironman") - ) - - expect(token).toMatch( - /^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*$/ - ) - }) - }) -}) diff --git a/packages/medusa/src/services/analytics-config.ts b/packages/medusa/src/services/analytics-config.ts deleted file mode 100644 index 7662771e31..0000000000 --- a/packages/medusa/src/services/analytics-config.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { AnalyticsConfig } from "../models" -import { AnalyticsConfigRepository as AnalyticsRepository } from "../repositories/analytics-config" -import { - CreateAnalyticsConfig, - UpdateAnalyticsConfig, -} from "../types/analytics-config" -import UserService from "./user" - -type InjectedDependencies = { - analyticsConfigRepository: typeof AnalyticsRepository - manager: EntityManager -} - -class AnalyticsConfigService extends TransactionBaseService { - protected readonly analyticsConfigRepository_: typeof AnalyticsRepository - protected readonly userService_: UserService - - constructor({ analyticsConfigRepository }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.analyticsConfigRepository_ = analyticsConfigRepository - } - - async retrieve(userId: string): Promise { - const analyticsRepo = this.activeManager_.withRepository( - this.analyticsConfigRepository_ - ) - - const analyticsConfig = await analyticsRepo.findOne({ - where: { user_id: userId }, - }) - - if (!analyticsConfig) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `No analytics config found for user with id: ${userId}` - ) - } - - return analyticsConfig - } - - /** - * Creates an analytics config. - */ - async create( - userId: string, - data: CreateAnalyticsConfig - ): Promise { - const analyticsRepo = this.activeManager_.withRepository( - this.analyticsConfigRepository_ - ) - - const config = analyticsRepo.create({ user_id: userId, ...data }) - return await analyticsRepo.save(config) - } - - /** - * Updates an analytics config. If the config does not exist, it will be created instead. - */ - async update( - userId: string, - update: UpdateAnalyticsConfig - ): Promise { - const analyticsRepo = this.activeManager_.withRepository( - this.analyticsConfigRepository_ - ) - - const config = await this.retrieve(userId).catch(() => undefined) - - if (!config) { - return this.create(userId, { - opt_out: update.opt_out ?? false, - anonymize: update.anonymize ?? false, - }) - } - - for (const [key, value] of Object.entries(update)) { - if (value !== undefined) { - config[key] = value - } - } - - return await analyticsRepo.save(config) - } - - /** - * Deletes an analytics config. - */ - async delete(userId: string): Promise { - const analyticsRepo = this.activeManager_.withRepository( - this.analyticsConfigRepository_ - ) - - const config = await this.retrieve(userId).catch(() => undefined) - - if (!config) { - return - } - - await analyticsRepo.softRemove(config) - } -} - -export default AnalyticsConfigService diff --git a/packages/medusa/src/services/auth.ts b/packages/medusa/src/services/auth.ts deleted file mode 100644 index bc8fe19ba9..0000000000 --- a/packages/medusa/src/services/auth.ts +++ /dev/null @@ -1,174 +0,0 @@ -import Scrypt from "scrypt-kdf" -import { AuthenticateResult } from "../types/auth" -import { Customer, User } from "../models" -import { TransactionBaseService } from "../interfaces" -import UserService from "./user" -import CustomerService from "./customer" -import { EntityManager } from "typeorm" -import { Logger } from "@medusajs/types" - -type InjectedDependencies = { - manager: EntityManager - userService: UserService - customerService: CustomerService - logger: Logger -} - -/** - * Can authenticate a user based on email password combination - */ -class AuthService extends TransactionBaseService { - protected readonly userService_: UserService - protected readonly customerService_: CustomerService - protected readonly logger_: Logger - - constructor({ userService, customerService, logger }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.userService_ = userService - this.customerService_ = customerService - this.logger_ = logger - } - - /** - * Verifies if a password is valid given the provided password hash - * @param {string} password - the raw password to check - * @param {string} hash - the hash to compare against - * @return {bool} the result of the comparison - */ - protected async comparePassword_( - password: string, - hash: string - ): Promise { - const buf = Buffer.from(hash, "base64") - return Scrypt.verify(buf, password) - } - - /** - * Authenticates a given user with an API token - * @param {string} token - the api_token of the user to authenticate - * @return {AuthenticateResult} - * success: whether authentication succeeded - * user: the user document if authentication succeeded - * error: a string with the error message - */ - async authenticateAPIToken(token: string): Promise { - return await this.atomicPhase_(async (transactionManager) => { - try { - const user: User = await this.userService_ - .withTransaction(transactionManager) - .retrieveByApiToken(token) - return { - success: true, - user, - } - } catch (error) { - return { - success: false, - error: "Invalid API Token", - } - } - }) - } - - /** - * Authenticates a given user based on an email, password combination. Uses - * scrypt to match password with hashed value. - * @param {string} email - the email of the user - * @param {string} password - the password of the user - * @return {AuthenticateResult} - * success: whether authentication succeeded - * user: the user document if authentication succeeded - * error: a string with the error message - */ - async authenticate( - email: string, - password: string - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - try { - const userPasswordHash: User = await this.userService_ - .withTransaction(transactionManager) - .retrieveByEmail(email, { - select: ["password_hash"], - }) - - const passwordsMatch = await this.comparePassword_( - password, - userPasswordHash.password_hash - ) - - if (passwordsMatch) { - const user = await this.userService_ - .withTransaction(transactionManager) - .retrieveByEmail(email) - - return { - success: true, - user: user, - } - } - } catch (error) { - this.logger_.log("error", error) - // ignore - } - - return { - success: false, - error: "Invalid email or password", - } - }) - } - - /** - * Authenticates a customer based on an email, password combination. Uses - * scrypt to match password with hashed value. - * @param {string} email - the email of the user - * @param {string} password - the password of the user - * @return {{ success: (bool), customer: (object | undefined) }} - * success: whether authentication succeeded - * customer: the customer document if authentication succeded - * error: a string with the error message - */ - async authenticateCustomer( - email: string, - password: string - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - try { - const customer: Customer = await this.customerService_ - .withTransaction(transactionManager) - .retrieveRegisteredByEmail(email, { - select: ["id", "password_hash"], - }) - if (customer.password_hash) { - const passwordsMatch = await this.comparePassword_( - password, - customer.password_hash - ) - - if (passwordsMatch) { - const customer = await this.customerService_ - .withTransaction(transactionManager) - .retrieveRegisteredByEmail(email) - - return { - success: true, - customer, - } - } - } - } catch (error) { - // ignore - } - - return { - success: false, - error: "Invalid email or password", - } - }) - } -} - -export default AuthService diff --git a/packages/medusa/src/services/batch-job.ts b/packages/medusa/src/services/batch-job.ts deleted file mode 100644 index f463128e3f..0000000000 --- a/packages/medusa/src/services/batch-job.ts +++ /dev/null @@ -1,382 +0,0 @@ -import { Request } from "express" -import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { BatchJob } from "../models" -import { BatchJobRepository } from "../repositories/batch-job" -import { - BatchJobCreateProps, - BatchJobResultError, - BatchJobStatus, - BatchJobUpdateProps, - CreateBatchJobInput, - FilterableBatchJobProps, -} from "../types/batch-job" -import { FindConfig } from "../types/common" -import { buildQuery } from "../utils" -import EventBusService from "./event-bus" -import { StrategyResolverService } from "./index" - -type InjectedDependencies = { - manager: EntityManager - eventBusService: EventBusService - batchJobRepository: typeof BatchJobRepository - strategyResolverService: StrategyResolverService -} - -class BatchJobService extends TransactionBaseService { - static readonly Events = { - CREATED: "batch.created", - UPDATED: "batch.updated", - PRE_PROCESSED: "batch.pre_processed", - CONFIRMED: "batch.confirmed", - PROCESSING: "batch.processing", - COMPLETED: "batch.completed", - CANCELED: "batch.canceled", - FAILED: "batch.failed", - } - - protected readonly batchJobRepository_: typeof BatchJobRepository - protected readonly eventBus_: EventBusService - protected readonly strategyResolver_: StrategyResolverService - - protected batchJobStatusMapToProps = new Map< - BatchJobStatus, - { entityColumnName: string; eventType: string } - >([ - [ - BatchJobStatus.PRE_PROCESSED, - { - entityColumnName: "pre_processed_at", - eventType: BatchJobService.Events.PRE_PROCESSED, - }, - ], - [ - BatchJobStatus.CONFIRMED, - { - entityColumnName: "confirmed_at", - eventType: BatchJobService.Events.CONFIRMED, - }, - ], - [ - BatchJobStatus.PROCESSING, - { - entityColumnName: "processing_at", - eventType: BatchJobService.Events.PROCESSING, - }, - ], - [ - BatchJobStatus.COMPLETED, - { - entityColumnName: "completed_at", - eventType: BatchJobService.Events.COMPLETED, - }, - ], - [ - BatchJobStatus.CANCELED, - { - entityColumnName: "canceled_at", - eventType: BatchJobService.Events.CANCELED, - }, - ], - [ - BatchJobStatus.FAILED, - { - entityColumnName: "failed_at", - eventType: BatchJobService.Events.FAILED, - }, - ], - ]) - - constructor({ - batchJobRepository, - eventBusService, - strategyResolverService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.batchJobRepository_ = batchJobRepository - this.eventBus_ = eventBusService - this.strategyResolver_ = strategyResolverService - } - - async retrieve( - batchJobId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(batchJobId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"batchJobId" must be defined` - ) - } - - const batchJobRepo = this.activeManager_.withRepository( - this.batchJobRepository_ - ) - - const query = buildQuery({ id: batchJobId }, config) - const batchJob = await batchJobRepo.findOne(query) - - if (!batchJob) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Batch job with id ${batchJobId} was not found` - ) - } - - return batchJob - } - - async listAndCount( - selector: FilterableBatchJobProps = {}, - config: FindConfig = { skip: 0, take: 20 } - ): Promise<[BatchJob[], number]> { - const batchJobRepo = this.activeManager_.withRepository( - this.batchJobRepository_ - ) - - const query = buildQuery(selector, config) - return await batchJobRepo.findAndCount(query) - } - - async create(data: BatchJobCreateProps): Promise { - return await this.atomicPhase_(async (manager) => { - const batchJobRepo = manager.withRepository(this.batchJobRepository_) - - const batchJob = batchJobRepo.create(data) - const result = await batchJobRepo.save(batchJob) - - await this.eventBus_ - .withTransaction(manager) - .emit(BatchJobService.Events.CREATED, { - id: result.id, - }) - - return result - }) - } - - async update( - batchJobOrId: BatchJob | string, - data: BatchJobUpdateProps - ): Promise { - return await this.atomicPhase_(async (manager) => { - const batchJobRepo = manager.withRepository(this.batchJobRepository_) - - let batchJob = batchJobOrId as BatchJob - if (typeof batchJobOrId === "string") { - batchJob = await this.retrieve(batchJobOrId) - } - - const { context, result, ...rest } = data - if (context) { - batchJob.context = { ...batchJob.context, ...context } - } - - if (result) { - batchJob.result = { ...batchJob.result, ...result } - } - - Object.keys(rest) - .filter((key) => typeof rest[key] !== `undefined`) - .forEach((key) => { - batchJob[key] = rest[key] - }) - - batchJob = await batchJobRepo.save(batchJob) - - await this.eventBus_ - .withTransaction(manager) - .emit(BatchJobService.Events.UPDATED, { - id: batchJob.id, - }) - - return batchJob - }) - } - - async confirm(batchJobOrId: string | BatchJob): Promise { - return await this.atomicPhase_(async () => { - let batchJob: BatchJob = batchJobOrId as BatchJob - if (typeof batchJobOrId === "string") { - batchJob = await this.retrieve(batchJobOrId) - } - - if (batchJob.status !== BatchJobStatus.PRE_PROCESSED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot confirm processing for a batch job that is not pre processed" - ) - } - - return await this.updateStatus(batchJob, BatchJobStatus.CONFIRMED) - }) - } - - async complete(batchJobOrId: string | BatchJob): Promise { - return await this.atomicPhase_(async () => { - let batchJob: BatchJob = batchJobOrId as BatchJob - if (typeof batchJobOrId === "string") { - batchJob = await this.retrieve(batchJobOrId) - } - - if (batchJob.status !== BatchJobStatus.PROCESSING) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Cannot complete a batch job with status "${batchJob.status}". The batch job must be processing` - ) - } - - return await this.updateStatus(batchJob, BatchJobStatus.COMPLETED) - }) - } - - async cancel(batchJobOrId: string | BatchJob): Promise { - return await this.atomicPhase_(async () => { - let batchJob: BatchJob = batchJobOrId as BatchJob - if (typeof batchJobOrId === "string") { - batchJob = await this.retrieve(batchJobOrId) - } - - if (batchJob.status === BatchJobStatus.COMPLETED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot cancel completed batch job" - ) - } - - return await this.updateStatus(batchJob, BatchJobStatus.CANCELED) - }) - } - - async setPreProcessingDone( - batchJobOrId: string | BatchJob - ): Promise { - return await this.atomicPhase_(async () => { - let batchJob: BatchJob = batchJobOrId as BatchJob - if (typeof batchJobOrId === "string") { - batchJob = await this.retrieve(batchJobOrId) - } - - if (batchJob.status === BatchJobStatus.PRE_PROCESSED) { - return batchJob - } - - if (batchJob.status !== BatchJobStatus.CREATED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot mark a batch job as pre processed if it is not in created status" - ) - } - - batchJob = await this.updateStatus( - batchJobOrId, - BatchJobStatus.PRE_PROCESSED - ) - - if (batchJob.dry_run) { - return batchJob - } - - return await this.confirm(batchJob) - }) - } - - async setProcessing( - batchJobOrId: string | BatchJob - ): Promise { - return await this.atomicPhase_(async () => { - let batchJob: BatchJob = batchJobOrId as BatchJob - if (typeof batchJobOrId === "string") { - batchJob = await this.retrieve(batchJobOrId) - } - - if (batchJob.status !== BatchJobStatus.CONFIRMED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot mark a batch job as processing if the status is different that confirmed" - ) - } - - return await this.updateStatus(batchJob, BatchJobStatus.PROCESSING) - }) - } - - async setFailed( - batchJobOrId: string | BatchJob, - error?: BatchJobResultError | string - ): Promise { - return await this.atomicPhase_(async () => { - let batchJob = batchJobOrId as BatchJob - - if (error) { - if (typeof batchJobOrId === "string") { - batchJob = await this.retrieve(batchJobOrId) - } - - const result = batchJob.result ?? {} - - await this.update(batchJob, { - result: { - ...result, - errors: [...(result?.errors ?? []), error], - }, - }) - } - - return await this.updateStatus(batchJob, BatchJobStatus.FAILED) - }) - } - - async prepareBatchJobForProcessing( - data: CreateBatchJobInput, - req: Request - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const batchStrategy = this.strategyResolver_.resolveBatchJobByType( - data.type - ) - return await batchStrategy - .withTransaction(transactionManager) - .prepareBatchJobForProcessing(data, req) - }) - } - - protected async updateStatus( - batchJobOrId: BatchJob | string, - status: BatchJobStatus - ): Promise { - let batchJob: BatchJob = batchJobOrId as BatchJob - if (typeof batchJobOrId === "string") { - batchJob = await this.retrieve(batchJobOrId) - } - - const { entityColumnName, eventType } = - this.batchJobStatusMapToProps.get(status) || {} - - if (!entityColumnName || !eventType) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Unable to update the batch job status from ${batchJob.status} to ${status}. The status doesn't exist` - ) - } - - batchJob[entityColumnName] = new Date() - - const batchJobRepo = this.activeManager_.withRepository( - this.batchJobRepository_ - ) - batchJob = await batchJobRepo.save(batchJob) - batchJob.loadStatus() - - await this.eventBus_.withTransaction(this.activeManager_).emit(eventType, { - id: batchJob.id, - }) - - return batchJob - } -} - -export default BatchJobService diff --git a/packages/medusa/src/services/cart.ts b/packages/medusa/src/services/cart.ts deleted file mode 100644 index 0bc0aac145..0000000000 --- a/packages/medusa/src/services/cart.ts +++ /dev/null @@ -1,2984 +0,0 @@ -import { RemoteQueryFunction } from "@medusajs/types" -import { - FlagRouter, - isDefined, - MedusaError, - MedusaV2Flag, - promiseAll, -} from "@medusajs/utils" -import { isEmpty, isEqual } from "lodash" -import { DeepPartial, EntityManager, In, IsNull, Not } from "typeorm" -import { - CustomerService, - CustomShippingOptionService, - DiscountService, - EventBusService, - GiftCardService, - LineItemAdjustmentService, - LineItemService, - NewTotalsService, - PaymentProviderService, - PricingService, - ProductService, - ProductVariantInventoryService, - ProductVariantService, - RegionService, - SalesChannelService, - ShippingOptionService, - ShippingProfileService, - StoreService, - TaxProviderService, - TotalsService, -} from "." -import { IPriceSelectionStrategy, TransactionBaseService } from "../interfaces" -import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels" -import { - Address, - Cart, - Customer, - CustomShippingOption, - Discount, - DiscountRule, - DiscountRuleType, - LineItem, - PaymentSession, - PaymentSessionStatus, - SalesChannel, - ShippingMethod, -} from "../models" -import { AddressRepository } from "../repositories/address" -import { CartRepository } from "../repositories/cart" -import { LineItemRepository } from "../repositories/line-item" -import { PaymentSessionRepository } from "../repositories/payment-session" -import { ShippingMethodRepository } from "../repositories/shipping-method" -import { - CartCreateProps, - CartUpdateProps, - FilterableCartProps, - isCart, - LineItemUpdate, - LineItemValidateData, -} from "../types/cart" -import { - AddressPayload, - FindConfig, - TotalField, - WithRequiredProperty, -} from "../types/common" -import { PaymentSessionInput } from "../types/payment" -import { buildQuery, isString, setMetadata } from "../utils" -import { validateEmail } from "../utils/is-email" - -type InjectedDependencies = { - manager: EntityManager - cartRepository: typeof CartRepository - shippingMethodRepository: typeof ShippingMethodRepository - addressRepository: typeof AddressRepository - paymentSessionRepository: typeof PaymentSessionRepository - lineItemRepository: typeof LineItemRepository - eventBusService: EventBusService - salesChannelService: SalesChannelService - taxProviderService: TaxProviderService - paymentProviderService: PaymentProviderService - productService: ProductService - storeService: StoreService - featureFlagRouter: FlagRouter - productVariantService: ProductVariantService - regionService: RegionService - lineItemService: LineItemService - shippingOptionService: ShippingOptionService - shippingProfileService: ShippingProfileService - customerService: CustomerService - discountService: DiscountService - giftCardService: GiftCardService - totalsService: TotalsService - newTotalsService: NewTotalsService - customShippingOptionService: CustomShippingOptionService - lineItemAdjustmentService: LineItemAdjustmentService - priceSelectionStrategy: IPriceSelectionStrategy - productVariantInventoryService: ProductVariantInventoryService - pricingService: PricingService - remoteQuery: RemoteQueryFunction -} - -type TotalsConfig = { - force_taxes?: boolean -} - -/* Provides layer to manipulate carts. - * @implements BaseService - */ -class CartService extends TransactionBaseService { - static readonly Events = { - CUSTOMER_UPDATED: "cart.customer_updated", - CREATED: "cart.created", - UPDATED: "cart.updated", - } - - protected readonly shippingMethodRepository_: typeof ShippingMethodRepository - protected readonly cartRepository_: typeof CartRepository - protected readonly addressRepository_: typeof AddressRepository - protected readonly paymentSessionRepository_: typeof PaymentSessionRepository - protected readonly lineItemRepository_: typeof LineItemRepository - protected readonly eventBus_: EventBusService - protected readonly productVariantService_: ProductVariantService - protected readonly productService_: ProductService - protected readonly storeService_: StoreService - protected readonly salesChannelService_: SalesChannelService - protected readonly regionService_: RegionService - protected readonly lineItemService_: LineItemService - protected readonly paymentProviderService_: PaymentProviderService - protected readonly customerService_: CustomerService - protected readonly shippingOptionService_: ShippingOptionService - protected readonly shippingProfileService_: ShippingProfileService - protected readonly discountService_: DiscountService - protected readonly giftCardService_: GiftCardService - protected readonly taxProviderService_: TaxProviderService - protected readonly totalsService_: TotalsService - protected readonly newTotalsService_: NewTotalsService - protected readonly customShippingOptionService_: CustomShippingOptionService - protected readonly priceSelectionStrategy_: IPriceSelectionStrategy - protected readonly lineItemAdjustmentService_: LineItemAdjustmentService - protected readonly featureFlagRouter_: FlagRouter - protected remoteQuery_: RemoteQueryFunction - // eslint-disable-next-line max-len - protected readonly productVariantInventoryService_: ProductVariantInventoryService - protected readonly pricingService_: PricingService - - constructor({ - cartRepository, - shippingMethodRepository, - lineItemRepository, - eventBusService, - paymentProviderService, - productService, - productVariantService, - taxProviderService, - regionService, - lineItemService, - shippingOptionService, - shippingProfileService, - customerService, - discountService, - giftCardService, - totalsService, - newTotalsService, - addressRepository, - paymentSessionRepository, - customShippingOptionService, - lineItemAdjustmentService, - priceSelectionStrategy, - salesChannelService, - featureFlagRouter, - storeService, - remoteQuery, - productVariantInventoryService, - pricingService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.shippingMethodRepository_ = shippingMethodRepository - this.cartRepository_ = cartRepository - this.lineItemRepository_ = lineItemRepository - this.eventBus_ = eventBusService - this.productVariantService_ = productVariantService - this.productService_ = productService - this.regionService_ = regionService - this.lineItemService_ = lineItemService - this.paymentProviderService_ = paymentProviderService - this.customerService_ = customerService - this.shippingOptionService_ = shippingOptionService - this.shippingProfileService_ = shippingProfileService - this.discountService_ = discountService - this.giftCardService_ = giftCardService - this.totalsService_ = totalsService - this.newTotalsService_ = newTotalsService - this.addressRepository_ = addressRepository - this.paymentSessionRepository_ = paymentSessionRepository - this.customShippingOptionService_ = customShippingOptionService - this.taxProviderService_ = taxProviderService - this.lineItemAdjustmentService_ = lineItemAdjustmentService - this.priceSelectionStrategy_ = priceSelectionStrategy - this.salesChannelService_ = salesChannelService - this.featureFlagRouter_ = featureFlagRouter - this.storeService_ = storeService - this.productVariantInventoryService_ = productVariantInventoryService - this.pricingService_ = pricingService - this.remoteQuery_ = remoteQuery - } - - /** - * @param selector - the query object for find - * @param config - config object - * @return the result of the find operation - */ - async list( - selector: FilterableCartProps, - config: FindConfig = {} - ): Promise { - const cartRepo = this.activeManager_.withRepository(this.cartRepository_) - - const query = buildQuery(selector, config) - - return await cartRepo.find(query) - } - - /** - * Gets a cart by id. - * @param cartId - the id of the cart to get. - * @param options - the options to get a cart - * @param totalsConfig - * @return the cart document. - */ - async retrieve( - cartId: string, - options: FindConfig = {}, - totalsConfig: TotalsConfig = {} - ): Promise { - if (!isDefined(cartId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"cartId" must be defined` - ) - } - - if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) { - if (Array.isArray(options.relations)) { - for (let i = 0; i < options.relations.length; i++) { - if (options.relations[i].startsWith("items.variant")) { - options.relations[i] = "items" - } - } - } - options.relations = [...new Set(options.relations)] - } - - const { totalsToSelect } = this.transformQueryForTotals_(options) - - if (totalsToSelect.length) { - return await this.retrieveLegacy(cartId, options, totalsConfig) - } - - const cartRepo = this.activeManager_.withRepository(this.cartRepository_) - - const query = buildQuery({ id: cartId }, options) - - if ((options.select || []).length === 0) { - query.select = undefined - } - - const queryRelations = { ...query.relations } - delete query.relations - - const raw = await cartRepo.findOneWithRelations(queryRelations, query) - - if (!raw) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Cart with ${cartId} was not found` - ) - } - - return raw - } - - /** - * @deprecated - * @param cartId - * @param options - * @param totalsConfig - * @protected - */ - protected async retrieveLegacy( - cartId: string, - options: FindConfig = {}, - totalsConfig: TotalsConfig = {} - ): Promise { - const cartRepo = this.activeManager_.withRepository(this.cartRepository_) - - const { select, relations, totalsToSelect } = - this.transformQueryForTotals_(options) - - const query = buildQuery({ id: cartId }, { - ...options, - select, - relations, - } as FindConfig) - - const raw = await cartRepo.findOne(query) - - if (!raw) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Cart with ${cartId} was not found` - ) - } - - return await this.decorateTotals_(raw, totalsToSelect, totalsConfig) - } - - async retrieveWithTotals( - cartId: string, - options: FindConfig = {}, - totalsConfig: TotalsConfig = {} - ): Promise> { - const relations = this.getTotalsRelations(options) - - const opt = { ...options, relations } - - if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) { - if (Array.isArray(opt.relations)) { - for (let i = 0; i < opt.relations.length; i++) { - if (opt.relations[i].startsWith("items.variant")) { - opt.relations[i] = "items" - } - } - } - - opt.relations = [...new Set(opt.relations)] - } - - const cart = await this.retrieve(cartId, opt) - - return await this.decorateTotals(cart, totalsConfig) - } - - /** - * Creates a cart. - * @param data - the data to create the cart with - * @return the result of the create operation - */ - async create(data: CartCreateProps): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cartRepo = transactionManager.withRepository(this.cartRepository_) - const addressRepo = transactionManager.withRepository( - this.addressRepository_ - ) - - const rawCart: DeepPartial = { - context: data.context ?? {}, - } - - if ( - this.featureFlagRouter_.isFeatureEnabled( - SalesChannelFeatureFlag.key - ) && - !this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key) - ) { - rawCart.sales_channel_id = ( - await this.getValidatedSalesChannel(data.sales_channel_id) - ).id - } - - if (data.customer_id || data.customer) { - const customer = (data.customer ?? - (data.customer_id && - (await this.customerService_ - .withTransaction(transactionManager) - .retrieve(data.customer_id) - .catch(() => undefined)))) as Customer - - rawCart.customer = customer - rawCart.customer_id = customer?.id - rawCart.email = customer?.email - } - - if (!rawCart.email && data.email) { - const customer = await this.createOrFetchGuestCustomerFromEmail_( - data.email - ) - rawCart.customer = customer - rawCart.customer_id = customer.id - rawCart.email = customer.email - } - - if (!data.region_id && !data.region) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `A region_id must be provided when creating a cart` - ) - } - - rawCart.region_id = data.region_id - const region = data.region - ? data.region - : await this.regionService_ - .withTransaction(transactionManager) - .retrieve(data.region_id!, { - relations: ["countries"], - }) - const regCountries = region.countries.map(({ iso_2 }) => iso_2) - - if (!data.shipping_address && !data.shipping_address_id) { - if (region.countries.length === 1) { - rawCart.shipping_address = addressRepo.create({ - country_code: regCountries[0], - }) - } - } else { - if (data.shipping_address) { - if (!regCountries.includes(data.shipping_address.country_code!)) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Shipping country not in region" - ) - } - rawCart.shipping_address = data.shipping_address - } - if (data.shipping_address_id) { - const addr = await addressRepo.findOne({ - where: { id: data.shipping_address_id }, - }) - if ( - addr?.country_code && - !regCountries.includes(addr.country_code) - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Shipping country not in region" - ) - } - rawCart.shipping_address_id = data.shipping_address_id - } - } - - if (data.billing_address) { - if (!regCountries.includes(data.billing_address.country_code!)) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Billing country not in region" - ) - } - rawCart.billing_address = data.billing_address - } - if (data.billing_address_id) { - const addr = await addressRepo.findOne({ - where: { id: data.billing_address_id }, - }) - if (addr?.country_code && !regCountries.includes(addr.country_code)) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Billing country not in region" - ) - } - rawCart.billing_address_id = data.billing_address_id - } - - const remainingFields: (keyof Cart)[] = [ - "context", - "type", - "metadata", - "discounts", - "gift_cards", - ] - - for (const remainingField of remainingFields) { - if (isDefined(data[remainingField]) && remainingField !== "object") { - const key = remainingField as string - rawCart[key] = data[remainingField] - } - } - - const createdCart = cartRepo.create(rawCart) - const cart = await cartRepo.save(createdCart) - - if ( - this.featureFlagRouter_.isFeatureEnabled([ - SalesChannelFeatureFlag.key, - MedusaV2Flag.key, - ]) - ) { - const salesChannel = await this.getValidatedSalesChannel( - data.sales_channel_id - ) - - cart.sales_channel_id = salesChannel.id - } - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.CREATED, { - id: cart.id, - }) - return cart - } - ) - } - - protected async getValidatedSalesChannel( - salesChannelId?: string - ): Promise { - let salesChannel: SalesChannel - if (isDefined(salesChannelId)) { - if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) { - const query = { - sales_channel: { - __args: { - id: salesChannelId, - }, - }, - } - ;[salesChannel] = await this.remoteQuery_(query) - } else { - salesChannel = await this.salesChannelService_ - .withTransaction(this.activeManager_) - .retrieve(salesChannelId) - } - } else { - salesChannel = ( - await this.storeService_.withTransaction(this.activeManager_).retrieve({ - relations: ["default_sales_channel"], - }) - ).default_sales_channel - } - - if (salesChannel.is_disabled) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Unable to assign the cart to a disabled Sales Channel "${salesChannel.name}"` - ) - } - - return salesChannel - } - - /** - * Removes a line item from the cart. - * @param cartId - the id of the cart that we will remove from - * @param lineItemId - the line item(s) to remove. - * @return the result of the update operation - */ - async removeLineItem( - cartId: string, - lineItemId: string | string[] - ): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cart = await this.retrieve(cartId, { - relations: ["items.variant.product.profiles", "shipping_methods"], - }) - - const lineItemIdsToRemove = new Set( - Array.isArray(lineItemId) ? lineItemId : [lineItemId] - ) - - const lineItems = cart.items.filter((item) => - lineItemIdsToRemove.has(item.id) - ) - - if (!lineItems.length) { - return - } - - if (cart.shipping_methods?.length) { - await this.shippingOptionService_ - .withTransaction(transactionManager) - .deleteShippingMethods(cart.shipping_methods) - } - - const lineItemRepository = transactionManager.withRepository( - this.lineItemRepository_ - ) - await lineItemRepository.update( - { - id: In(cart.items.map((item) => item.id)), - }, - { - has_shipping: false, - } - ) - - await this.lineItemService_ - .withTransaction(transactionManager) - .delete([...lineItemIdsToRemove]) - - const result = await this.retrieve(cartId, { - relations: [ - "items.variant.product.profiles", - "discounts.rule", - "region", - ], - }) - - await this.refreshAdjustments_(result) - - // Notify subscribers - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, { - id: cart.id, - }) - } - ) - } - - /** - * Checks if a given line item has a shipping method that can fulfill it. - * Returns true if all products in the cart can be fulfilled with the current - * shipping methods. - * @param shippingMethods - the set of shipping methods to check from - * @param lineItemShippingProfiledId - the line item - * @return boolean representing whether shipping method is validated - */ - protected validateLineItemShipping_( - shippingMethods: ShippingMethod[], - lineItemShippingProfiledId: string - ): boolean { - if (!lineItemShippingProfiledId) { - return true - } - - if ( - shippingMethods && - shippingMethods.length && - lineItemShippingProfiledId - ) { - const selectedProfiles = shippingMethods.map( - ({ shipping_option }) => shipping_option.profile_id - ) - return selectedProfiles.includes(lineItemShippingProfiledId) - } - - return false - } - - /** - * Check if line item's variant belongs to the cart's sales channel. - * - * @param sales_channel_id - the cart for the line item - * @param lineItem - the line item being added - * @return a boolean indicating validation result - */ - protected async validateLineItem( - { sales_channel_id }: { sales_channel_id: string | null }, - lineItem: LineItemValidateData - ): Promise { - if (!sales_channel_id || !lineItem.variant_id) { - return true - } - - const lineItemVariant = lineItem.variant?.product_id - ? lineItem.variant - : await this.productVariantService_ - .withTransaction(this.activeManager_) - .retrieve(lineItem.variant_id, { select: ["id", "product_id"] }) - - return !!( - await this.productService_ - .withTransaction(this.activeManager_) - .filterProductsBySalesChannel( - [lineItemVariant.product_id], - sales_channel_id - ) - ).length - } - - /** - * Adds a line item to the cart. - * @param cartId - the id of the cart that we will add to - * @param lineItem - the line item to add. - * @param config - * validateSalesChannels - should check if product belongs to the same sales channel as cart - * (if cart has associated sales channel) - * @return the result of the update operation - * @deprecated Use {@link addOrUpdateLineItems} instead. - */ - async addLineItem( - cartId: string, - lineItem: LineItem, - config = { validateSalesChannels: true } - ): Promise { - const fields: (keyof Cart)[] = ["id"] - const relations: (keyof Cart)[] = ["shipping_methods"] - - if (this.featureFlagRouter_.isFeatureEnabled("sales_channels")) { - if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) { - relations.push("sales_channels") - } else { - fields.push("sales_channel_id") - } - } - - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - let cart = await this.retrieve(cartId, { - select: fields, - relations, - }) - - if (this.featureFlagRouter_.isFeatureEnabled("sales_channels")) { - if (config.validateSalesChannels) { - if (lineItem.variant_id) { - const lineItemIsValid = await this.validateLineItem( - cart, - lineItem as LineItemValidateData - ) - - if (!lineItemIsValid) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `The product "${lineItem.title}" must belongs to the sales channel on which the cart has been created.` - ) - } - } - } - } - - const lineItemServiceTx = - this.lineItemService_.withTransaction(transactionManager) - - let currentItem: LineItem | undefined - if (lineItem.should_merge) { - const [existingItem] = await lineItemServiceTx.list( - { - cart_id: cart.id, - variant_id: lineItem.variant_id, - should_merge: true, - }, - { take: 1, select: ["id", "metadata", "quantity"] } - ) - if ( - existingItem && - isEqual(existingItem.metadata, lineItem.metadata) - ) { - currentItem = existingItem - } - } - - // If content matches one of the line items currently in the cart we can - // simply update the quantity of the existing line item - const quantity = currentItem - ? (currentItem.quantity += lineItem.quantity) - : lineItem.quantity - - // Confirm inventory or throw error - if (lineItem.variant_id) { - const isCovered = - await this.productVariantInventoryService_.confirmInventory( - lineItem.variant_id, - quantity, - { salesChannelId: cart.sales_channel_id } - ) - - if (!isCovered) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Variant with id: ${lineItem.variant_id} does not have the required inventory`, - MedusaError.Codes.INSUFFICIENT_INVENTORY - ) - } - } - - if (currentItem) { - await lineItemServiceTx.update(currentItem.id, { - quantity: currentItem.quantity, - }) - } else { - await lineItemServiceTx.create({ - ...lineItem, - has_shipping: false, - cart_id: cart.id, - }) - } - - await lineItemServiceTx - .update( - { cart_id: cartId, has_shipping: true }, - { has_shipping: false } - ) - .catch((err: Error | MedusaError) => { - // We only want to catch the errors related to not found items since we don't care if there is not item to update - if ("type" in err && err.type === MedusaError.Types.NOT_FOUND) { - return - } - throw err - }) - - if (cart.shipping_methods?.length) { - await this.shippingOptionService_ - .withTransaction(transactionManager) - .deleteShippingMethods(cart.shipping_methods) - } - - cart = await this.retrieve(cart.id, { - relations: [ - "items.variant.product.profiles", - "discounts", - "discounts.rule", - "region", - ], - }) - - await this.refreshAdjustments_(cart) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, { id: cart.id }) - } - ) - } - - /** - * Adds or update one or multiple line items to the cart. It also update all existing items in the cart - * to have has_shipping to false. Finally, the adjustments will be updated. - * @param cartId - the id of the cart that we will add to - * @param lineItems - the line items to add. - * @param config - * validateSalesChannels - should check if product belongs to the same sales channel as cart - * (if cart has associated sales channel) - * @return the result of the update operation - */ - async addOrUpdateLineItems( - cartId: string, - lineItems: LineItem | LineItem[], - config = { validateSalesChannels: true } - ): Promise { - const items: LineItem[] = Array.isArray(lineItems) ? lineItems : [lineItems] - - const fields: (keyof Cart)[] = ["id", "customer_id", "region_id"] - const relations: (keyof Cart)[] = ["shipping_methods"] - - if (this.featureFlagRouter_.isFeatureEnabled("sales_channels")) { - if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) { - relations.push("sales_channels") - } else { - fields.push("sales_channel_id") - } - } - - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - let cart = await this.retrieve(cartId, { - select: fields, - relations, - }) - - if (this.featureFlagRouter_.isFeatureEnabled("sales_channels")) { - if (config.validateSalesChannels) { - const areValid = await promiseAll( - items.map(async (item) => { - if (item.variant_id) { - return await this.validateLineItem( - cart, - item as LineItemValidateData - ) - } - return true - }) - ) - - const invalidProducts = areValid - .map((valid, index) => { - return !valid ? { title: items[index].title } : undefined - }) - .filter((v): v is { title: string } => !!v) - - if (invalidProducts.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `The products [${invalidProducts - .map((item) => item.title) - .join( - " - " - )}] must belongs to the sales channel on which the cart has been created.` - ) - } - } - } - - const lineItemServiceTx = - this.lineItemService_.withTransaction(transactionManager) - const productVariantInventoryServiceTx = - this.productVariantInventoryService_.withTransaction( - transactionManager - ) - - const existingItems = await lineItemServiceTx.list( - { - cart_id: cart.id, - variant_id: In(items.map((item) => item.variant_id)), - should_merge: true, - }, - { select: ["id", "metadata", "quantity", "variant_id"] } - ) - - const existingItemsVariantMap = new Map() - existingItems.forEach((item) => { - existingItemsVariantMap.set(item.variant_id, item) - }) - - const lineItemsToCreate: LineItem[] = [] - const lineItemsToUpdate: { [id: string]: LineItem }[] = [] - for (const item of items) { - let currentItem: LineItem | undefined - - const existingItem = existingItemsVariantMap.get(item.variant_id) - if (item.should_merge) { - if (existingItem && isEqual(existingItem.metadata, item.metadata)) { - currentItem = existingItem - } - } - - // If content matches one of the line items currently in the cart we can - // simply update the quantity of the existing line item - item.quantity = currentItem - ? (currentItem.quantity += item.quantity) - : item.quantity - - if (item.variant_id) { - const isSufficient = - await productVariantInventoryServiceTx.confirmInventory( - item.variant_id, - item.quantity, - { salesChannelId: cart.sales_channel_id } - ) - - if (!isSufficient) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Variant with id: ${item.variant_id} does not have the required inventory`, - MedusaError.Codes.INSUFFICIENT_INVENTORY - ) - } - } - - if (currentItem) { - const variantsPricing = await this.pricingService_ - .withTransaction(transactionManager) - .getProductVariantsPricing( - [ - { - variantId: item.variant_id!, - quantity: item.quantity, - }, - ], - { - region_id: cart.region_id, - customer_id: cart.customer_id, - include_discount_prices: true, - } - ) - - const { calculated_price } = - variantsPricing[currentItem.variant_id!] - - lineItemsToUpdate[currentItem.id] = { - quantity: item.quantity, - has_shipping: false, - } - - if (isDefined(calculated_price)) { - lineItemsToUpdate[currentItem.id].unit_price = calculated_price - } - } else { - // Since the variant is eager loaded, we are removing it before the line item is being created. - delete (item as Partial).variant - item.has_shipping = false - item.cart_id = cart.id - lineItemsToCreate.push(item) - } - } - - const itemKeysToUpdate = Object.keys(lineItemsToUpdate) - - // Update all items that needs to be updated - if (itemKeysToUpdate.length) { - await promiseAll( - itemKeysToUpdate.map(async (id) => { - return await lineItemServiceTx.update(id, lineItemsToUpdate[id]) - }) - ) - } - - // Create all items that needs to be created - await lineItemServiceTx.create(lineItemsToCreate) - - await lineItemServiceTx - .update( - { - cart_id: cartId, - has_shipping: true, - }, - { has_shipping: false } - ) - .catch((err: Error | MedusaError) => { - // We only want to catch the errors related to not found items since we don't care if there is not item to update - if ("type" in err && err.type === MedusaError.Types.NOT_FOUND) { - return - } - throw err - }) - - if (cart.shipping_methods?.length) { - await this.shippingOptionService_ - .withTransaction(transactionManager) - .deleteShippingMethods(cart.shipping_methods) - } - - cart = await this.retrieve(cart.id, { - relations: [ - "items.variant.product.profiles", - "discounts", - "discounts.rule", - "region", - ], - }) - - await this.refreshAdjustments_(cart) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, { id: cart.id }) - } - ) - } - - /** - * Updates a cart's existing line item. - * @param cartId - the id of the cart to update - * @param lineItemId - the id of the line item to update. - * @param update - the line item to update. Must include an id field. - * @return the result of the update operation - */ - async updateLineItem( - cartId: string, - lineItemId: string, - update: LineItemUpdate - ): Promise { - const { should_calculate_prices, ...lineItemUpdate } = update - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const select: (keyof Cart)[] = ["id", "region_id", "customer_id"] - if ( - this.featureFlagRouter_.isFeatureEnabled(SalesChannelFeatureFlag.key) - ) { - select.push("sales_channel_id") - } - - const cart = await this.retrieve(cartId, { - select: select, - relations: ["shipping_methods"], - }) - - const lineItem = await this.lineItemService_.retrieve(lineItemId, { - select: ["id", "quantity", "variant_id", "cart_id"], - }) - - if (lineItem.cart_id !== cartId) { - // Ensure that the line item exists in the cart - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "A line item with the provided id doesn't exist in the cart" - ) - } - - if (lineItemUpdate.quantity) { - if (lineItem.variant_id) { - const hasInventory = - await this.productVariantInventoryService_.confirmInventory( - lineItem.variant_id, - lineItemUpdate.quantity, - { salesChannelId: cart.sales_channel_id } - ) - - if (!hasInventory) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Inventory doesn't cover the desired quantity", - MedusaError.Codes.INSUFFICIENT_INVENTORY - ) - } - - if (should_calculate_prices) { - const variantsPricing = await this.pricingService_ - .withTransaction(transactionManager) - .getProductVariantsPricing( - [ - { - variantId: lineItem.variant_id, - quantity: lineItemUpdate.quantity, - }, - ], - { - region_id: cart.region_id, - customer_id: cart.customer_id, - include_discount_prices: true, - } - ) - - const { calculated_price } = variantsPricing[lineItem.variant_id] - lineItemUpdate.unit_price = calculated_price ?? undefined - } - } - } - - if (cart.shipping_methods?.length) { - await this.shippingOptionService_ - .withTransaction(transactionManager) - .deleteShippingMethods(cart.shipping_methods) - } - - await this.lineItemService_ - .withTransaction(transactionManager) - .update(lineItemId, lineItemUpdate) - - const updatedCart = await this.retrieve(cartId, { - relations: [ - "items.variant.product.profiles", - "discounts", - "discounts.rule", - "region", - ], - }) - - await this.refreshAdjustments_(updatedCart) - - // Update the line item - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, updatedCart) - - return updatedCart - } - ) - } - - /** - * Ensures shipping total on cart is correct in regards to a potential free - * shipping discount - * If a free shipping is present, we set shipping methods price to 0 - * if a free shipping was present, we set shipping methods to original amount - * @param cart - the cart to adjust free shipping for - * @param shouldAdd - flag to indicate, if we should add or remove - * @return void - */ - protected async adjustFreeShipping_( - cart: Cart, - shouldAdd: boolean - ): Promise { - if (cart.shipping_methods?.length) { - const shippingMethodRepository = this.activeManager_.withRepository( - this.shippingMethodRepository_ - ) - - // if any free shipping discounts, we ensure to update shipping method amount - if (shouldAdd) { - await shippingMethodRepository.update( - { - id: In( - cart.shipping_methods.map((shippingMethod) => shippingMethod.id) - ), - }, - { - price: 0, - } - ) - } else { - await promiseAll( - cart.shipping_methods.map(async (shippingMethod) => { - // if free shipping discount is removed, we adjust the shipping - // back to its original amount - // if shipping option amount is null, we assume the option is calculated - shippingMethod.price = - shippingMethod.shipping_option.amount ?? - (await this.shippingOptionService_.getPrice_( - shippingMethod.shipping_option, - shippingMethod.data, - cart - )) - return shippingMethodRepository.save(shippingMethod) - }) - ) - } - } - } - - async update(cartOrId: string | Cart, data: CartUpdateProps): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cartRepo = transactionManager.withRepository(this.cartRepository_) - const relations = [ - "items.variant.product.profiles", - "shipping_methods", - "shipping_methods.shipping_option", - "shipping_address", - "billing_address", - "gift_cards", - "customer", - "region", - "payment_sessions", - "region.countries", - "discounts", - "discounts.rule", - ] - - const cart = !isString(cartOrId) - ? cartOrId - : await this.retrieve(cartOrId, { - relations, - }) - - const originalCartCustomer = { ...(cart.customer ?? {}) } - if (data.customer_id) { - await this.updateCustomerId_(cart, data.customer_id) - } else if (isDefined(data.email)) { - const customer = await this.createOrFetchGuestCustomerFromEmail_( - data.email - ) - cart.customer = customer - cart.customer_id = customer.id - cart.email = customer.email - } - - if (isDefined(data.customer_id) || isDefined(data.region_id)) { - await this.updateUnitPrices_(cart, data.region_id, data.customer_id) - } - - if (isDefined(data.region_id) && cart.region_id !== data.region_id) { - const shippingAddress = - typeof data.shipping_address !== "string" - ? data.shipping_address - : {} - const countryCode = - (data.country_code || shippingAddress?.country_code) ?? null - await this.setRegion_(cart, data.region_id, countryCode) - } - - const addrRepo = transactionManager.withRepository( - this.addressRepository_ - ) - - const billingAddress = data.billing_address_id ?? data.billing_address - if (billingAddress !== undefined) { - await this.updateBillingAddress_(cart, billingAddress, addrRepo) - } - - const shippingAddress = - data.shipping_address_id ?? data.shipping_address - if (shippingAddress !== undefined) { - await this.updateShippingAddress_(cart, shippingAddress, addrRepo) - } - - if ( - this.featureFlagRouter_.isFeatureEnabled( - SalesChannelFeatureFlag.key - ) && - isDefined(data.sales_channel_id) && - data.sales_channel_id != cart.sales_channel_id - ) { - const salesChannel = await this.getValidatedSalesChannel( - data.sales_channel_id - ) - - await this.onSalesChannelChange(cart, data.sales_channel_id) - - cart.sales_channel_id = salesChannel.id - } - - if (isDefined(data.discounts) && data.discounts.length) { - const previousDiscounts = [...cart.discounts] - cart.discounts.length = 0 - - await this.applyDiscounts( - cart, - data.discounts.map((d) => d.code) - ) - - const hasFreeShipping = cart.discounts.some( - ({ rule }) => rule?.type === DiscountRuleType.FREE_SHIPPING - ) - - // if we previously had a free shipping discount and then removed it, - // we need to update shipping methods to original price - if ( - previousDiscounts.some( - ({ rule }) => rule.type === DiscountRuleType.FREE_SHIPPING - ) && - !hasFreeShipping - ) { - await this.adjustFreeShipping_(cart, false) - } - - if (hasFreeShipping) { - await this.adjustFreeShipping_(cart, true) - } - } else if (isDefined(data.discounts) && !data.discounts.length) { - cart.discounts.length = 0 - await this.refreshAdjustments_(cart) - } - - if ("gift_cards" in data) { - cart.gift_cards = [] - - await promiseAll( - (data.gift_cards ?? []).map(async ({ code }) => { - return this.applyGiftCard_(cart, code) - }) - ) - } - - if (data?.metadata) { - cart.metadata = setMetadata(cart, data.metadata) - } - - if ("context" in data) { - const prevContext = cart.context || {} - cart.context = { - ...prevContext, - ...data.context, - } - } - - if ("completed_at" in data) { - cart.completed_at = data.completed_at! - } - - if ("payment_authorized_at" in data) { - cart.payment_authorized_at = data.payment_authorized_at! - } - - const updatedCart = await cartRepo.save(cart) - - if ( - (data.email && data.email !== originalCartCustomer.email) || - (data.customer_id && data.customer_id !== originalCartCustomer.id) - ) { - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.CUSTOMER_UPDATED, updatedCart.id) - } - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, updatedCart) - - return updatedCart - } - ) - } - - /** - * Remove the cart line item that does not belongs to the newly assigned sales channel - * - * @param cart - The cart being updated - * @param newSalesChannelId - The new sales channel being assigned to the cart - * @return void - * @protected - */ - protected async onSalesChannelChange( - cart: Cart, - newSalesChannelId: string - ): Promise { - await this.getValidatedSalesChannel(newSalesChannelId) - - const productIds = cart.items.map((item) => item.variant.product_id) - const productsToKeep = await this.productService_ - .withTransaction(this.activeManager_) - .filterProductsBySalesChannel(productIds, newSalesChannelId, { - select: ["id"], - take: productIds.length, - }) - const productIdsToKeep = new Set( - productsToKeep.map((product) => product.id) - ) - const itemsToRemove = cart.items.filter((item) => { - return !productIdsToKeep.has(item.variant.product_id) - }) - - if (!itemsToRemove.length) { - return - } - - const itemIdsToRemove = new Set(itemsToRemove.map((item) => item.id)) - await this.removeLineItem(cart.id, [...itemIdsToRemove]) - cart.items = cart.items.filter((item) => !itemIdsToRemove.has(item.id)) - } - - /** - * Sets the customer id of a cart - * @param cart - the cart to add email to - * @param customerId - the customer to add to cart - * @return the result of the update operation - */ - protected async updateCustomerId_( - cart: Cart, - customerId: string - ): Promise { - const customer = await this.customerService_ - .withTransaction(this.activeManager_) - .retrieve(customerId) - - cart.customer = customer - cart.customer_id = customer.id - cart.email = customer.email - } - - /** - * Creates or fetches a user based on an email. - * @param email - the email to use - * @return the resultign customer object - */ - protected async createOrFetchGuestCustomerFromEmail_( - email: string - ): Promise { - const validatedEmail = validateEmail(email) - - const customerServiceTx = this.customerService_.withTransaction( - this.activeManager_ - ) - - let customer = await customerServiceTx - .retrieveUnregisteredByEmail(validatedEmail) - .catch(() => undefined) - - if (!customer) { - customer = await customerServiceTx.create({ email: validatedEmail }) - } - - return customer - } - - /** - * Updates the cart's billing address. - * @param cart - the cart to update - * @param addressOrId - the value to set the billing address to - * @param addrRepo - the repository to use for address updates - * @return the result of the update operation - */ - protected async updateBillingAddress_( - cart: Cart, - addressOrId: AddressPayload | Partial
| string, - addrRepo: typeof AddressRepository - ): Promise { - let address: Address - if (typeof addressOrId === `string`) { - address = (await addrRepo.findOne({ - where: { id: addressOrId }, - })) as Address - } else { - address = addressOrId as Address - } - - if (address.id) { - cart.billing_address = await addrRepo.save(address) - } else { - if (cart.billing_address_id) { - const addr = await addrRepo.findOne({ - where: { id: cart.billing_address_id }, - }) - - await addrRepo.save({ ...addr, ...address }) - } else { - cart.billing_address = addrRepo.create({ - ...address, - }) - } - } - } - - /** - * Updates the cart's shipping address. - * @param cart - the cart to update - * @param addressOrId - the value to set the shipping address to - * @param addrRepo - the repository to use for address updates - * @return the result of the update operation - */ - protected async updateShippingAddress_( - cart: Cart, - addressOrId: AddressPayload | Partial
| string, - addrRepo: typeof AddressRepository - ): Promise { - let address: Address - - if (addressOrId === null) { - cart.shipping_address = null - return - } - - if (typeof addressOrId === `string`) { - address = (await addrRepo.findOne({ - where: { id: addressOrId }, - })) as Address - } else { - address = addressOrId as Address - } - - if ( - address.country_code && - !cart.region.countries.find( - ({ iso_2 }) => address.country_code?.toLowerCase() === iso_2 - ) - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Shipping country must be in the cart region" - ) - } - - if (address.id) { - cart.shipping_address = await addrRepo.save(address) - } else { - if (cart.shipping_address_id) { - const addr = await addrRepo.findOne({ - where: { id: cart.shipping_address_id }, - }) - - await addrRepo.save({ ...addr, ...address }) - } else { - cart.shipping_address = addrRepo.create({ - ...address, - }) - } - } - } - - protected async applyGiftCard_(cart: Cart, code: string): Promise { - const giftCard = await this.giftCardService_ - .withTransaction(this.activeManager_) - .retrieveByCode(code) - - if (giftCard.is_disabled) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "The gift card is disabled" - ) - } - - if (giftCard.region_id !== cart.region_id) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "The gift card cannot be used in the current region" - ) - } - - // if discount is already there, we simply resolve - if (cart.gift_cards.find(({ id }) => id === giftCard.id)) { - return - } - - cart.gift_cards = [...cart.gift_cards, giftCard] - } - - /** - * Updates the cart's discounts. - * If discount besides free shipping is already applied, this - * will be overwritten - * Throws if discount regions does not include the cart region - * @param cart - the cart to update - * @param discountCode - the discount code - */ - async applyDiscount(cart: Cart, discountCode: string): Promise { - return await this.applyDiscounts(cart, [discountCode]) - } - - /** - * Updates the cart's discounts. - * If discount besides free shipping is already applied, this - * will be overwritten - * Throws if discount regions does not include the cart region - * @param cart - the cart to update - * @param discountCodes - the discount code(s) to apply - */ - async applyDiscounts(cart: Cart, discountCodes: string[]): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const discounts = await this.discountService_ - .withTransaction(transactionManager) - .listByCodes(discountCodes, { - relations: ["rule", "rule.conditions", "regions"], - }) - - await this.discountService_ - .withTransaction(transactionManager) - .validateDiscountForCartOrThrow(cart, discounts) - - const rules: Map = new Map() - const discountsMap = new Map( - discounts.map((d) => { - rules.set(d.id, d.rule) - return [d.id, d] - }) - ) - - cart.discounts.forEach((discount) => { - if (discountsMap.has(discount.id)) { - discountsMap.delete(discount.id) - } - }) - - const toParse = [...cart.discounts, ...discountsMap.values()] - - let sawNotShipping = false - const newDiscounts = toParse.map((discountToParse) => { - switch (discountToParse.rule?.type) { - case DiscountRuleType.FREE_SHIPPING: - if ( - discountToParse.rule.type === - rules.get(discountToParse.id)!.type - ) { - return discountsMap.get(discountToParse.id) - } - return discountToParse - default: - if (!sawNotShipping) { - sawNotShipping = true - if ( - rules.get(discountToParse.id)!.type !== - DiscountRuleType.FREE_SHIPPING - ) { - return discountsMap.get(discountToParse.id) - } - return discountToParse - } - return null - } - }) - - cart.discounts = newDiscounts.filter( - (newDiscount): newDiscount is Discount => { - return !!newDiscount - } - ) - - const hadNonFreeShippingDiscounts = [...rules.values()].some( - (rule) => rule.type !== DiscountRuleType.FREE_SHIPPING - ) - - if (hadNonFreeShippingDiscounts && cart?.items) { - await this.refreshAdjustments_(cart) - } - } - ) - } - - /** - * Removes a discount based on a discount code. - * @param cartId - the id of the cart to remove from - * @param discountCode - the discount code to remove - * @return the resulting cart - */ - async removeDiscount(cartId: string, discountCode: string): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cart = await this.retrieve(cartId, { - relations: [ - "items.variant.product.profiles", - "region", - "discounts", - "discounts.rule", - "payment_sessions", - "shipping_methods", - "shipping_methods.shipping_option", - ], - }) - - if ( - cart.discounts.some( - ({ rule }) => rule.type === DiscountRuleType.FREE_SHIPPING - ) - ) { - await this.adjustFreeShipping_(cart, false) - } - - cart.discounts = cart.discounts.filter( - (discount) => discount.code !== discountCode - ) - - const cartRepo = transactionManager.withRepository(this.cartRepository_) - const updatedCart = await cartRepo.save(cart) - - await this.refreshAdjustments_(updatedCart) - - if (cart.payment_sessions?.length) { - await this.setPaymentSessions(cartId) - } - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, updatedCart) - - return updatedCart - } - ) - } - - /** - * Updates the currently selected payment session. - * @param cartId - the id of the cart to update the payment session for - * @param update - the data to update the payment session with - * @return the resulting cart - */ - async updatePaymentSession( - cartId: string, - update: Record - ): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cart = await this.retrieve(cartId, { - relations: ["payment_sessions"], - }) - - if (cart.payment_session) { - await this.paymentProviderService_ - .withTransaction(transactionManager) - .updateSessionData(cart.payment_session, update) - } - - const updatedCart = await this.retrieve(cart.id) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, updatedCart) - return updatedCart - } - ) - } - - /** - * Authorizes a payment for a cart. - * Will authorize with chosen payment provider. This will return - * a payment object, that we will use to update our cart payment with. - * Additionally, if the payment does not require more or fails, we will - * set the payment on the cart. - * @param cartOrId - the id of the cart to authorize payment for - * @param context - object containing whatever is relevant for - * authorizing the payment with the payment provider. As an example, - * this could be IP address or similar for fraud handling. - * @return the resulting cart - */ - async authorizePayment( - cartOrId: string | WithRequiredProperty, - context: Record = { cart_id: "" } - ): Promise { - context = { - ...context, - cart_id: isString(cartOrId) ? cartOrId : cartOrId.id, - } - - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cartRepository = transactionManager.withRepository( - this.cartRepository_ - ) - - const cart = !isString(cartOrId) - ? cartOrId - : await this.retrieveWithTotals(cartOrId, { - relations: ["payment_sessions", "items.variant.product.profiles"], - }) - - // If cart total is 0, we don't perform anything payment related - if (cart.total! <= 0) { - cart.payment_authorized_at = new Date() - await cartRepository.save({ - id: cart.id, - payment_authorized_at: cart.payment_authorized_at, - }) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, cart) - - return cart - } - - if (!cart.payment_session) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "You cannot complete a cart without a payment session." - ) - } - - const session = (await this.paymentProviderService_ - .withTransaction(transactionManager) - .authorizePayment(cart.payment_session, context)) as PaymentSession - - const freshCart = (await this.retrieve(cart.id, { - relations: ["payment_sessions"], - })) as Cart & { payment_session: PaymentSession } - - if (session.status === "authorized") { - freshCart.payment = await this.paymentProviderService_ - .withTransaction(transactionManager) - .createPayment({ - cart_id: cart.id, - currency_code: cart.region.currency_code, - amount: cart.total!, - payment_session: freshCart.payment_session, - }) - freshCart.payment_authorized_at = new Date() - } - - const updatedCart = await cartRepository.save(freshCart) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, updatedCart) - - return updatedCart - } - ) - } - - /** - * Selects a payment session for a cart and creates a payment object in the external provider system - * @param cartId - the id of the cart to add payment method to - * @param providerId - the id of the provider to be set to the cart - */ - async setPaymentSession(cartId: string, providerId: string): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const psRepo = transactionManager.withRepository( - this.paymentSessionRepository_ - ) - - const cart = await this.retrieveWithTotals(cartId, { - relations: [ - "items.variant.product.profiles", - "customer", - "region", - "region.payment_providers", - "payment_sessions", - ], - }) - - const isProviderPresent = cart.region.payment_providers.find( - ({ id }) => providerId === id - ) - - if (providerId !== "system" && !isProviderPresent) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `The payment method is not available in this region` - ) - } - - let currentlySelectedSession = cart.payment_sessions.find( - (s) => s.is_selected - ) - - if ( - currentlySelectedSession && - currentlySelectedSession.provider_id !== providerId - ) { - const psRepo = transactionManager.withRepository( - this.paymentSessionRepository_ - ) - - if (currentlySelectedSession.is_initiated) { - await this.paymentProviderService_ - .withTransaction(transactionManager) - .deleteSession(currentlySelectedSession) - - currentlySelectedSession = psRepo.create(currentlySelectedSession) - } - - currentlySelectedSession.is_initiated = false - currentlySelectedSession.is_selected = false - await psRepo.save(currentlySelectedSession) - } - - const cartPaymentSessionIds = cart.payment_sessions.map((p) => p.id) - await psRepo.update( - { id: In(cartPaymentSessionIds) }, - { - is_selected: null, - is_initiated: false, - } - ) - - let paymentSession = cart.payment_sessions.find( - (ps) => ps.provider_id === providerId - ) - - if (!paymentSession) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Could not find payment session" - ) - } - - const sessionInput: PaymentSessionInput = { - cart, - customer: cart.customer, - amount: cart.total!, - currency_code: cart.region.currency_code, - provider_id: providerId, - payment_session_id: paymentSession.id, - } - - if (paymentSession.is_initiated) { - // update the session remotely - await this.paymentProviderService_ - .withTransaction(transactionManager) - .updateSession(paymentSession, sessionInput) - } else { - // Create the session remotely - paymentSession = await this.paymentProviderService_ - .withTransaction(transactionManager) - .createSession(sessionInput) - } - - await psRepo.update(paymentSession.id, { - is_selected: true, - is_initiated: true, - }) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, { id: cartId }) - } - ) - } - - /** - * Creates, updates and sets payment sessions associated with the cart. The - * first time the method is called payment sessions will be created for each - * provider. Additional calls will ensure that payment sessions have correct - * amounts, currencies, etc. as well as make sure to filter payment sessions - * that are not available for the cart's region. - * @param cartOrCartId - the id of the cart to set payment session for - * @return the result of the update operation. - */ - async setPaymentSessions( - cartOrCartId: WithRequiredProperty | string - ): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const psRepo = transactionManager.withRepository( - this.paymentSessionRepository_ - ) - - const paymentProviderServiceTx = - this.paymentProviderService_.withTransaction(transactionManager) - - const cart = !isString(cartOrCartId) - ? cartOrCartId - : await this.retrieveWithTotals( - cartOrCartId, - { - relations: [ - "items.variant.product.profiles", - "items.adjustments", - "discounts", - "discounts.rule", - "gift_cards", - "shipping_methods", - "shipping_methods.shipping_option", - "billing_address", - "shipping_address", - "region", - "region.tax_rates", - "region.payment_providers", - "payment_sessions", - "customer", - ], - }, - { force_taxes: true } - ) - - const { total, region } = cart - - // Helpers that either delete a session locally or remotely. Will be used in multiple places below. - const deleteSessionAppropriately = async (session) => { - if (session.is_initiated) { - return paymentProviderServiceTx.deleteSession(session) - } - - return psRepo.remove(session) - } - - // In the case of a cart that has a total <= 0 we can return prematurely. - // we are deleting the sessions, and we don't need to create or update anything from now on. - if (total <= 0) { - await promiseAll( - cart.payment_sessions.map(async (session) => { - return deleteSessionAppropriately(session) - }) - ) - return - } - - const providerSet = new Set(region.payment_providers.map((p) => p.id)) - const alreadyConsumedProviderIds: Set = new Set() - - const partialSessionInput: Omit = { - cart: cart as Cart, - customer: cart.customer, - amount: total, - currency_code: cart.region.currency_code, - } - const partialPaymentSessionData = { - cart_id: cart.id, - data: {}, - status: PaymentSessionStatus.PENDING, - amount: total, - } - - await promiseAll( - cart.payment_sessions.map(async (session) => { - if (!providerSet.has(session.provider_id)) { - /** - * if the provider does not belong to the region then delete the session. - * The deletion occurs locally if the session is not initiated - * otherwise the deletion will also occur remotely through the external provider. - */ - - return await deleteSessionAppropriately(session) - } - - /** - * if the provider belongs to the region then update or delete the session. - * The update occurs locally if it is not selected - * otherwise the update will also occur remotely through the external provider. - */ - - // We are saving the provider id on which the work below will be done. That way, - // when handling the providers from the cart region at a later point below, we do not double the work on the sessions that already - // exists for the same provider. - alreadyConsumedProviderIds.add(session.provider_id) - - // Update remotely - if (session.is_selected && session.is_initiated) { - const paymentSessionInput = { - ...partialSessionInput, - provider_id: session.provider_id, - } - - return paymentProviderServiceTx.updateSession( - session, - paymentSessionInput - ) - } - - let updatedSession: PaymentSession - - // At this stage the session is not selected. Delete it remotely if there is some - // external provider data and create the session locally only. Otherwise, update the existing local session. - if (session.is_initiated) { - await paymentProviderServiceTx.deleteSession(session) - updatedSession = psRepo.create({ - ...partialPaymentSessionData, - is_initiated: false, - provider_id: session.provider_id, - }) - } else { - updatedSession = { ...session, amount: total } as PaymentSession - } - - return psRepo.save(updatedSession) - }) - ) - - /** - * From now on, the sessions have been cleanup. We can now - * - Set the provider session as selected if it is the only one existing and there is no payment session on the cart - * - Create a session per provider locally if it does not already exists on the cart as per the previous step - */ - - // If only one provider exists and there is no session on the cart, create the session and select it. - if (region.payment_providers.length === 1 && !cart.payment_session) { - const paymentProvider = region.payment_providers[0] - - const paymentSessionInput = { - ...partialSessionInput, - provider_id: paymentProvider.id, - } - - const paymentSession = await this.paymentProviderService_ - .withTransaction(transactionManager) - .createSession(paymentSessionInput) - - await psRepo.update(paymentSession.id, { - is_selected: true, - is_initiated: true, - }) - return - } - - await promiseAll( - region.payment_providers.map(async (paymentProvider) => { - if (alreadyConsumedProviderIds.has(paymentProvider.id)) { - return - } - - const paymentSession = psRepo.create({ - ...partialPaymentSessionData, - provider_id: paymentProvider.id, - }) - return psRepo.save(paymentSession) - }) - ) - } - ) - } - - /** - * Removes a payment session from the cart. - * @param cartId - the id of the cart to remove from - * @param providerId - the id of the provider whose payment session - * should be removed. - * @return the resulting cart. - */ - async deletePaymentSession( - cartId: string, - providerId: string - ): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cart = await this.retrieve(cartId, { - relations: ["payment_sessions"], - }) - - const cartRepo = transactionManager.withRepository(this.cartRepository_) - - if (cart.payment_sessions) { - const paymentSession = cart.payment_sessions.find( - ({ provider_id }) => provider_id === providerId - ) - - cart.payment_sessions = cart.payment_sessions.filter( - ({ provider_id }) => provider_id !== providerId - ) - - const psRepo = transactionManager.withRepository( - this.paymentSessionRepository_ - ) - - if (paymentSession) { - if (paymentSession.is_selected || paymentSession.is_initiated) { - await this.paymentProviderService_ - .withTransaction(transactionManager) - .deleteSession(paymentSession) - } else { - await psRepo.delete({ id: paymentSession.id }) - } - } - } - - await cartRepo.save(cart) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, { id: cart.id }) - } - ) - } - - /** - * Refreshes a payment session on a cart - * @param cartId - the id of the cart to remove from - * @param providerId - the id of the provider whose payment session - * should be removed. - * @return {Promise} the resulting cart. - */ - async refreshPaymentSession( - cartId: string, - providerId: string - ): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cart = await this.retrieveWithTotals(cartId, { - relations: ["payment_sessions"], - }) - - if (cart.payment_sessions) { - const paymentSession = cart.payment_sessions.find( - ({ provider_id }) => provider_id === providerId - ) - - if (paymentSession) { - if (paymentSession.is_selected) { - await this.paymentProviderService_ - .withTransaction(transactionManager) - .refreshSession(paymentSession, { - cart: cart as Cart, - customer: cart.customer, - amount: cart.total, - currency_code: cart.region.currency_code, - provider_id: providerId, - }) - } else { - const psRepo = transactionManager.withRepository( - this.paymentSessionRepository_ - ) - await psRepo.update(paymentSession.id, { - amount: cart.total, - }) - } - } - } - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, { id: cartId }) - } - ) - } - - /** - * Adds the shipping method to the list of shipping methods associated with - * the cart. Shipping Methods are the ways that an order is shipped, whereas a - * Shipping Option is a possible way to ship an order. Shipping Methods may - * also have additional details in the data field such as an id for a package - * shop. - * @param cartOrId - the id of the cart to add shipping method to - * @param optionId - id of shipping option to add as valid method - * @param data - the fulmillment data for the method - * @return the result of the update operation - */ - async addShippingMethod( - cartOrId: string | Cart, - optionId: string, - data: Record = {} - ): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cart = !isString(cartOrId) - ? cartOrId - : await this.retrieveWithTotals(cartOrId, { - relations: [ - "shipping_methods", - "shipping_methods.shipping_option", - "items.variant.product.profiles", - "payment_sessions", - ], - }) - - const cartCustomShippingOptions = - await this.customShippingOptionService_ - .withTransaction(transactionManager) - .list({ cart_id: cart.id }) - - const customShippingOption = this.findCustomShippingOption( - cartCustomShippingOptions, - optionId - ) - - const { shipping_methods } = cart - - /** - * If we have a custom shipping option configured we want the price - * override to take effect and do not want `validateCartOption` to check - * if requirements are met, hence we are not passing the entire cart, but - * just the id. - */ - const shippingMethodConfig = customShippingOption - ? { cart_id: cart.id, price: customShippingOption.price } - : { cart } - - const newShippingMethod = await this.shippingOptionService_ - .withTransaction(transactionManager) - .createShippingMethod(optionId, data, shippingMethodConfig) - - const methods = [newShippingMethod] - if (shipping_methods?.length) { - const shippingOptionServiceTx = - this.shippingOptionService_.withTransaction(transactionManager) - - for (const shippingMethod of shipping_methods) { - if ( - shippingMethod.shipping_option.profile_id === - newShippingMethod.shipping_option.profile_id - ) { - await shippingOptionServiceTx.deleteShippingMethods( - shippingMethod - ) - } else { - methods.push(shippingMethod) - } - } - } - - if (cart.items?.length) { - const lineItemServiceTx = - this.lineItemService_.withTransaction(transactionManager) - - let productShippingProfileMap = new Map() - - if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) { - productShippingProfileMap = - await this.shippingProfileService_.getMapProfileIdsByProductIds( - cart.items.map((item) => item.variant.product_id) - ) - } else { - productShippingProfileMap = new Map( - cart.items.map((item) => [ - item.variant?.product?.id, - item.variant?.product?.profile_id, - ]) - ) - } - - await promiseAll( - cart.items.map(async (item) => { - return lineItemServiceTx.update(item.id, { - has_shipping: this.validateLineItemShipping_( - methods, - productShippingProfileMap.get(item.variant?.product_id)! - ), - }) - }) - ) - } - - const updatedCart = await this.retrieve(cart.id, { - relations: [ - "discounts", - "discounts.rule", - "shipping_methods", - "shipping_methods.shipping_option", - ], - }) - - // if cart has freeshipping, adjust price - if ( - updatedCart.discounts.some( - ({ rule }) => rule.type === DiscountRuleType.FREE_SHIPPING - ) - ) { - await this.adjustFreeShipping_(updatedCart, true) - } - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, updatedCart) - return updatedCart - }, - "SERIALIZABLE" - ) - } - - /** - * Finds the cart's custom shipping options based on the passed option id. - * throws if custom options is not empty and no shipping option corresponds to optionId - * @param cartCustomShippingOptions - the cart's custom shipping options - * @param optionId - id of the normal or custom shipping option to find in the cartCustomShippingOptions - * @return custom shipping option - */ - findCustomShippingOption( - cartCustomShippingOptions: CustomShippingOption[], - optionId: string - ): CustomShippingOption | undefined { - const customOption = cartCustomShippingOptions?.find( - (cso) => cso.shipping_option_id === optionId - ) - const hasCustomOptions = cartCustomShippingOptions?.length - - if (hasCustomOptions && !customOption) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Wrong shipping option" - ) - } - - return customOption - } - - protected async updateUnitPrices_( - cart: Cart, - regionId?: string, - customer_id?: string - ): Promise { - if (!cart.items?.length) { - return - } - - // If the cart contains items, we update the price of the items - // to match the updated region or customer id (keeping the old - // value if it exists) - - const region = await this.regionService_ - .withTransaction(this.activeManager_) - .retrieve(regionId || cart.region_id, { - relations: ["countries"], - }) - - const lineItemServiceTx = this.lineItemService_.withTransaction( - this.activeManager_ - ) - - const calculateVariantPriceData = cart.items - .filter((i) => i.variant_id) - .map((item) => { - return { variantId: item.variant_id!, quantity: item.quantity } - }) - - const availablePriceMap = await this.priceSelectionStrategy_ - .withTransaction(this.activeManager_) - .calculateVariantPrice(calculateVariantPriceData, { - region_id: region.id, - currency_code: region.currency_code, - customer_id: customer_id || cart.customer_id, - include_discount_prices: true, - }) - - cart.items = ( - await promiseAll( - cart.items.map(async (item) => { - if (!item.variant_id) { - return item - } - - const availablePrice = availablePriceMap.get(item.variant_id)! - - if ( - availablePrice !== undefined && - availablePrice.calculatedPrice !== null - ) { - return await lineItemServiceTx.update(item.id, { - has_shipping: false, - unit_price: availablePrice.calculatedPrice, - }) - } - - return await lineItemServiceTx.delete(item.id) - }) - ) - ) - .flat() - .filter((item): item is LineItem => !!item) - - cart.items = await lineItemServiceTx.list( - { id: cart.items.map((i) => i.id) }, - { - relations: ["variant.product.profiles"], - } - ) - } - - /** - * Set's the region of a cart. - * @param cart - the cart to set region on - * @param regionId - the id of the region to set the region to - * @param countryCode - the country code to set the country to - * @return the result of the update operation - */ - protected async setRegion_( - cart: Cart, - regionId: string, - countryCode: string | null - ): Promise { - if (cart.completed_at || cart.payment_authorized_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot change the region of a completed cart" - ) - } - - const region = await this.regionService_ - .withTransaction(this.activeManager_) - .retrieve(regionId, { - relations: ["countries"], - }) - cart.region = region - cart.region_id = region.id - - const addrRepo = this.activeManager_.withRepository(this.addressRepository_) - /* - * When changing the region you are changing the set of countries that your - * cart can be shipped to so we need to make sure that the current shipping - * address adheres to the new country set. - * - * First check if there is an existing shipping address on the cart if so - * fetch the entire thing so we can modify the shipping country - */ - let shippingAddress: Partial
= {} - if (cart.shipping_address_id) { - shippingAddress = (await addrRepo.findOne({ - where: { id: cart.shipping_address_id }, - })) as Address - } - - /* - * If the client has specified which country code we are updating to check - * that that country is in fact in the country and perform the update. - */ - if (countryCode !== null) { - if ( - !region.countries.find( - ({ iso_2 }) => iso_2 === countryCode.toLowerCase() - ) - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Country not available in region` - ) - } - - const updated = addrRepo.create({ - ...shippingAddress, - country_code: countryCode.toLowerCase(), - }) - - await addrRepo.save(updated) - await this.updateShippingAddress_(cart, updated, addrRepo) - } else { - /* - * In the case where the country code is not specified we need to check - * - * 1. if the region we are switching to has only one country preselect - * that - * 2. if the region has multiple countries we need to unset the country - * and wait for client to decide which country to use - */ - - let updated = { ...shippingAddress } - - // If the country code of a shipping address is set we need to clear it - if (!isEmpty(shippingAddress) && shippingAddress.country_code) { - updated = { - ...updated, - country_code: null, - } - } - - // If there is only one country in the region preset it - if (region.countries.length === 1) { - updated = { - ...updated, - country_code: region.countries[0].iso_2, - } - } - - await this.updateShippingAddress_(cart, updated, addrRepo) - } - - // Shipping methods are determined by region so the user needs to find a - // new shipping method - if (cart.shipping_methods && cart.shipping_methods.length) { - await this.shippingOptionService_ - .withTransaction(this.activeManager_) - .deleteShippingMethods(cart.shipping_methods) - } - - if (cart.discounts && cart.discounts.length) { - const discounts = await this.discountService_ - .withTransaction(this.activeManager_) - .list( - { - id: [...cart.discounts.map(({ id }) => id)], - }, - { relations: ["rule", "regions"] } - ) - - cart.discounts = discounts.filter((discount) => { - return discount.regions.find(({ id }) => id === regionId) - }) - } - - if (cart?.items?.length) { - // line item adjustments should be refreshed on region change after having filtered out inapplicable discounts - await this.refreshAdjustments_(cart) - } - - cart.gift_cards = [] - - if (cart.payment_sessions && cart.payment_sessions.length) { - const paymentSessionRepo = this.activeManager_.withRepository( - this.paymentSessionRepository_ - ) - await paymentSessionRepo.delete({ - id: In( - cart.payment_sessions.map((paymentSession) => paymentSession.id) - ), - }) - cart.payment_sessions.length = 0 - cart.payment_session = null - } - } - - /** - * Deletes a cart from the database. Completed carts cannot be deleted. - * @param cartId - the id of the cart to delete - * @return the deleted cart or undefined if the cart was not found. - */ - async delete(cartId: string): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cart = await this.retrieve(cartId, { - relations: [ - "items.variant.product.profiles", - "discounts", - "discounts.rule", - "payment_sessions", - ], - }) - - if (cart.completed_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Completed carts cannot be deleted" - ) - } - - if (cart.payment_authorized_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Can't delete a cart with an authorized payment" - ) - } - - const cartRepo = transactionManager.withRepository(this.cartRepository_) - return cartRepo.remove(cart) - } - ) - } - - /** - * Dedicated method to set metadata for a cart. - * To ensure that plugins does not overwrite each - * others metadata fields, setMetadata is provided. - * @param cartId - the cart to apply metadata to. - * @param key - key for metadata field - * @param value - value for metadata field. - * @return resolves to the updated result. - */ - async setMetadata( - cartId: string, - key: string, - value: string | number - ): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cartRepo = transactionManager.withRepository(this.cartRepository_) - - if (typeof key !== "string") { - throw new MedusaError( - MedusaError.Types.INVALID_ARGUMENT, - "Key type is invalid. Metadata keys must be strings" - ) - } - - const cart = await cartRepo.findOne({ where: { id: cartId } }) - if (!cart) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - "Unable to find the cart with the given id" - ) - } - - const existing = cart.metadata || {} - cart.metadata = { - ...existing, - [key]: value, - } - - const updatedCart = await cartRepo.save(cart) - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, updatedCart) - - return updatedCart - } - ) - } - - async createTaxLines(cartOrId: string | Cart): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cart = isCart(cartOrId) - ? cartOrId - : await this.retrieve(cartOrId, { - relations: [ - "customer", - "discounts", - "discounts.rule", - "gift_cards", - "items.variant.product.profiles", - "items.adjustments", - "region", - "region.tax_rates", - "shipping_address", - "shipping_methods", - "shipping_methods.shipping_option", - ], - }) - - const calculationContext = await this.totalsService_ - .withTransaction(transactionManager) - .getCalculationContext(cart) - - await this.taxProviderService_ - .withTransaction(transactionManager) - .createTaxLines(cart, calculationContext) - } - ) - } - - async deleteTaxLines(id: string): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const cart = await this.retrieve(id, { - relations: [ - "items", - "items.tax_lines", - "shipping_methods", - "shipping_methods.shipping_option", - "shipping_methods.tax_lines", - ], - }) - await transactionManager.remove(cart.items.flatMap((i) => i.tax_lines)) - await transactionManager.remove( - cart.shipping_methods.flatMap((s) => s.tax_lines) - ) - } - ) - } - - async decorateTotals( - cart: Cart, - totalsConfig: TotalsConfig = {} - ): Promise> { - const newTotalsServiceTx = this.newTotalsService_.withTransaction( - this.activeManager_ - ) - - const calculationContext = await this.totalsService_.getCalculationContext( - cart - ) - const includeTax = totalsConfig?.force_taxes || cart.region?.automatic_taxes - const cartItems = [...(cart.items ?? [])] - const cartShippingMethods = [...(cart.shipping_methods ?? [])] - - if (includeTax) { - const taxLinesMaps = await this.taxProviderService_ - .withTransaction(this.activeManager_) - .getTaxLinesMap(cartItems, calculationContext) - - cartItems.forEach((item) => { - if (item.is_return) { - return - } - item.tax_lines = taxLinesMaps.lineItemsTaxLines[item.id] ?? [] - }) - cartShippingMethods.forEach((method) => { - method.tax_lines = taxLinesMaps.shippingMethodsTaxLines[method.id] ?? [] - }) - } - - const itemsTotals = await newTotalsServiceTx.getLineItemTotals(cartItems, { - includeTax, - calculationContext, - }) - const shippingTotals = await newTotalsServiceTx.getShippingMethodTotals( - cartShippingMethods, - { - discounts: cart.discounts, - includeTax, - calculationContext, - } - ) - - cart.subtotal = 0 - cart.discount_total = 0 - cart.item_tax_total = 0 - cart.shipping_total = 0 - cart.shipping_tax_total = 0 - - cart.items = (cart.items || []).map((item) => { - const itemWithTotals = Object.assign(item, itemsTotals[item.id] ?? {}) - - cart.subtotal! += itemWithTotals.subtotal ?? 0 - cart.discount_total! += itemWithTotals.raw_discount_total ?? 0 - cart.item_tax_total! += itemWithTotals.tax_total ?? 0 - - return itemWithTotals - }) - - cart.shipping_methods = (cart.shipping_methods || []).map( - (shippingMethod) => { - const methodWithTotals = Object.assign( - shippingMethod, - shippingTotals[shippingMethod.id] ?? {} - ) - - cart.shipping_total! += methodWithTotals.subtotal ?? 0 - cart.shipping_tax_total! += methodWithTotals.tax_total ?? 0 - - return methodWithTotals - } - ) - - 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) - - const giftCardableAmount = this.newTotalsService_.getGiftCardableAmount({ - gift_cards_taxable: cart.region?.gift_cards_taxable, - subtotal: cart.subtotal, - discount_total: cart.discount_total, - shipping_total: cart.shipping_total, - tax_total: cart.tax_total, - }) - - const giftCardTotal = await this.newTotalsService_.getGiftCardTotals( - giftCardableAmount, - { - region: cart.region, - giftCards: cart.gift_cards, - } - ) - - cart.gift_card_total = giftCardTotal.total || 0 - cart.gift_card_tax_total = giftCardTotal.tax_total || 0 - - cart.total = - cart.subtotal + - cart.shipping_total + - cart.tax_total - - (cart.gift_card_total + cart.discount_total + cart.gift_card_tax_total) - - return cart as Cart & { total: number } - } - - protected async refreshAdjustments_(cart: Cart): Promise { - const nonReturnLineIDs = cart.items - .filter((item) => !item.is_return) - .map((i) => i.id) - - const lineItemAdjustmentServiceTx = - this.lineItemAdjustmentService_.withTransaction(this.activeManager_) - - // delete all old non return line item adjustments - await lineItemAdjustmentServiceTx.delete({ - item_id: nonReturnLineIDs, - discount_id: Not(IsNull()), - }) - - // potentially create/update line item adjustments - await lineItemAdjustmentServiceTx.createAdjustments(cart) - } - - protected transformQueryForTotals_( - config: FindConfig - ): FindConfig & { totalsToSelect: TotalField[] } { - let { select, relations } = config - - if (!select) { - return { - select, - relations, - totalsToSelect: [], - } - } - - const totalFields = [ - "subtotal", - "tax_total", - "shipping_total", - "discount_total", - "gift_card_total", - "total", - ] - - const totalsToSelect = select.filter((v) => - totalFields.includes(v) - ) as TotalField[] - if (totalsToSelect.length > 0) { - const relationSet = new Set(relations) - relationSet.add("items") - relationSet.add("items.tax_lines") - relationSet.add("gift_cards") - relationSet.add("discounts") - relationSet.add("discounts.rule") - // relationSet.add("discounts.parent_discount") - // relationSet.add("discounts.parent_discount.rule") - // relationSet.add("discounts.parent_discount.regions") - relationSet.add("shipping_methods") - relationSet.add("shipping_address") - relationSet.add("region") - relationSet.add("region.tax_rates") - relations = Array.from(relationSet.values()) - - select = select.filter((v) => !totalFields.includes(v)) - } - - return { - relations, - select, - totalsToSelect, - } - } - - /** - * @deprecated Use decorateTotals instead - * @param cart - * @param totalsToSelect - * @param options - * @protected - */ - protected async decorateTotals_( - cart: Cart, - totalsToSelect: TotalField[], - options: TotalsConfig = { force_taxes: false } - ): Promise { - const totals: { [K in TotalField]?: number | null } = {} - - for (const key of totalsToSelect) { - switch (key) { - case "total": { - totals.total = await this.totalsService_.getTotal(cart, { - force_taxes: options.force_taxes, - }) - break - } - case "shipping_total": { - totals.shipping_total = await this.totalsService_.getShippingTotal( - cart - ) - break - } - case "discount_total": - totals.discount_total = await this.totalsService_.getDiscountTotal( - cart - ) - break - case "tax_total": - totals.tax_total = await this.totalsService_.getTaxTotal( - cart, - options.force_taxes - ) - break - case "gift_card_total": { - const giftCardBreakdown = await this.totalsService_.getGiftCardTotal( - cart - ) - totals.gift_card_total = giftCardBreakdown.total - totals.gift_card_tax_total = giftCardBreakdown.tax_total - break - } - case "subtotal": - totals.subtotal = await this.totalsService_.getSubtotal(cart) - break - default: - break - } - } - - return Object.assign(cart, totals) - } - - private getTotalsRelations(config: FindConfig): string[] { - const relationSet = new Set(config.relations) - - relationSet.add("items.variant.product.profiles") - relationSet.add("items.tax_lines") - relationSet.add("items.adjustments") - relationSet.add("gift_cards") - relationSet.add("discounts") - relationSet.add("discounts.rule") - relationSet.add("shipping_methods") - relationSet.add("shipping_methods.tax_lines") - relationSet.add("shipping_address") - relationSet.add("region") - relationSet.add("region.tax_rates") - - return Array.from(relationSet.values()) - } -} - -export default CartService diff --git a/packages/medusa/src/services/claim-item.ts b/packages/medusa/src/services/claim-item.ts deleted file mode 100644 index f889afbbed..0000000000 --- a/packages/medusa/src/services/claim-item.ts +++ /dev/null @@ -1,253 +0,0 @@ -import { promiseAll } from "@medusajs/utils" -import { isDefined, MedusaError } from "medusa-core-utils" -import { TransactionBaseService } from "../interfaces" -import { ClaimImage, ClaimItem, ClaimTag } from "../models" -import { ClaimImageRepository } from "../repositories/claim-image" -import { ClaimItemRepository } from "../repositories/claim-item" -import { ClaimTagRepository } from "../repositories/claim-tag" -import { CreateClaimItemInput } from "../types/claim" -import { FindConfig, Selector } from "../types/common" -import { buildQuery, setMetadata } from "../utils" -import EventBusService from "./event-bus" -import LineItemService from "./line-item" - -class ClaimItemService extends TransactionBaseService { - static Events = { - CREATED: "claim_item.created", - UPDATED: "claim_item.updated", - CANCELED: "claim_item.canceled", - } - - protected readonly lineItemService_: LineItemService - protected readonly eventBus_: EventBusService - protected readonly claimItemRepository_: typeof ClaimItemRepository - protected readonly claimTagRepository_: typeof ClaimTagRepository - protected readonly claimImageRepository_: typeof ClaimImageRepository - - constructor({ - claimItemRepository, - claimTagRepository, - claimImageRepository, - lineItemService, - eventBusService, - }) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.claimItemRepository_ = claimItemRepository - this.claimTagRepository_ = claimTagRepository - this.claimImageRepository_ = claimImageRepository - this.lineItemService_ = lineItemService - this.eventBus_ = eventBusService - } - - async create(data: CreateClaimItemInput): Promise { - return await this.atomicPhase_(async (manager) => { - const ciRepo = manager.withRepository(this.claimItemRepository_) - - const { item_id, reason, quantity, tags, images, ...rest } = data - - if ( - reason !== "missing_item" && - reason !== "wrong_item" && - reason !== "production_failure" && - reason !== "other" - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Claim Item reason must be one of "missing_item", "wrong_item", "production_failure" or "other".` - ) - } - - const lineItem = await this.lineItemService_ - .withTransaction(manager) - .retrieve(item_id) - - if (!lineItem.variant_id) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot claim a custom line item" - ) - } - - if (lineItem.fulfilled_quantity! < quantity) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot claim more of an item than has been fulfilled." - ) - } - - let tagsToAdd: ClaimTag[] = [] - if (tags && tags.length) { - const claimTagRepo = manager.withRepository(this.claimTagRepository_) - tagsToAdd = await promiseAll( - tags.map(async (t) => { - const normalized = t.trim().toLowerCase() - const existing = await claimTagRepo.findOne({ - where: { value: normalized }, - }) - if (existing) { - return existing - } - return claimTagRepo.create({ value: normalized }) - }) - ) - } - - let imagesToAdd: ClaimImage[] = [] - if (images && images.length) { - const claimImgRepo = manager.withRepository(this.claimImageRepository_) - imagesToAdd = images.map((url) => { - return claimImgRepo.create({ url }) - }) - } - - const toCreate: Partial = { - ...rest, - variant_id: lineItem.variant_id, - tags: tagsToAdd, - images: imagesToAdd, - item_id, - reason, - quantity, - } - const created = ciRepo.create(toCreate) - - const result = await ciRepo.save(created) - - await this.eventBus_ - .withTransaction(manager) - .emit(ClaimItemService.Events.CREATED, { - id: result.id, - }) - - return result - }) - } - - async update(id, data): Promise { - return this.atomicPhase_(async (manager) => { - const ciRepo = manager.withRepository(this.claimItemRepository_) - const item = await this.retrieve(id, { relations: ["images", "tags"] }) - - const { tags, images, reason, note, metadata } = data - - if (note) { - item.note = note - } - - if (reason) { - item.reason = reason - } - - if (metadata) { - item.metadata = setMetadata(item, metadata) - } - - if (tags) { - item.tags = [] - const claimTagRepo = manager.withRepository(this.claimTagRepository_) - for (const t of tags) { - if (t.id) { - item.tags.push(t) - } else { - const normalized = t.value.trim().toLowerCase() - - const existing = await claimTagRepo.findOne({ - where: { value: normalized }, - }) - - if (existing) { - item.tags.push(existing) - } else { - item.tags.push(claimTagRepo.create({ value: normalized })) - } - } - } - } - - if (images) { - const claimImgRepo = manager.withRepository(this.claimImageRepository_) - const ids = images.map((i) => i.id) - for (const i of item.images) { - if (!ids.includes(i.id)) { - await claimImgRepo.remove(i) - } - } - - item.images = [] - - for (const i of images) { - if (i.id) { - item.images.push(i) - } else { - item.images.push(claimImgRepo.create({ url: i.url })) - } - } - } - - await ciRepo.save(item) - - await this.eventBus_ - .withTransaction(manager) - .emit(ClaimItemService.Events.UPDATED, { - id: item.id, - }) - - return item - }) - } - - /** - * @param {Object} selector - the query object for find - * @param {Object} config - the config object for find - * @return {Promise} the result of the find operation - */ - async list( - selector: Selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise { - const ciRepo = this.activeManager_.withRepository(this.claimItemRepository_) - const query = buildQuery(selector, config) - return ciRepo.find(query) - } - - /** - * Gets a claim item by id. - * @param {string} claimItemId - id of ClaimItem to retrieve - * @param {Object} config - configuration for the find operation - * @return {Promise} the ClaimItem - */ - async retrieve( - claimItemId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(claimItemId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"claimItemId" must be defined` - ) - } - - const claimItemRepo = this.activeManager_.withRepository( - this.claimItemRepository_ - ) - const query = buildQuery({ id: claimItemId }, config) - const item = await claimItemRepo.findOne(query) - - if (!item) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Claim item with id: ${claimItemId} was not found.` - ) - } - - return item - } -} - -export default ClaimItemService diff --git a/packages/medusa/src/services/claim.ts b/packages/medusa/src/services/claim.ts deleted file mode 100644 index aead7c3b94..0000000000 --- a/packages/medusa/src/services/claim.ts +++ /dev/null @@ -1,915 +0,0 @@ -import { isDefined, MedusaError } from "medusa-core-utils" -import { DeepPartial, EntityManager } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { - ClaimFulfillmentStatus, - ClaimOrder, - ClaimPaymentStatus, - ClaimType, - FulfillmentItem, - LineItem, - Order, - ReturnItem, -} from "../models" -import { AddressRepository } from "../repositories/address" -import { ClaimRepository } from "../repositories/claim" -import { LineItemRepository } from "../repositories/line-item" -import { ShippingMethodRepository } from "../repositories/shipping-method" -import { - CreateClaimInput, - CreateClaimItemInput, - UpdateClaimInput, -} from "../types/claim" -import { FindConfig } from "../types/common" -import { buildQuery, setMetadata } from "../utils" -import ClaimItemService from "./claim-item" -import EventBusService from "./event-bus" -import FulfillmentService from "./fulfillment" -import FulfillmentProviderService from "./fulfillment-provider" -import LineItemService from "./line-item" -import PaymentProviderService from "./payment-provider" -import ProductVariantInventoryService from "./product-variant-inventory" -import RegionService from "./region" -import ReturnService from "./return" -import ShippingOptionService from "./shipping-option" -import TaxProviderService from "./tax-provider" -import TotalsService from "./totals" -import { promiseAll } from "@medusajs/utils" - -type InjectedDependencies = { - manager: EntityManager - addressRepository: typeof AddressRepository - shippingMethodRepository: typeof ShippingMethodRepository - lineItemRepository: typeof LineItemRepository - claimRepository: typeof ClaimRepository - claimItemService: ClaimItemService - eventBusService: EventBusService - fulfillmentProviderService: FulfillmentProviderService - fulfillmentService: FulfillmentService - productVariantInventoryService: ProductVariantInventoryService - lineItemService: LineItemService - paymentProviderService: PaymentProviderService - regionService: RegionService - returnService: ReturnService - shippingOptionService: ShippingOptionService - taxProviderService: TaxProviderService - totalsService: TotalsService -} - -export default class ClaimService extends TransactionBaseService { - static readonly Events = { - CREATED: "claim.created", - UPDATED: "claim.updated", - CANCELED: "claim.canceled", - FULFILLMENT_CREATED: "claim.fulfillment_created", - SHIPMENT_CREATED: "claim.shipment_created", - REFUND_PROCESSED: "claim.refund_processed", - } - - protected readonly addressRepository_: typeof AddressRepository - protected readonly claimRepository_: typeof ClaimRepository - protected readonly shippingMethodRepository_: typeof ShippingMethodRepository - protected readonly lineItemRepository_: typeof LineItemRepository - protected readonly claimItemService_: ClaimItemService - protected readonly eventBus_: EventBusService - protected readonly fulfillmentProviderService_: FulfillmentProviderService - protected readonly fulfillmentService_: FulfillmentService - protected readonly lineItemService_: LineItemService - protected readonly paymentProviderService_: PaymentProviderService - protected readonly regionService_: RegionService - protected readonly returnService_: ReturnService - protected readonly shippingOptionService_: ShippingOptionService - protected readonly taxProviderService_: TaxProviderService - protected readonly totalsService_: TotalsService - // eslint-disable-next-line max-len - protected readonly productVariantInventoryService_: ProductVariantInventoryService - - constructor({ - addressRepository, - claimRepository, - shippingMethodRepository, - lineItemRepository, - claimItemService, - eventBusService, - fulfillmentProviderService, - fulfillmentService, - productVariantInventoryService, - lineItemService, - paymentProviderService, - regionService, - returnService, - shippingOptionService, - taxProviderService, - totalsService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.addressRepository_ = addressRepository - this.claimRepository_ = claimRepository - this.shippingMethodRepository_ = shippingMethodRepository - this.lineItemRepository_ = lineItemRepository - this.claimItemService_ = claimItemService - this.eventBus_ = eventBusService - this.fulfillmentProviderService_ = fulfillmentProviderService - this.fulfillmentService_ = fulfillmentService - this.productVariantInventoryService_ = productVariantInventoryService - this.lineItemService_ = lineItemService - this.paymentProviderService_ = paymentProviderService - this.regionService_ = regionService - this.returnService_ = returnService - this.shippingOptionService_ = shippingOptionService - this.taxProviderService_ = taxProviderService - this.totalsService_ = totalsService - } - - async update(id: string, data: UpdateClaimInput): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const claimRepo = transactionManager.withRepository( - this.claimRepository_ - ) - const claim = await this.retrieve(id, { - relations: ["shipping_methods"], - }) - - if (claim.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Canceled claim cannot be updated" - ) - } - - const { claim_items, shipping_methods, metadata, no_notification } = - data - - if (metadata) { - claim.metadata = setMetadata(claim, metadata) - await claimRepo.save(claim) - } - - if (shipping_methods) { - const shippingOptionServiceTx = - this.shippingOptionService_.withTransaction(transactionManager) - - for (const m of claim.shipping_methods) { - await shippingOptionServiceTx.updateShippingMethod(m.id, { - claim_order_id: null, - }) - } - - for (const method of shipping_methods) { - if (method.id) { - await shippingOptionServiceTx.updateShippingMethod(method.id, { - claim_order_id: claim.id, - }) - } else { - await shippingOptionServiceTx.createShippingMethod( - method.option_id as string, - method.data ?? {}, - { - claim_order_id: claim.id, - price: method.price, - } - ) - } - } - } - - if (no_notification !== undefined) { - claim.no_notification = no_notification - await claimRepo.save(claim) - } - - if (claim_items) { - const claimItemServiceTx = - this.claimItemService_.withTransaction(transactionManager) - - for (const i of claim_items) { - if (i.id) { - await claimItemServiceTx.update(i.id, i) - } - } - } - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(ClaimService.Events.UPDATED, { - id: claim.id, - no_notification: claim.no_notification, - }) - - return claim - } - ) - } - - protected async validateCreateClaimInput( - data: CreateClaimInput - ): Promise { - const lineItemServiceTx = this.lineItemService_.withTransaction( - this.manager_ - ) - - const { type, claim_items, additional_items, refund_amount } = data - - if (type !== ClaimType.REFUND && type !== ClaimType.REPLACE) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Claim type must be one of "refund" or "replace".` - ) - } - - if (type === ClaimType.REPLACE && !additional_items?.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Claims with type "replace" must have at least one additional item.` - ) - } - - if (!claim_items?.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Claims must have at least one claim item.` - ) - } - - if (refund_amount && type !== ClaimType.REFUND) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Claim has type "${type}" but must be type "refund" to have a refund_amount.` - ) - } - - const claimLineItems = await lineItemServiceTx.list( - { id: claim_items.map((c) => c.item_id) }, - { relations: ["order", "swap", "claim_order", "tax_lines"] } - ) - - for (const line of claimLineItems) { - if ( - line.order?.canceled_at || - line.swap?.canceled_at || - line.claim_order?.canceled_at - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Cannot create a claim on a canceled item.` - ) - } - } - } - - /** - * Finds claim line items on an order and calculates the refund amount. - * There are three places too look: - * - Order items - * - Swap items - * - Claim items (from previous claims) - * Note, it will attempt to return early from each of these places to avoid having to iterate over all items every time. - * @param order - the order to find claim lines on - * @param claimItems - the claim items to match against - * @return the refund amount - */ - protected async getRefundTotalForClaimLinesOnOrder( - order: Order, - claimItems: CreateClaimItemInput[] - ) { - const claimLines = claimItems - .map((ci) => { - const predicate = (it: LineItem) => - it.shipped_quantity! > 0 && - ci.quantity <= it.shipped_quantity! && - it.id === ci.item_id - - const claimLine = order.items.find(predicate) - - if (claimLine) { - return { ...claimLine, quantity: ci.quantity } - } - - if (order.swaps?.length) { - for (const swap of order.swaps) { - const claimLine = swap.additional_items.find(predicate) - - if (claimLine) { - return { ...claimLine, quantity: ci.quantity } - } - } - } - - if (order.claims?.length) { - for (const claim of order.claims) { - const claimLine = claim.additional_items.find(predicate) - - if (claimLine) { - return { ...claimLine, quantity: ci.quantity } - } - } - } - - return null - }) - .filter(Boolean) as LineItem[] - - const refunds: number[] = [] - - for (const item of claimLines) { - const refund = await this.totalsService_.getLineItemRefund(order, item) - refunds.push(refund) - } - - return Math.round(refunds.reduce((acc, next) => acc + next, 0)) - } - - /** - * Creates a Claim on an Order. Claims consists of items that are claimed and - * optionally items to be sent as replacement for the claimed items. The - * shipping address that the new items will be shipped to - * @param data - the object containing all data required to create a claim - * @return created claim - */ - async create(data: CreateClaimInput): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const claimRepo = transactionManager.withRepository( - this.claimRepository_ - ) - - const { - type, - claim_items, - order, - return_shipping, - additional_items, - shipping_methods, - refund_amount, - shipping_address, - shipping_address_id, - no_notification, - return_location_id, - ...rest - } = data - - await this.validateCreateClaimInput(data) - - let addressId = shipping_address_id || order.shipping_address_id - if (shipping_address) { - const addressRepo = transactionManager.withRepository( - this.addressRepository_ - ) - const created = addressRepo.create(shipping_address) - const saved = await addressRepo.save(created) - addressId = saved.id - } - - let toRefund = refund_amount - if (type === ClaimType.REFUND && typeof refund_amount === "undefined") { - // In case no refund amount is passed, we calculate it based on the claim items on the order - toRefund = await this.getRefundTotalForClaimLinesOnOrder( - order, - claim_items - ) - } - - const lineItemServiceTx = - this.lineItemService_.withTransaction(transactionManager) - - let newItems: LineItem[] = [] - - if (isDefined(additional_items)) { - newItems = await promiseAll( - additional_items.map(async (i) => - lineItemServiceTx.generate( - i.variant_id, - order.region_id, - i.quantity - ) - ) - ) - - await promiseAll( - newItems.map(async (newItem) => { - if (newItem.variant_id) { - await this.productVariantInventoryService_.reserveQuantity( - newItem.variant_id, - newItem.quantity, - { - lineItemId: newItem.id, - salesChannelId: order.sales_channel_id, - } - ) - } - }) - ) - } - - const evaluatedNoNotification = - no_notification !== undefined - ? no_notification - : order.no_notification - - const created = claimRepo.create({ - shipping_address_id: addressId, - payment_status: type === ClaimType.REFUND ? "not_refunded" : "na", - refund_amount: toRefund, - type, - additional_items: newItems, - order_id: order.id, - no_notification: evaluatedNoNotification, - ...rest, - } as DeepPartial) - - const result: ClaimOrder = await claimRepo.save(created) - - if (result.additional_items && result.additional_items.length) { - const calcContext = await this.totalsService_.getCalculationContext( - order - ) - const lineItems = await lineItemServiceTx.list( - { - id: result.additional_items.map((i) => i.id), - }, - { - relations: ["variant.product.profiles"], - } - ) - - await this.taxProviderService_ - .withTransaction(transactionManager) - .createTaxLines(lineItems, calcContext) - } - - if (shipping_methods) { - const shippingOptionServiceTx = - this.shippingOptionService_.withTransaction(transactionManager) - - for (const method of shipping_methods) { - if (method.id) { - await shippingOptionServiceTx.updateShippingMethod(method.id, { - claim_order_id: result.id, - }) - } else { - await shippingOptionServiceTx.createShippingMethod( - method.option_id as string, - method.data ?? {}, - { - claim_order_id: result.id, - price: method.price, - } - ) - } - } - } - - const claimItemServiceTx = - this.claimItemService_.withTransaction(transactionManager) - - for (const ci of claim_items) { - await claimItemServiceTx.create({ - ...ci, - claim_order_id: result.id, - }) - } - - if (return_shipping) { - await this.returnService_.withTransaction(transactionManager).create({ - refund_amount: toRefund, - order_id: order.id, - claim_order_id: result.id, - items: claim_items.map( - (ci) => - ({ - item_id: ci.item_id, - quantity: ci.quantity, - metadata: (ci as any).metadata, - } as ReturnItem) - ), - shipping_method: return_shipping, - no_notification: evaluatedNoNotification, - location_id: return_location_id, - }) - } - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(ClaimService.Events.CREATED, { - id: result.id, - no_notification: result.no_notification, - }) - - return result - } - ) - } - - /** - * @param id - the object containing all data required to create a claim - * @param config - config object - * @param config.metadata - config metadata - * @param config.no_notification - config no notification - * @return created claim - */ - async createFulfillment( - id: string, - config: { - metadata?: Record - no_notification?: boolean - location_id?: string - } = { - metadata: {}, - } - ): Promise { - const { metadata, no_notification } = config - - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const claim = await this.retrieve(id, { - relations: [ - "additional_items.tax_lines", - "additional_items.variant.product.profiles", - "shipping_methods", - "shipping_methods.shipping_option", - "shipping_methods.tax_lines", - "shipping_address", - "order", - "order.billing_address", - "order.discounts", - "order.discounts.rule", - "order.payments", - ], - }) - - if (claim.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Canceled claim cannot be fulfilled" - ) - } - - const order = claim.order - - if ( - claim.fulfillment_status !== "not_fulfilled" && - claim.fulfillment_status !== "canceled" - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "The claim has already been fulfilled." - ) - } - - if (claim.type !== "replace") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Claims with the type "${claim.type}" can not be fulfilled.` - ) - } - - if (!claim.shipping_methods?.length) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot fulfill a claim without a shipping method." - ) - } - - const evaluatedNoNotification = - no_notification !== undefined - ? no_notification - : claim.no_notification - - const fulfillments = await this.fulfillmentService_ - .withTransaction(transactionManager) - .createFulfillment( - { - ...claim, - email: order.email, - payments: order.payments, - discounts: order.discounts, - currency_code: order.currency_code, - tax_rate: order.tax_rate, - region_id: order.region_id, - display_id: order.display_id, - billing_address: order.billing_address, - items: claim.additional_items, - shipping_methods: claim.shipping_methods, - is_claim: true, - no_notification: evaluatedNoNotification, - }, - claim.additional_items.map((i) => ({ - item_id: i.id, - quantity: i.quantity, - })), - { claim_order_id: id, metadata, location_id: config.location_id } - ) - - let successfullyFulfilledItems: FulfillmentItem[] = [] - for (const fulfillment of fulfillments) { - successfullyFulfilledItems = successfullyFulfilledItems.concat( - fulfillment.items - ) - } - - claim.fulfillment_status = ClaimFulfillmentStatus.FULFILLED - - for (const item of claim.additional_items) { - const fulfillmentItem = successfullyFulfilledItems.find( - (successfullyFulfilledItem) => { - return successfullyFulfilledItem.item_id === item.id - } - ) - - if (fulfillmentItem) { - const fulfilledQuantity = - (item.fulfilled_quantity || 0) + fulfillmentItem.quantity - - // Update the fulfilled quantity - await this.lineItemService_ - .withTransaction(transactionManager) - .update(item.id, { - fulfilled_quantity: fulfilledQuantity, - }) - - if (item.quantity !== fulfilledQuantity) { - claim.fulfillment_status = ClaimFulfillmentStatus.REQUIRES_ACTION - } - } else if (item.quantity !== item.fulfilled_quantity) { - claim.fulfillment_status = ClaimFulfillmentStatus.REQUIRES_ACTION - } - } - - const claimRepo = transactionManager.withRepository( - this.claimRepository_ - ) - const claimOrder = await claimRepo.save(claim) - - const eventsToEmit = fulfillments.map((fulfillment) => ({ - eventName: ClaimService.Events.FULFILLMENT_CREATED, - data: { - id: id, - fulfillment_id: fulfillment.id, - no_notification: claim.no_notification, - }, - })) - await this.eventBus_ - .withTransaction(transactionManager) - .emit(eventsToEmit) - - return claimOrder - } - ) - } - - async cancelFulfillment(fulfillmentId: string): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const canceled = await this.fulfillmentService_ - .withTransaction(transactionManager) - .cancelFulfillment(fulfillmentId) - - if (!canceled.claim_order_id) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Fufillment not related to a claim` - ) - } - - const claim = await this.retrieve(canceled.claim_order_id) - - claim.fulfillment_status = ClaimFulfillmentStatus.CANCELED - - const claimRepo = transactionManager.withRepository( - this.claimRepository_ - ) - return claimRepo.save(claim) - } - ) - } - - async processRefund(id: string): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const claim = await this.retrieve(id, { - relations: ["order", "order.payments"], - }) - - if (claim.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Canceled claim cannot be processed" - ) - } - - if (claim.type !== "refund") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Claim must have type "refund" to create a refund.` - ) - } - - if (claim.refund_amount) { - await this.paymentProviderService_ - .withTransaction(transactionManager) - .refundPayment(claim.order.payments, claim.refund_amount, "claim") - } - - claim.payment_status = ClaimPaymentStatus.REFUNDED - - const claimRepo = transactionManager.withRepository( - this.claimRepository_ - ) - const claimOrder = await claimRepo.save(claim) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(ClaimService.Events.REFUND_PROCESSED, { - id, - no_notification: claimOrder.no_notification, - }) - - return claimOrder - } - ) - } - - async createShipment( - id: string, - fulfillmentId: string, - trackingLinks: { tracking_number: string }[] = [], - config = { - metadata: {}, - no_notification: undefined, - } - ): Promise { - const { metadata, no_notification } = config - - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const claim = await this.retrieve(id, { - relations: ["additional_items"], - }) - - if (claim.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Canceled claim cannot be fulfilled as shipped" - ) - } - const evaluatedNoNotification = - no_notification !== undefined - ? no_notification - : claim.no_notification - - const shipment = await this.fulfillmentService_ - .withTransaction(transactionManager) - .createShipment(fulfillmentId, trackingLinks, { - metadata, - no_notification: evaluatedNoNotification, - }) - - claim.fulfillment_status = ClaimFulfillmentStatus.SHIPPED - - const lineItemServiceTx = - this.lineItemService_.withTransaction(transactionManager) - - for (const additionalItem of claim.additional_items) { - const shipped = shipment.items.find( - (si) => si.item_id === additionalItem.id - ) - if (shipped) { - const shippedQty = - (additionalItem.shipped_quantity || 0) + shipped.quantity - await lineItemServiceTx.update(additionalItem.id, { - shipped_quantity: shippedQty, - }) - - if (shippedQty !== additionalItem.quantity) { - claim.fulfillment_status = - ClaimFulfillmentStatus.PARTIALLY_SHIPPED - } - } else if ( - additionalItem.shipped_quantity !== additionalItem.quantity - ) { - claim.fulfillment_status = ClaimFulfillmentStatus.PARTIALLY_SHIPPED - } - } - - const claimRepo = transactionManager.withRepository( - this.claimRepository_ - ) - const claimOrder = await claimRepo.save(claim) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(ClaimService.Events.SHIPMENT_CREATED, { - id, - fulfillment_id: shipment.id, - no_notification: evaluatedNoNotification, - }) - - return claimOrder - } - ) - } - - async cancel(id: string): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const claim = await this.retrieve(id, { - relations: ["return_order", "fulfillments", "order", "order.refunds"], - }) - if (claim.refund_amount) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Claim with a refund cannot be canceled" - ) - } - - if (claim.fulfillments) { - for (const f of claim.fulfillments) { - if (!f.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "All fulfillments must be canceled before the claim can be canceled" - ) - } - } - } - - if (claim.return_order && claim.return_order.status !== "canceled") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Return must be canceled before the claim can be canceled" - ) - } - - claim.fulfillment_status = ClaimFulfillmentStatus.CANCELED - claim.canceled_at = new Date() - - const claimRepo = transactionManager.withRepository( - this.claimRepository_ - ) - const claimOrder = await claimRepo.save(claim) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(ClaimService.Events.CANCELED, { - id: claimOrder.id, - no_notification: claimOrder.no_notification, - }) - - return claimOrder - } - ) - } - - /** - * @param selector - the query object for find - * @param config - the config object containing query settings - * @return the result of the find operation - */ - async list( - selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise { - const claimRepo = this.activeManager_.withRepository(this.claimRepository_) - const query = buildQuery(selector, config) - return await claimRepo.find(query) - } - - /** - * Gets an order by id. - * @param claimId - id of the claim order to retrieve - * @param config - the config object containing query settings - * @return the order document - */ - async retrieve( - claimId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(claimId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"claimId" must be defined` - ) - } - - const claimRepo = this.activeManager_.withRepository(this.claimRepository_) - - const query = buildQuery({ id: claimId }, config) - const claim = await claimRepo.findOne(query) - - if (!claim) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Claim with ${claimId} was not found` - ) - } - - return claim - } -} diff --git a/packages/medusa/src/services/csv-parser.ts b/packages/medusa/src/services/csv-parser.ts deleted file mode 100644 index 263408783b..0000000000 --- a/packages/medusa/src/services/csv-parser.ts +++ /dev/null @@ -1,202 +0,0 @@ -import { difference } from "lodash" -import Papa, { ParseConfig } from "papaparse" - -import { AbstractParser } from "../interfaces/abstract-parser" -import { CsvParserContext, CsvSchema } from "../interfaces/csv-parser" - -const DEFAULT_PARSE_OPTIONS = { - dynamicTyping: true, - header: true, -} - -class CsvParser< - TSchema extends CsvSchema = CsvSchema, - TParserResult extends object = Record, - TOutputResult = unknown -> extends AbstractParser { - protected readonly $$delimiter: string = ";" - - constructor(schema: TSchema, delimiter?: string) { - super(schema) - if (delimiter) { - this.$$delimiter = delimiter - } - } - - public async parse( - readableStream: NodeJS.ReadableStream, - options: ParseConfig = DEFAULT_PARSE_OPTIONS - ): Promise { - const csvStream = Papa.parse(Papa.NODE_STREAM_INPUT, options) - - const parsedContent: TParserResult[] = [] - readableStream.pipe(csvStream) - for await (const chunk of csvStream) { - parsedContent.push(chunk) - } - - return parsedContent - } - - async buildData(data: TParserResult[]): Promise { - const validatedData = [] as TOutputResult[] - for (let i = 0; i < data.length; i++) { - const builtLine = await this._buildLine(data[i], i + 1) - validatedData.push(builtLine) - } - return validatedData - } - - private async _buildLine( - line: TParserResult, - lineNumber: number - ): Promise { - let outputTuple = {} as TOutputResult - const columnMap = this.buildColumnMap_(this.$$schema.columns) - const requiredColumnsMap = this.buildColumnMap_( - this.$$schema.columns.filter((col) => col.required) - ) - - const tupleKeys = Object.keys(line) - - /** - * map which keeps track of the columns processed - * used to detect any missing columns which are present in the schema but not in the line - */ - const processedColumns = {} - for (const tupleKey of tupleKeys) { - const column = this.resolveColumn_(tupleKey, columnMap) - - /** - * if the tupleKey does not correspond to any column defined in the schema - */ - if (!column) { - throw new Error( - `Unable to treat column ${tupleKey} from the csv file. No target column found in the provided schema` - ) - } - - processedColumns[column.name] = true - - /** - * if the value corresponding to the tupleKey is empty and the column is required in the schema - */ - if (!line[tupleKey] && column.required) { - throw new Error( - `No value found for target column "${column.name}" in line ${lineNumber} of the given csv file` - ) - } - - const context = { - line, - lineNumber, - column: column.name, - tupleKey, - } - - outputTuple = this.resolveTuple_(outputTuple, column, context) - } - - /** - * missing columns = columns defined (& required) in the schema - columns present in the line - */ - const missingColumns = difference( - Object.keys(requiredColumnsMap), - Object.keys(processedColumns) - ) - - if (missingColumns.length > 0) { - throw new Error( - `Missing column(s) ${formatMissingColumns( - missingColumns - )} from the given csv file` - ) - } - - /** - * Runs the validation defined in the schema columns - */ - for (const column of this.$$schema.columns) { - const context = { - line, - lineNumber, - column: column.name, - } - - if (column.validator) { - await column.validator.validate(outputTuple, context) - } - } - - return outputTuple - } - - private buildColumnMap_( - columns: TSchema["columns"] - ): Record { - return columns.reduce((map, column) => { - if (typeof column.name === "string") { - map[column.name] = column - } - return map - }, {}) - } - - private resolveColumn_( - tupleKey: string, - columnMap: Record - ): TSchema["columns"][number] | undefined { - // @ts-ignore - if (columnMap[tupleKey] && !columnMap[tupleKey].match) { - return columnMap[tupleKey] - } - - const matchedColumn = this.$$schema.columns.find((column) => { - return "match" in column && - typeof column.match === "object" && - column.match instanceof RegExp - ? column.match.test(tupleKey) - : false - }) - - return matchedColumn - } - - private resolveTuple_( - tuple: TOutputResult, - column: TSchema["columns"][number], - context: CsvParserContext & { tupleKey: string } - ): TOutputResult { - const outputTuple = { ...tuple } - const { tupleKey, ...csvContext } = context - const { line } = csvContext - - let resolvedKey = tupleKey - /** - * if match is provided, then we should call the reducer if it's defined - * otherwise, before using the mapTo property, we should make sure match was not provided - */ - if ("match" in column && column.reducer) { - return column.reducer(outputTuple, tupleKey, line[tupleKey], csvContext) - } else if (!("match" in column) && "mapTo" in column && column.mapTo) { - resolvedKey = column.mapTo - } - - const resolvedValue = column.transform - ? column.transform(line[tupleKey], csvContext) - : line[tupleKey] - - outputTuple[resolvedKey] = resolvedValue - - return outputTuple - } -} - -const formatMissingColumns = (list: string[]): string => - list.reduce( - (text, curr, i, array) => - text + (i < array.length - 1 ? `"${curr}", ` : `"${curr}"`), - "" - ) - -export default CsvParser diff --git a/packages/medusa/src/services/currency.ts b/packages/medusa/src/services/currency.ts deleted file mode 100644 index bf056a0890..0000000000 --- a/packages/medusa/src/services/currency.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { MedusaError } from "medusa-core-utils" -import { EntityManager, FindOptionsWhere, ILike } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { Currency } from "../models" -import { CurrencyRepository } from "../repositories/currency" -import { FindConfig, Selector } from "../types/common" -import { UpdateCurrencyInput } from "../types/currency" -import { buildQuery } from "../utils" -import EventBusService from "./event-bus" - -type InjectedDependencies = { - manager: EntityManager - currencyRepository: typeof CurrencyRepository - eventBusService: EventBusService - featureFlagRouter: FlagRouter -} - -export default class CurrencyService extends TransactionBaseService { - static readonly Events = { - UPDATED: "currency.updated", - } - - protected readonly currencyRepository_: typeof CurrencyRepository - protected readonly eventBusService_: EventBusService - protected readonly featureFlagRouter_: FlagRouter - - constructor({ - currencyRepository, - eventBusService, - featureFlagRouter, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.currencyRepository_ = currencyRepository - this.eventBusService_ = eventBusService - this.featureFlagRouter_ = featureFlagRouter - } - - /** - * Return the currency - * @param code - The code of the currency that must be retrieve - * @return The currency - */ - async retrieveByCode(code: string): Promise { - const currencyRepo = this.activeManager_.withRepository( - this.currencyRepository_ - ) - - code = code.toLowerCase() - const currency = await currencyRepo.findOne({ - where: { code }, - }) - - if (!currency) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Currency with code: ${code} was not found` - ) - } - - return currency - } - - /** - * Lists currencies based on the provided parameters and includes the count of - * currencies that match the query. - * @param selector - an object that defines rules to filter currencies - * by - * @param config - object that defines the scope for what should be - * returned - * @return an array containing the currencies as - * the first element and the total count of products that matches the query - * as the second element. - */ - async listAndCount( - selector: Selector & { q?: string }, - config: FindConfig = { - skip: 0, - take: 20, - } - ): Promise<[Currency[], number]> { - const productRepo = this.activeManager_.withRepository( - this.currencyRepository_ - ) - - let q: string | undefined - - if (selector.q) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - - if (q) { - const where = query.where as FindOptionsWhere - - delete where.code - delete where.name - - query.where = [ - { - ...where, - code: ILike(`%${q}%`), - }, - { - ...where, - name: ILike(`%${q}%`), - }, - ] - } - - return await productRepo.findAndCount(query) - } - - /** - * Update a currency - * @param code - The code of the currency to update - * @param data - The data that must be updated on the currency - * @return The updated currency - */ - async update( - code: string, - data: UpdateCurrencyInput - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const currency = await this.retrieveByCode(code) - - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) - ) { - if (typeof data.includes_tax !== "undefined") { - currency.includes_tax = data.includes_tax - } - } - - const currencyRepo = transactionManager.withRepository( - this.currencyRepository_ - ) - await currencyRepo.save(currency) - - await this.eventBusService_ - .withTransaction(transactionManager) - .emit(CurrencyService.Events.UPDATED, { - code, - }) - - return currency - }) - } -} diff --git a/packages/medusa/src/services/custom-shipping-option.ts b/packages/medusa/src/services/custom-shipping-option.ts deleted file mode 100644 index aea0bf92ce..0000000000 --- a/packages/medusa/src/services/custom-shipping-option.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { DeepPartial, EntityManager } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { CustomShippingOption } from "../models" -import { CustomShippingOptionRepository } from "../repositories/custom-shipping-option" -import { FindConfig, Selector } from "../types/common" -import { CreateCustomShippingOptionInput } from "../types/shipping-options" -import { buildQuery } from "../utils" - -type InjectedDependencies = { - manager: EntityManager - customShippingOptionRepository: typeof CustomShippingOptionRepository -} -class CustomShippingOptionService extends TransactionBaseService { - // eslint-disable-next-line max-len - protected customShippingOptionRepository_: typeof CustomShippingOptionRepository - - constructor({ customShippingOptionRepository }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.customShippingOptionRepository_ = customShippingOptionRepository - } - - /** - * Retrieves a specific shipping option. - * @param id - the id of the custom shipping option to retrieve. - * @param config - any options needed to query for the result. - * @return the requested custom shipping option. - */ - async retrieve( - id: string, - config: FindConfig = {} - ): Promise { - const customShippingOptionRepo = this.activeManager_.withRepository( - this.customShippingOptionRepository_ - ) - - const query = buildQuery({ id }, config) - - const customShippingOption = await customShippingOptionRepo.findOne(query) - - if (!customShippingOption) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Custom shipping option with id: ${id} was not found.` - ) - } - - return customShippingOption - } - - /** Fetches all custom shipping options based on the given selector - * @param selector - the query object for find - * @param config - the configuration used to find the objects. contains relations, skip, and take. - * @return custom shipping options matching the query - */ - async list( - selector: Selector, - config: FindConfig = { - skip: 0, - take: 50, - relations: [], - } - ): Promise { - const customShippingOptionRepo = this.activeManager_.withRepository( - this.customShippingOptionRepository_ - ) - - const query = buildQuery(selector, config) - - return await customShippingOptionRepo.find(query) - } - - /** - * Creates a custom shipping option - * @param data - the custom shipping option to create - * @return resolves to the creation result - */ - async create< - T = CreateCustomShippingOptionInput | CreateCustomShippingOptionInput[], - TResult = T extends CreateCustomShippingOptionInput[] - ? CustomShippingOption[] - : CustomShippingOption - >(data: T): Promise { - const customShippingOptionRepo = this.activeManager_.withRepository( - this.customShippingOptionRepository_ - ) - const data_ = ( - Array.isArray(data) ? data : [data] - ) as DeepPartial[] - - const customShippingOptions = customShippingOptionRepo.create(data_) - const shippingOptions = await customShippingOptionRepo.save( - customShippingOptions - ) - - return (Array.isArray(data) - ? shippingOptions - : shippingOptions[0]) as unknown as TResult - } -} - -export default CustomShippingOptionService diff --git a/packages/medusa/src/services/customer-group.ts b/packages/medusa/src/services/customer-group.ts deleted file mode 100644 index 33669a48b1..0000000000 --- a/packages/medusa/src/services/customer-group.ts +++ /dev/null @@ -1,284 +0,0 @@ -import { isDefined, MedusaError } from "medusa-core-utils" -import { DeepPartial, EntityManager, FindOptionsWhere, ILike } from "typeorm" -import { CustomerService } from "." -import { CustomerGroup } from ".." -import { - CustomerGroupRepository, - FindWithoutRelationsOptions, -} from "../repositories/customer-group" -import { FindConfig, Selector } from "../types/common" -import { CustomerGroupUpdate } from "../types/customer-groups" -import { buildQuery, isString, PostgresError, setMetadata } from "../utils" -import { TransactionBaseService } from "../interfaces" - -type CustomerGroupConstructorProps = { - manager: EntityManager - customerGroupRepository: typeof CustomerGroupRepository - customerService: CustomerService -} - -class CustomerGroupService extends TransactionBaseService { - protected readonly customerGroupRepository_: typeof CustomerGroupRepository - protected readonly customerService_: CustomerService - - constructor({ - customerGroupRepository, - customerService, - }: CustomerGroupConstructorProps) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.customerGroupRepository_ = customerGroupRepository - this.customerService_ = customerService - } - - async retrieve(customerGroupId: string, config = {}): Promise { - if (!isDefined(customerGroupId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"customerGroupId" must be defined` - ) - } - - const cgRepo = this.activeManager_.withRepository( - this.customerGroupRepository_ - ) - - const query = buildQuery({ id: customerGroupId }, config) - - const customerGroup = await cgRepo.findOne(query) - if (!customerGroup) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `CustomerGroup with id ${customerGroupId} was not found` - ) - } - - return customerGroup - } - - /** - * Creates a customer group with the provided data. - * @param group - the customer group to create - * @return the result of the create operation - */ - async create(group: DeepPartial): Promise { - return await this.atomicPhase_(async (manager) => { - try { - const cgRepo: typeof CustomerGroupRepository = manager.withRepository( - this.customerGroupRepository_ - ) - - const created = cgRepo.create(group) - return await cgRepo.save(created) - } catch (err) { - if (err.code === PostgresError.DUPLICATE_ERROR) { - throw new MedusaError(MedusaError.Types.DUPLICATE_ERROR, err.detail) - } - throw err - } - }) - } - - /** - * Add a batch of customers to a customer group at once - * @param id id of the customer group to add customers to - * @param customerIds customer id's to add to the group - * @return the customer group after insertion - */ - async addCustomers( - id: string, - customerIds: string | string[] - ): Promise { - let ids: string[] - if (typeof customerIds === "string") { - ids = [customerIds] - } else { - ids = customerIds - } - - return await this.atomicPhase_( - async (manager) => { - const cgRepo: typeof CustomerGroupRepository = manager.withRepository( - this.customerGroupRepository_ - ) - return await cgRepo.addCustomers(id, ids) - }, - async (e: any) => { - await this.handleCreationFail(id, ids, e) - } - ) - } - - /** - * Update a customer group. - * - * @param customerGroupId - id of the customer group - * @param update - customer group partial data - * @returns resulting customer group - */ - async update( - customerGroupId: string, - update: CustomerGroupUpdate - ): Promise { - return await this.atomicPhase_(async (manager) => { - const { metadata, ...properties } = update - - const cgRepo: typeof CustomerGroupRepository = manager.withRepository( - this.customerGroupRepository_ - ) - - const customerGroup = await this.retrieve(customerGroupId) - - for (const key in properties) { - if (isDefined(properties[key])) { - customerGroup[key] = properties[key] - } - } - - if (isDefined(metadata)) { - customerGroup.metadata = setMetadata(customerGroup, metadata) - } - - return await cgRepo.save(customerGroup) - }) - } - - /** - * Remove customer group - * - * @param groupId id of the customer group to delete - * @return a promise - */ - async delete(groupId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const cgRepo: typeof CustomerGroupRepository = manager.withRepository( - this.customerGroupRepository_ - ) - - const customerGroup = await cgRepo.findOne({ where: { id: groupId } }) - - if (customerGroup) { - await cgRepo.remove(customerGroup) - } - - return Promise.resolve() - }) - } - - /** - * List customer groups. - * - * @param selector - the query object for find - * @param config - the config to be used for find - * @return the result of the find operation - */ - async list( - selector: Selector & { - q?: string - discount_condition_id?: string - } = {}, - config: FindConfig - ): Promise { - const [customerGroups] = await this.listAndCount(selector, config) - return customerGroups - } - - /** - * Retrieve a list of customer groups and total count of records that match the query. - * - * @param selector - the query object for find - * @param config - the config to be used for find - * @return the result of the find operation - */ - async listAndCount( - selector: Selector & { - q?: string - discount_condition_id?: string - } = {}, - config: FindConfig - ): Promise<[CustomerGroup[], number]> { - const cgRepo = this.activeManager_.withRepository( - this.customerGroupRepository_ - ) - - let q - if (isString(selector.q)) { - q = selector.q - delete selector.q - } - - const query = buildQuery, any>(selector, config) - query.where = query.where as FindOptionsWhere - - if (q) { - query.where.name = ILike(`%${q}%`) - } - - if (query.where.discount_condition_id) { - const { relations, ...query_ } = query - return await cgRepo.findWithRelationsAndCount( - relations, - query_ as FindWithoutRelationsOptions - ) - } - - return await cgRepo.findAndCount(query) - } - - /** - * Remove list of customers from a customergroup - * - * @param id id of the customer group from which the customers are removed - * @param customerIds id's of the customer to remove from group - * @return the customergroup with the provided id - */ - async removeCustomer( - id: string, - customerIds: string[] | string - ): Promise { - const cgRepo = this.activeManager_.withRepository( - this.customerGroupRepository_ - ) - let ids: string[] - if (typeof customerIds === "string") { - ids = [customerIds] - } else { - ids = customerIds - } - - const customerGroup = await this.retrieve(id) - - await cgRepo.removeCustomers(id, ids) - - return customerGroup - } - - private async handleCreationFail( - id: string, - ids: string[], - error: any - ): Promise { - if (error.code === PostgresError.FOREIGN_KEY_ERROR) { - await this.retrieve(id) - - const existingCustomers = await this.customerService_.list({ - id: ids, - }) - - const nonExistingCustomers = ids.filter( - (cId) => existingCustomers.findIndex((el) => el.id === cId) === -1 - ) - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `The following customer ids do not exist: ${JSON.stringify( - nonExistingCustomers.join(", ") - )}` - ) - } - throw error - } -} - -export default CustomerGroupService diff --git a/packages/medusa/src/services/customer.ts b/packages/medusa/src/services/customer.ts deleted file mode 100644 index 5b085f77db..0000000000 --- a/packages/medusa/src/services/customer.ts +++ /dev/null @@ -1,580 +0,0 @@ -import jwt from "jsonwebtoken" -import { isDefined, MedusaError } from "medusa-core-utils" -import Scrypt from "scrypt-kdf" -import { - DeepPartial, - EntityManager, - FindOperator, - FindOptionsWhere, -} from "typeorm" -import { EventBusService } from "." -import { StorePostCustomersCustomerAddressesAddressReq } from "../api" -import { TransactionBaseService } from "../interfaces" -import { Address, Customer, CustomerGroup } from "../models" -import { AddressRepository } from "../repositories/address" -import { CustomerRepository } from "../repositories/customer" -import { - AddressCreatePayload, - ExtendedFindConfig, - FindConfig, - Selector, -} from "../types/common" -import { CreateCustomerInput, UpdateCustomerInput } from "../types/customers" -import { buildQuery, setMetadata } from "../utils" -import { selectorConstraintsToString } from "@medusajs/utils" - -type InjectedDependencies = { - manager: EntityManager - eventBusService: EventBusService - customerRepository: typeof CustomerRepository - addressRepository: typeof AddressRepository -} - -/** - * Provides layer to manipulate customers. - */ -class CustomerService extends TransactionBaseService { - protected readonly customerRepository_: typeof CustomerRepository - protected readonly addressRepository_: typeof AddressRepository - protected readonly eventBusService_: EventBusService - - static Events = { - PASSWORD_RESET: "customer.password_reset", - CREATED: "customer.created", - UPDATED: "customer.updated", - } - - constructor({ - customerRepository, - eventBusService, - addressRepository, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.customerRepository_ = customerRepository - this.eventBusService_ = eventBusService - this.addressRepository_ = addressRepository - } - - /** - * Generate a JSON Web token, that will be sent to a customer, that wishes to - * reset password. - * The token will be signed with the customer's current password hash as a - * secret a long side a payload with userId and the expiry time for the token, - * which is always 15 minutes. - * @param {string} customerId - the customer to reset the password for - * @return {string} the generated JSON web token - */ - async generateResetPasswordToken(customerId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const customer = await this.retrieve(customerId, { - select: [ - "id", - "has_account", - "password_hash", - "email", - "first_name", - "last_name", - ], - }) - - if (!customer.has_account) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "You must have an account to reset the password. Create an account first" - ) - } - - const secret = customer.password_hash - const expiry = Math.floor(Date.now() / 1000) + 60 * 15 // 15 minutes ahead - const payload = { customer_id: customer.id, exp: expiry } - const token = jwt.sign(payload, secret) - // Notify subscribers - void this.eventBusService_ - .withTransaction(manager) - .emit(CustomerService.Events.PASSWORD_RESET, { - id: customerId, - email: customer.email, - first_name: customer.first_name, - last_name: customer.last_name, - token, - }) - return token - }) - } - - /** - * @param {Object} selector - the query object for find - * @param {Object} config - the config object containing query settings - * @return {Promise} the result of the find operation - */ - async list( - selector: Selector & { q?: string; groups?: string[] } = {}, - config: FindConfig = { relations: [], skip: 0, take: 50 } - ): Promise { - const customerRepo = this.activeManager_.withRepository( - this.customerRepository_ - ) - - let q - if ("q" in selector) { - q = selector.q - delete selector.q - } - - const query = buildQuery, Customer>( - selector, - config - ) as ExtendedFindConfig & { - where: FindOptionsWhere< - Customer | (Customer & { groups?: FindOperator }) - > - } - - const [customers] = await customerRepo.listAndCount(query, q) - return customers - } - - /** - * @param {Object} selector - the query object for find - * @param {FindConfig} config - the config object containing query settings - * @return {Promise} the result of the find operation - */ - async listAndCount( - selector: Selector & { q?: string; groups?: string[] }, - config: FindConfig = { - relations: [], - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise<[Customer[], number]> { - const customerRepo = this.activeManager_.withRepository( - this.customerRepository_ - ) - - let q - if ("q" in selector) { - q = selector.q - delete selector.q - } - - const query = buildQuery( - selector, - config - ) as ExtendedFindConfig & { - where: FindOptionsWhere< - Customer | (Customer & { groups?: FindOperator }) - > - } - - return await customerRepo.listAndCount(query, q) - } - - /** - * Return the total number of documents in database - * @return {Promise} the result of the count operation - */ - async count(): Promise { - const customerRepo = this.activeManager_.withRepository( - this.customerRepository_ - ) - return await customerRepo.count({}) - } - - private async retrieve_( - selector: Selector, - config: FindConfig = {} - ): Promise { - const customerRepo = this.activeManager_.withRepository( - this.customerRepository_ - ) - - const query = buildQuery(selector, config) - const customer = await customerRepo.findOne(query) - - if (!customer) { - const selectorConstraints = selectorConstraintsToString(selector) - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Customer with ${selectorConstraints} was not found` - ) - } - - return customer - } - - /** - * Gets a registered customer by email. - * @param {string} email - the email of the customer to get. - * @param {Object} config - the config object containing query settings - * @return {Promise} the customer document. - * @deprecated - */ - async retrieveByEmail( - email: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(email)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"email" must be defined` - ) - } - - return await this.retrieve_({ email: email.toLowerCase() }, config) - } - - async retrieveUnregisteredByEmail( - email: string, - config: FindConfig = {} - ): Promise { - return await this.retrieve_( - { email: email.toLowerCase(), has_account: false }, - config - ) - } - async retrieveRegisteredByEmail( - email: string, - config: FindConfig = {} - ): Promise { - return await this.retrieve_( - { email: email.toLowerCase(), has_account: true }, - config - ) - } - - async listByEmail( - email: string, - config: FindConfig = { relations: [], skip: 0, take: 2 } - ): Promise { - return await this.list({ email: email.toLowerCase() }, config) - } - /** - * Gets a customer by phone. - * @param {string} phone - the phone of the customer to get. - * @param {Object} config - the config object containing query settings - * @return {Promise} the customer document. - */ - async retrieveByPhone( - phone: string, - config: FindConfig = {} - ): Promise { - return await this.retrieve_({ phone }, config) - } - - /** - * Gets a customer by id. - * @param {string} customerId - the id of the customer to get. - * @param {Object} config - the config object containing query settings - * @return {Promise} the customer document. - */ - async retrieve( - customerId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(customerId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"customerId" must be defined` - ) - } - - return this.retrieve_({ id: customerId }, config) - } - - /** - * Hashes a password - * @param {string} password - the value to hash - * @return {Promise} hashed password - */ - async hashPassword_(password: string): Promise { - const buf = await Scrypt.kdf(password, { logN: 1, r: 1, p: 1 }) - return buf.toString("base64") - } - - /** - * Creates a customer from an email - customers can have accounts associated, - * e.g. to login and view order history, etc. If a password is provided the - * customer will automatically get an account, otherwise the customer is just - * used to hold details of customers. - * @param {object} customer - the customer to create - * @return {Promise} the result of create - */ - async create(customer: CreateCustomerInput): Promise { - return await this.atomicPhase_(async (manager) => { - const customerRepository = manager.withRepository( - this.customerRepository_ - ) - - customer.email = customer.email.toLowerCase() - - const { email, password } = customer - - // should be a list of customers at this point - const existing = await this.listByEmail(email).catch(() => undefined) - - // should validate that "existing.some(acc => acc.has_account) && password" - if (existing) { - if (existing.some((customer) => customer.has_account) && password) { - throw new MedusaError( - MedusaError.Types.DUPLICATE_ERROR, - "A customer with the given email already has an account. Log in instead" - ) - } else if ( - existing?.some((customer) => !customer.has_account) && - !password - ) { - throw new MedusaError( - MedusaError.Types.DUPLICATE_ERROR, - "Guest customer with email already exists" - ) - } - } - - if (password) { - const hashedPassword = await this.hashPassword_(password) - customer.password_hash = hashedPassword - customer.has_account = true - delete customer.password - } - - const created = customerRepository.create(customer) - const result = await customerRepository.save(created) - - await this.eventBusService_ - .withTransaction(manager) - .emit(CustomerService.Events.CREATED, result) - - return result - }) - } - - /** - * Updates a customer. - * @param {string} customerId - the id of the variant. Must be a string that - * can be casted to an ObjectId - * @param {object} update - an object with the update values. - * @return {Promise} resolves to the update result. - */ - async update( - customerId: string, - update: UpdateCustomerInput - ): Promise { - return await this.atomicPhase_(async (manager) => { - const customerRepository = manager.withRepository( - this.customerRepository_ - ) - - const customer = await this.retrieve(customerId) - - const { - password, - metadata, - billing_address, - billing_address_id, - groups, - ...rest - } = update - - if (metadata) { - customer.metadata = setMetadata(customer, metadata) - } - - if ("billing_address_id" in update || "billing_address" in update) { - const address = billing_address_id || billing_address - if (isDefined(address)) { - await this.updateBillingAddress_(customer, address) - } - } - - for (const [key, value] of Object.entries(rest)) { - customer[key] = value - } - - if (password) { - customer.password_hash = await this.hashPassword_(password) - } - - if (groups) { - customer.groups = groups as CustomerGroup[] - } - - const updated = await customerRepository.save(customer) - - await this.eventBusService_ - .withTransaction(manager) - .emit(CustomerService.Events.UPDATED, updated) - - return updated - }) - } - - /** - * Updates the customers' billing address. - * @param {Customer} customer - the Customer to update - * @param {Object|string} addressOrId - the value to set the billing address to - * @return {Promise} the result of the update operation - */ - async updateBillingAddress_( - customer: Customer, - addressOrId: string | DeepPartial
| undefined - ): Promise { - return await this.atomicPhase_(async (manager) => { - const addrRepo: typeof AddressRepository = manager.withRepository( - this.addressRepository_ - ) - - if (addressOrId === null || addressOrId === undefined) { - customer.billing_address_id = null - return - } - - let address: DeepPartial
- if (typeof addressOrId === `string`) { - const fetchedAddress = await addrRepo.findOne({ - where: { id: addressOrId }, - }) - - if (!fetchedAddress) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Address with id ${addressOrId} was not found` - ) - } - - address = fetchedAddress - } else { - address = addressOrId - } - - address.country_code = address.country_code?.toLowerCase() - - if (isDefined(address?.id)) { - customer.billing_address_id = address.id - } else { - if (customer.billing_address_id) { - const addr = await addrRepo.findOne({ - where: { id: customer.billing_address_id }, - }) - - await addrRepo.save({ ...addr, ...address }) - } else { - const created = addrRepo.create(address) - const saved: Address = await addrRepo.save(created) - customer.billing_address = saved - } - } - }) - } - - async updateAddress( - customerId: string, - addressId: string, - address: StorePostCustomersCustomerAddressesAddressReq - ): Promise
{ - return await this.atomicPhase_(async (manager) => { - const addressRepo = manager.withRepository(this.addressRepository_) - - address.country_code = address.country_code?.toLowerCase() - - const toUpdate = await addressRepo.findOne({ - where: { id: addressId, customer_id: customerId }, - }) - - if (!toUpdate) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Could not find address for customer" - ) - } - for (const [key, value] of Object.entries(address)) { - toUpdate[key] = value - } - - return addressRepo.save(toUpdate) - }) - } - - async removeAddress(customerId: string, addressId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const addressRepo = manager.withRepository(this.addressRepository_) - - // Should not fail, if user does not exist, since delete is idempotent - const address = await addressRepo.findOne({ - where: { id: addressId, customer_id: customerId }, - }) - - if (!address) { - return - } - - await addressRepo.softRemove(address) - }) - } - - async addAddress( - customerId: string, - address: AddressCreatePayload - ): Promise { - return await this.atomicPhase_(async (manager) => { - const addressRepository = manager.withRepository(this.addressRepository_) - - address.country_code = address.country_code.toLowerCase() - - const customer = await this.retrieve(customerId, { - relations: ["shipping_addresses"], - }) - - const shouldAdd = !customer.shipping_addresses.find( - (a) => - a.country_code?.toLowerCase() === - address.country_code.toLowerCase() && - a.address_1 === address.address_1 && - a.address_2 === address.address_2 && - a.city === address.city && - a.phone === address.phone && - a.postal_code === address.postal_code && - a.province === address.province && - a.first_name === address.first_name && - a.last_name === address.last_name - ) - - if (shouldAdd) { - const created = addressRepository.create({ - ...address, - customer_id: customerId, - }) - const result = await addressRepository.save(created) - return result - } else { - return customer - } - }) - } - - /** - * Deletes a customer from a given customer id. - * @param {string} customerId - the id of the customer to delete. Must be - * castable as an ObjectId - * @return {Promise} the result of the delete operation. - */ - async delete(customerId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const customerRepo = manager.withRepository(this.customerRepository_) - - // Should not fail, if user does not exist, since delete is idempotent - const customer = await customerRepo.findOne({ where: { id: customerId } }) - - if (!customer) { - return - } - - return await customerRepo.softRemove(customer) - }) - } -} - -export default CustomerService diff --git a/packages/medusa/src/services/discount-condition.ts b/packages/medusa/src/services/discount-condition.ts deleted file mode 100644 index f94b072de7..0000000000 --- a/packages/medusa/src/services/discount-condition.ts +++ /dev/null @@ -1,236 +0,0 @@ -import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { - DiscountCondition, - DiscountConditionCustomerGroup, - DiscountConditionProduct, - DiscountConditionProductCollection, - DiscountConditionProductTag, - DiscountConditionProductType, - DiscountConditionType, -} from "../models" -import { DiscountConditionRepository } from "../repositories/discount-condition" -import { FindConfig } from "../types/common" -import { DiscountConditionInput } from "../types/discount" -import { buildQuery, PostgresError } from "../utils" -import EventBusService from "./event-bus" - -type InjectedDependencies = { - manager: EntityManager - discountConditionRepository: typeof DiscountConditionRepository - eventBusService: EventBusService -} - -/** - * Provides layer to manipulate discount conditions. - * @implements {BaseService} - */ -class DiscountConditionService extends TransactionBaseService { - // eslint-disable-next-line max-len - protected readonly discountConditionRepository_: typeof DiscountConditionRepository - protected readonly eventBus_: EventBusService - - constructor({ - discountConditionRepository, - eventBusService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.discountConditionRepository_ = discountConditionRepository - this.eventBus_ = eventBusService - } - - async retrieve( - conditionId: string, - config?: FindConfig - ): Promise { - if (!isDefined(conditionId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"conditionId" must be defined` - ) - } - - const conditionRepo = this.activeManager_.withRepository( - this.discountConditionRepository_ - ) - - const query = buildQuery({ id: conditionId }, config) - - const condition = await conditionRepo.findOne(query) - - if (!condition) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `DiscountCondition with id ${conditionId} was not found` - ) - } - - return condition - } - - protected static resolveConditionType_(data: DiscountConditionInput): - | { - type: DiscountConditionType - resource_ids: (string | { id: string })[] - } - | undefined { - switch (true) { - case !!data.products?.length: - return { - type: DiscountConditionType.PRODUCTS, - resource_ids: data.products!, - } - case !!data.product_collections?.length: - return { - type: DiscountConditionType.PRODUCT_COLLECTIONS, - resource_ids: data.product_collections!, - } - case !!data.product_types?.length: - return { - type: DiscountConditionType.PRODUCT_TYPES, - resource_ids: data.product_types!, - } - case !!data.product_tags?.length: - return { - type: DiscountConditionType.PRODUCT_TAGS, - resource_ids: data.product_tags!, - } - case !!data.customer_groups?.length: - return { - type: DiscountConditionType.CUSTOMER_GROUPS, - resource_ids: data.customer_groups!, - } - default: - return undefined - } - } - - async upsertCondition( - data: DiscountConditionInput, - overrideExisting = true - ): Promise< - ( - | DiscountConditionProduct - | DiscountConditionProductType - | DiscountConditionProductCollection - | DiscountConditionProductTag - | DiscountConditionCustomerGroup - )[] - > { - let resolvedConditionType - - return await this.atomicPhase_( - async (manager: EntityManager) => { - resolvedConditionType = - DiscountConditionService.resolveConditionType_(data) - - if (!resolvedConditionType) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Missing one of products, collections, tags, types or customer groups in data` - ) - } - - const discountConditionRepo = manager.withRepository( - this.discountConditionRepository_ - ) - - if (data.id) { - const resolvedCondition = await this.retrieve(data.id) - - if (data.operator && data.operator !== resolvedCondition.operator) { - resolvedCondition.operator = data.operator - await discountConditionRepo.save(resolvedCondition) - } - - return await discountConditionRepo.addConditionResources( - data.id, - resolvedConditionType.resource_ids, - resolvedConditionType.type, - overrideExisting - ) - } - - const created = discountConditionRepo.create({ - discount_rule_id: data.rule_id, - operator: data.operator, - type: resolvedConditionType.type, - }) - - const discountCondition = await discountConditionRepo.save(created) - - return await discountConditionRepo.addConditionResources( - discountCondition.id, - resolvedConditionType.resource_ids, - resolvedConditionType.type - ) - }, - async (err: { code: string }) => { - if (err.code === PostgresError.DUPLICATE_ERROR) { - // A unique key constraint failed meaning the combination of - // discount rule id, type, and operator already exists in the db. - throw new MedusaError( - MedusaError.Types.DUPLICATE_ERROR, - `Discount Condition with operator '${data.operator}' and type '${resolvedConditionType?.type}' already exist on a Discount Rule` - ) - } - } - ) - } - - async removeResources( - data: Omit & { id: string } - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const resolvedConditionType = - DiscountConditionService.resolveConditionType_(data) - - if (!resolvedConditionType) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Missing one of products, collections, tags, types or customer groups in data` - ) - } - - const discountConditionRepo = manager.withRepository( - this.discountConditionRepository_ - ) - - const resolvedCondition = await this.retrieve(data.id) - - if (data.operator && data.operator !== resolvedCondition.operator) { - resolvedCondition.operator = data.operator - await discountConditionRepo.save(resolvedCondition) - } - - await discountConditionRepo.removeConditionResources( - data.id, - resolvedConditionType.type, - resolvedConditionType.resource_ids - ) - }) - } - - async delete(discountConditionId: string): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const conditionRepo = manager.withRepository( - this.discountConditionRepository_ - ) - - const condition = await conditionRepo.findOne({ - where: { id: discountConditionId }, - }) - - if (!condition) { - return Promise.resolve() - } - - return await conditionRepo.remove(condition) - }) - } -} - -export default DiscountConditionService diff --git a/packages/medusa/src/services/discount.ts b/packages/medusa/src/services/discount.ts deleted file mode 100644 index 039e6db3f1..0000000000 --- a/packages/medusa/src/services/discount.ts +++ /dev/null @@ -1,826 +0,0 @@ -import { FlagRouter, promiseAll } from "@medusajs/utils" -import { parse, toSeconds } from "iso8601-duration" -import { isEmpty, omit } from "lodash" -import { isDefined, MedusaError } from "medusa-core-utils" -import { - DeepPartial, - EntityManager, - FindOptionsWhere, - ILike, - In, -} from "typeorm" -import { - NewTotalsService, - ProductService, - RegionService, - TotalsService, -} from "." -import { TransactionBaseService } from "../interfaces" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { - Cart, - Discount, - DiscountConditionType, - LineItem, - Region, -} from "../models" -import { - AllocationType as DiscountAllocation, - DiscountRule, - DiscountRuleType, -} from "../models/discount-rule" -import { DiscountRepository } from "../repositories/discount" -import { DiscountConditionRepository } from "../repositories/discount-condition" -import { DiscountRuleRepository } from "../repositories/discount-rule" -import { GiftCardRepository } from "../repositories/gift-card" -import { FindConfig, Selector } from "../types/common" -import { - CreateDiscountInput, - CreateDiscountRuleInput, - CreateDynamicDiscountInput, - FilterableDiscountProps, - UpdateDiscountInput, - UpdateDiscountRuleInput, -} from "../types/discount" -import { CalculationContextData } from "../types/totals" -import { buildQuery, setMetadata } from "../utils" -import { isFuture, isPast } from "../utils/date-helpers" -import CustomerService from "./customer" -import DiscountConditionService from "./discount-condition" -import EventBusService from "./event-bus" - -/** - * Provides layer to manipulate discounts. - * @implements {BaseService} - */ -class DiscountService extends TransactionBaseService { - static readonly Events = { - CREATED: "discount.created", - } - protected readonly discountRepository_: typeof DiscountRepository - protected readonly customerService_: CustomerService - protected readonly discountRuleRepository_: typeof DiscountRuleRepository - protected readonly giftCardRepository_: typeof GiftCardRepository - // eslint-disable-next-line max-len - protected readonly discountConditionRepository_: typeof DiscountConditionRepository - protected readonly discountConditionService_: DiscountConditionService - protected readonly totalsService_: TotalsService - protected readonly newTotalsService_: NewTotalsService - protected readonly productService_: ProductService - protected readonly regionService_: RegionService - protected readonly eventBus_: EventBusService - protected readonly featureFlagRouter_: FlagRouter - - constructor({ - discountRepository, - discountRuleRepository, - giftCardRepository, - discountConditionRepository, - discountConditionService, - totalsService, - newTotalsService, - productService, - regionService, - customerService, - eventBusService, - featureFlagRouter, - }) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.discountRepository_ = discountRepository - this.discountRuleRepository_ = discountRuleRepository - this.giftCardRepository_ = giftCardRepository - this.discountConditionRepository_ = discountConditionRepository - this.discountConditionService_ = discountConditionService - this.totalsService_ = totalsService - this.newTotalsService_ = newTotalsService - this.productService_ = productService - this.regionService_ = regionService - this.customerService_ = customerService - this.eventBus_ = eventBusService - this.featureFlagRouter_ = featureFlagRouter - } - - /** - * Creates a discount rule with provided data given that the data is validated. - * @param {DiscountRule} discountRule - the discount rule to create - * @return {Promise} the result of the create operation - */ - validateDiscountRule_( - discountRule: T - ): T { - if (discountRule.type === "percentage" && discountRule.value > 100) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Discount value above 100 is not allowed when type is percentage" - ) - } - - return discountRule - } - - /** - * @param {Object} selector - the query object for find - * @param {Object} config - the config object containing query settings - * @return {Promise} the result of the find operation - */ - async list( - selector: FilterableDiscountProps = {}, - config: FindConfig = { relations: [], skip: 0, take: 10 } - ): Promise { - const discountRepo = this.activeManager_.withRepository( - this.discountRepository_ - ) - - const query = buildQuery(selector as Selector, config) - return await discountRepo.find(query) - } - - /** - * @param {Object} selector - the query object for find - * @param {Object} config - the config object containing query settings - * @return {Promise} the result of the find operation - */ - async listAndCount( - selector: FilterableDiscountProps = {}, - config: FindConfig = { - take: 20, - skip: 0, - order: { created_at: "DESC" }, - } - ): Promise<[Discount[], number]> { - const discountRepo = this.activeManager_.withRepository( - this.discountRepository_ - ) - - let q - if ("q" in selector) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector as Selector, config) - - if (q) { - query.where = query.where as FindOptionsWhere - query.where.code = ILike(`%${q}%`) - } - - const [discounts, count] = await discountRepo.findAndCount(query) - - return [discounts, count] - } - - /** - * Creates a discount with provided data given that the data is validated. - * Normalizes discount code to uppercase. - * @param {Discount} discount - the discount data to create - * @return {Promise} the result of the create operation - */ - async create(discount: CreateDiscountInput): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const discountRepo = manager.withRepository(this.discountRepository_) - const ruleRepo = manager.withRepository(this.discountRuleRepository_) - - const conditions = discount.rule?.conditions - - const ruleToCreate = omit(discount.rule, ["conditions"]) - const validatedRule: Omit = - this.validateDiscountRule_(ruleToCreate) - - if ( - discount?.regions && - discount?.regions.length > 1 && - discount?.rule?.type === "fixed" - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Fixed discounts can have one region" - ) - } - if (discount.regions) { - discount.regions = (await promiseAll( - discount.regions.map(async (regionId) => - this.regionService_.withTransaction(manager).retrieve(regionId) - ) - )) as Region[] - } - - if (!discount.regions?.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Discount must have at least 1 region" - ) - } - - const discountRule = ruleRepo.create(validatedRule) - const createdDiscountRule = await ruleRepo.save(discountRule) - - const created: Discount = discountRepo.create( - discount as DeepPartial - ) - created.rule = createdDiscountRule - - const result = await discountRepo.save(created) - - if (conditions?.length) { - await promiseAll( - conditions.map(async (cond) => { - await this.discountConditionService_ - .withTransaction(manager) - .upsertCondition({ rule_id: result.rule_id, ...cond }) - }) - ) - } - - await this.eventBus_ - .withTransaction(manager) - .emit(DiscountService.Events.CREATED, { id: result.id }) - - return result - }) - } - - /** - * Gets a discount by id. - * @param {string} discountId - id of discount to retrieve - * @param {Object} config - the config object containing query settings - * @return {Promise} the discount - */ - async retrieve( - discountId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(discountId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"discountId" must be defined` - ) - } - - const discountRepo = this.activeManager_.withRepository( - this.discountRepository_ - ) - - const query = buildQuery({ id: discountId }, config) - const discount = await discountRepo.findOne(query) - - if (!discount) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Discount with id ${discountId} was not found` - ) - } - - return discount - } - - /** - * Gets the discount by discount code. - * @param discountCode - discount code of discount to retrieve - * @param config - the config object containing query settings - * @return the discount - */ - async retrieveByCode( - discountCode: string, - config: FindConfig = {} - ): Promise { - const discountRepo = this.activeManager_.withRepository( - this.discountRepository_ - ) - - const normalizedCode = discountCode.toUpperCase().trim() - - const query = buildQuery({ code: normalizedCode }, config) - const discount = await discountRepo.findOne(query) - - if (!discount) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Discounts with code ${discountCode} was not found` - ) - } - - return discount - } - - /** - * List all the discounts corresponding to the given codes - * @param discountCodes - discount codes of discounts to retrieve - * @param config - the config object containing query settings - * @return the discounts - */ - async listByCodes( - discountCodes: string[], - config: FindConfig = {} - ): Promise { - const discountRepo = this.activeManager_.withRepository( - this.discountRepository_ - ) - - const normalizedCodes = discountCodes.map((code) => - code.toUpperCase().trim() - ) - - const query = buildQuery({ code: In(normalizedCodes) }, config) - const discounts = await discountRepo.find(query) - - if (discounts?.length !== discountCodes.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Discounts with code [${normalizedCodes.join(", ")}] was not found` - ) - } - - return discounts - } - - /** - * Updates a discount. - * @param {string} discountId - discount id of discount to update - * @param {Discount} update - the data to update the discount with - * @return {Promise} the result of the update operation - */ - async update( - discountId: string, - update: UpdateDiscountInput - ): Promise { - return await this.atomicPhase_(async (manager) => { - const discountRepo = manager.withRepository(this.discountRepository_) - const ruleRepo = manager.withRepository(this.discountRuleRepository_) - - const discount = await this.retrieve(discountId, { - relations: ["rule"], - }) - - const conditions = update?.rule?.conditions - const ruleToUpdate = omit(update.rule, "conditions") - - if (!isEmpty(ruleToUpdate)) { - update.rule = ruleToUpdate as UpdateDiscountRuleInput - } - - const { rule, metadata, regions, ...rest } = update - - if (rest.ends_at) { - if (discount.starts_at >= new Date(rest.ends_at)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `"ends_at" must be greater than "starts_at"` - ) - } - } - - if (regions && regions?.length > 1 && discount.rule.type === "fixed") { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Fixed discounts can have one region" - ) - } - - if (conditions?.length) { - await promiseAll( - conditions.map(async (cond) => { - await this.discountConditionService_ - .withTransaction(manager) - .upsertCondition({ rule_id: discount.rule_id, ...cond }) - }) - ) - } - - if (regions) { - discount.regions = await promiseAll( - regions.map(async (regionId) => - this.regionService_.retrieve(regionId) - ) - ) - } - - if (metadata) { - discount.metadata = setMetadata(discount, metadata) - } - - if (rule) { - const ruleUpdate: Omit = rule - - if (rule.value) { - this.validateDiscountRule_({ - value: rule.value, - type: discount.rule.type, - }) - } - - discount.rule = ruleRepo.create({ - ...discount.rule, - ...ruleUpdate, - } as DiscountRule) - } - - for (const key of Object.keys(rest).filter( - (k) => typeof rest[k] !== `undefined` - )) { - discount[key] = rest[key] - } - - discount.code = discount.code.toUpperCase() - - return await discountRepo.save(discount) - }) - } - - /** - * Creates a dynamic code for a discount id. - * @param {string} discountId - the id of the discount to create a code for - * @param {Object} data - the object containing a code to identify the discount by - * @return {Promise} the newly created dynamic code - */ - async createDynamicCode( - discountId: string, - data: CreateDynamicDiscountInput - ): Promise { - return await this.atomicPhase_(async (manager) => { - const discountRepo = manager.withRepository(this.discountRepository_) - - const discount = await this.retrieve(discountId) - - if (!discount.is_dynamic) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Discount must be set to dynamic" - ) - } - - if (!data.code) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Discount must have a code" - ) - } - - const toCreate = { - ...data, - rule_id: discount.rule_id, - is_dynamic: true, - is_disabled: false, - code: data.code.toUpperCase(), - parent_discount_id: discount.id, - usage_limit: discount.usage_limit, - } - - if (discount.valid_duration) { - const lastValidDate = new Date() - lastValidDate.setSeconds( - lastValidDate.getSeconds() + toSeconds(parse(discount.valid_duration)) - ) - toCreate.ends_at = lastValidDate - } - const created: Discount = discountRepo.create(toCreate) - return await discountRepo.save(created) - }) - } - - /** - * Deletes a dynamic code for a discount id. - * @param {string} discountId - the id of the discount to create a code for - * @param {string} code - the code to identify the discount by - * @return {Promise} the newly created dynamic code - */ - async deleteDynamicCode(discountId: string, code: string): Promise { - return await this.atomicPhase_(async (manager) => { - const discountRepo = manager.withRepository(this.discountRepository_) - const discount = await discountRepo.findOne({ - where: { parent_discount_id: discountId, code }, - }) - - if (!discount) { - return - } - - await discountRepo.softRemove(discount) - }) - } - - /** - * Adds a region to the discount regions array. - * @param {string} discountId - id of discount - * @param {string} regionId - id of region to add - * @return {Promise} the result of the update operation - */ - async addRegion(discountId: string, regionId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const discountRepo = manager.withRepository(this.discountRepository_) - - const discount = await this.retrieve(discountId, { - relations: ["regions", "rule"], - }) - - const exists = discount.regions.find((r) => r.id === regionId) - // If region is already present, we return early - if (exists) { - return discount - } - - if (discount.regions?.length === 1 && discount.rule.type === "fixed") { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Fixed discounts can have one region" - ) - } - - const region = await this.regionService_.retrieve(regionId) - - discount.regions = [...discount.regions, region] - - return await discountRepo.save(discount) - }) - } - - /** - * Removes a region from the discount regions array. - * @param {string} discountId - id of discount - * @param {string} regionId - id of region to remove - * @return {Promise} the result of the update operation - */ - async removeRegion(discountId: string, regionId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const discountRepo = manager.withRepository(this.discountRepository_) - - const discount = await this.retrieve(discountId, { - relations: ["regions"], - }) - - const exists = discount.regions.find((r) => r.id === regionId) - // If region is not present, we return early - if (!exists) { - return discount - } - - discount.regions = discount.regions.filter((r) => r.id !== regionId) - - return await discountRepo.save(discount) - }) - } - - /** - * Deletes a discount idempotently - * @param {string} discountId - id of discount to delete - * @return {Promise} the result of the delete operation - */ - async delete(discountId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const discountRepo = manager.withRepository(this.discountRepository_) - - const discount = await discountRepo.findOne({ where: { id: discountId } }) - - if (!discount) { - return - } - - await discountRepo.softRemove(discount) - }) - } - - async validateDiscountForProduct( - discountRuleId: string, - productId?: string - ): Promise { - return await this.atomicPhase_(async (manager) => { - const discountConditionRepo = manager.withRepository( - this.discountConditionRepository_ - ) - - // In case of custom line items, we don't have a product id. - // Instead of throwing, we simply invalidate the discount. - if (!productId) { - return false - } - - return await discountConditionRepo.isValidForProduct( - discountRuleId, - productId - ) - }) - } - - async calculateDiscountForLineItem( - discountId: string, - lineItem: LineItem, - calculationContextData: CalculationContextData - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - let adjustment = 0 - - if (!lineItem.allow_discounts) { - return adjustment - } - - const discount = await this.retrieve(discountId, { relations: ["rule"] }) - - const { type, value, allocation } = discount.rule - - const calculationContext = await this.totalsService_ - .withTransaction(transactionManager) - .getCalculationContext(calculationContextData, { - exclude_shipping: true, - }) - - let fullItemPrice = lineItem.unit_price * lineItem.quantity - const includesTax = - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && lineItem.includes_tax - - if (includesTax) { - const lineItemTotals = await this.newTotalsService_ - .withTransaction(transactionManager) - .getLineItemTotals([lineItem], { - includeTax: true, - calculationContext, - }) - fullItemPrice = lineItemTotals[lineItem.id].subtotal - } - - if (type === DiscountRuleType.PERCENTAGE) { - adjustment = Math.round((fullItemPrice / 100) * value) - } else if ( - type === DiscountRuleType.FIXED && - allocation === DiscountAllocation.TOTAL - ) { - // when a fixed discount should be applied to the total, - // we create line adjustments for each item with an amount - // relative to the subtotal - const discountedItems = calculationContextData.items.filter( - (item) => item.allow_discounts - ) - const totals = await this.newTotalsService_.getLineItemTotals( - discountedItems, - { - includeTax: includesTax, - calculationContext, - } - ) - const subtotal = Object.values(totals).reduce((subtotal, total) => { - subtotal += total.subtotal - return subtotal - }, 0) - const nominator = Math.min(value, subtotal) - const totalItemPercentage = fullItemPrice / subtotal - - adjustment = nominator * totalItemPercentage - } else { - adjustment = value * lineItem.quantity - } - - return Math.min(adjustment, fullItemPrice) - }) - } - - async validateDiscountForCartOrThrow( - cart: Cart, - discount: Discount | Discount[] - ): Promise { - const discounts = Array.isArray(discount) ? discount : [discount] - return await this.atomicPhase_(async () => { - await promiseAll( - discounts.map(async (disc) => { - if (this.hasReachedLimit(disc)) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Discount ${disc.code} has been used maximum allowed times` - ) - } - - if (this.hasNotStarted(disc)) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Discount ${disc.code} is not valid yet` - ) - } - - if (this.hasExpired(disc)) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Discount ${disc.code} is expired` - ) - } - - if (this.isDisabled(disc)) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `The discount code ${disc.code} is disabled` - ) - } - - if (!cart.customer_id && this.hasCustomersGroupCondition(disc)) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Discount ${disc.code} is only valid for specific customer` - ) - } - - const isValidForRegion = await this.isValidForRegion( - disc, - cart.region_id - ) - if (!isValidForRegion) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "The discount is not available in current region" - ) - } - - if (cart.customer_id) { - const canApplyForCustomer = await this.canApplyForCustomer( - disc.rule.id, - cart.customer_id - ) - - if (!canApplyForCustomer) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Discount ${disc.code} is not valid for customer` - ) - } - } - }) - ) - }) - } - - hasCustomersGroupCondition(discount: Discount): boolean { - return discount.rule.conditions.some( - (cond) => cond.type === DiscountConditionType.CUSTOMER_GROUPS - ) - } - - hasReachedLimit(discount: Discount): boolean { - const count = discount.usage_count || 0 - const limit = discount.usage_limit - return !!limit && count >= limit - } - - hasNotStarted(discount: Discount): boolean { - return isFuture(discount.starts_at) - } - - hasExpired(discount: Discount): boolean { - if (!discount.ends_at) { - return false - } - - return isPast(discount.ends_at) - } - - isDisabled(discount: Discount): boolean { - return discount.is_disabled - } - - async isValidForRegion( - discount: Discount, - region_id: string - ): Promise { - return await this.atomicPhase_(async () => { - let regions = discount.regions - - if (discount.parent_discount_id) { - const parent = await this.retrieve(discount.parent_discount_id, { - relations: ["rule", "regions"], - }) - - regions = parent.regions - } - - return regions.find(({ id }) => id === region_id) !== undefined - }) - } - - async canApplyForCustomer( - discountRuleId: string, - customerId: string | undefined - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const discountConditionRepo = manager.withRepository( - this.discountConditionRepository_ - ) - - // Instead of throwing on missing customer id, we simply invalidate the discount - if (!customerId) { - return false - } - - const customer = await this.customerService_ - .withTransaction(manager) - .retrieve(customerId, { - relations: ["groups"], - }) - - return await discountConditionRepo.canApplyForCustomer( - discountRuleId, - customer.id - ) - }) - } -} - -export default DiscountService diff --git a/packages/medusa/src/services/draft-order.ts b/packages/medusa/src/services/draft-order.ts deleted file mode 100644 index 561c7909aa..0000000000 --- a/packages/medusa/src/services/draft-order.ts +++ /dev/null @@ -1,489 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { - EntityManager, - FindOptionsWhere, - ILike, - IsNull, - Not, - Raw, - UpdateResult, -} from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { - CartType, - DraftOrder, - DraftOrderStatus, - LineItem, - ShippingMethod, -} from "../models" -import { DraftOrderRepository } from "../repositories/draft-order" -import { OrderRepository } from "../repositories/order" -import { PaymentRepository } from "../repositories/payment" -import { FindConfig } from "../types/common" -import { DraftOrderCreateProps } from "../types/draft-orders" -import { GenerateInputData } from "../types/line-item" -import { buildQuery } from "../utils" -import CartService from "./cart" -import CustomShippingOptionService from "./custom-shipping-option" -import EventBusService from "./event-bus" -import LineItemService from "./line-item" -import ProductVariantService from "./product-variant" -import ShippingOptionService from "./shipping-option" -import { isDefined, promiseAll } from "@medusajs/utils" - -type InjectedDependencies = { - manager: EntityManager - draftOrderRepository: typeof DraftOrderRepository - paymentRepository: typeof PaymentRepository - orderRepository: typeof OrderRepository - eventBusService: EventBusService - cartService: CartService - lineItemService: LineItemService - productVariantService: ProductVariantService - shippingOptionService: ShippingOptionService - customShippingOptionService: CustomShippingOptionService -} - -/** - * Handles draft orders - * @implements {BaseService} - */ -class DraftOrderService extends TransactionBaseService { - static readonly Events = { - CREATED: "draft_order.created", - UPDATED: "draft_order.updated", - } - - protected readonly draftOrderRepository_: typeof DraftOrderRepository - protected readonly paymentRepository_: typeof PaymentRepository - protected readonly orderRepository_: typeof OrderRepository - protected readonly eventBus_: EventBusService - protected readonly cartService_: CartService - protected readonly lineItemService_: LineItemService - protected readonly productVariantService_: ProductVariantService - protected readonly shippingOptionService_: ShippingOptionService - protected readonly customShippingOptionService_: CustomShippingOptionService - - constructor({ - draftOrderRepository, - paymentRepository, - orderRepository, - eventBusService, - cartService, - lineItemService, - productVariantService, - shippingOptionService, - customShippingOptionService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.draftOrderRepository_ = draftOrderRepository - this.paymentRepository_ = paymentRepository - this.orderRepository_ = orderRepository - this.lineItemService_ = lineItemService - this.cartService_ = cartService - this.productVariantService_ = productVariantService - this.shippingOptionService_ = shippingOptionService - this.customShippingOptionService_ = customShippingOptionService - this.eventBus_ = eventBusService - } - - /** - * Retrieves a draft order with the given id. - * @param draftOrderId - id of the draft order to retrieve - * @param config - query object for findOne - * @return the draft order - */ - async retrieve( - draftOrderId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(draftOrderId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"draftOrderId" must be defined` - ) - } - - const draftOrderRepo = this.activeManager_.withRepository( - this.draftOrderRepository_ - ) - - const query = buildQuery({ id: draftOrderId }, config) - const draftOrder = await draftOrderRepo.findOne(query) - if (!draftOrder) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Draft order with ${draftOrderId} was not found` - ) - } - - return draftOrder - } - - /** - * Retrieves a draft order based on its associated cart id - * @param cartId - cart id that the draft orders's cart has - * @param config - query object for findOne - * @return the draft order - */ - async retrieveByCartId( - cartId: string, - config: FindConfig = {} - ): Promise { - const draftOrderRepo = this.activeManager_.withRepository( - this.draftOrderRepository_ - ) - - const query = buildQuery({ cart_id: cartId }, config) - const draftOrder = await draftOrderRepo.findOne(query) - if (!draftOrder) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Draft order was not found` - ) - } - - return draftOrder - } - - /** - * Deletes draft order idempotently. - * @param {string} draftOrderId - id of draft order to delete - * @return {Promise} empty promise - */ - async delete(draftOrderId: string): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const draftOrderRepo = transactionManager.withRepository( - this.draftOrderRepository_ - ) - const draftOrder = await draftOrderRepo.findOne({ - where: { id: draftOrderId }, - }) - - if (!draftOrder) { - return - } - return await draftOrderRepo.remove(draftOrder) - } - ) - } - - /** - * Lists draft orders alongside the count - * @param selector - query selector to filter draft orders - * @param config - query config - * @return draft orders - */ - async listAndCount( - selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise<[DraftOrder[], number]> { - const draftOrderRepository = this.activeManager_.withRepository( - this.draftOrderRepository_ - ) - - const { q, ...restSelector } = selector - const query = buildQuery(restSelector, config) - - if (q) { - query.where = query.where as FindOptionsWhere - delete query.where?.display_id - - query.relations = query.relations ?? {} - query.relations.cart = query.relations.cart ?? true - - const innerJoinLikeConstraint = { - cart: { - id: Not(IsNull()), - }, - } - - query.where = query.where as FindOptionsWhere[] - query.where = [ - { - ...query.where, - ...innerJoinLikeConstraint, - cart: { - ...innerJoinLikeConstraint.cart, - id: Not(IsNull()), - email: ILike(`%${q}%`), - }, - }, - { - ...query.where, - ...innerJoinLikeConstraint, - display_id: Raw((alias) => `CAST(${alias} as varchar) ILike :q`, { - q: `%${q}%`, - }), - }, - ] - } - - return await draftOrderRepository.findAndCount(query) - } - - /** - * Lists draft orders - * @param selector - query object for find - * @param config - configurable attributes for find - * @return list of draft orders - */ - async list( - selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise { - const draftOrderRepo = this.activeManager_.withRepository( - this.draftOrderRepository_ - ) - - const query = buildQuery(selector, config) - - return await draftOrderRepo.find(query) - } - - /** - * Creates a draft order. - * @param data - data to create draft order from - * @return the created draft order - */ - async create(data: DraftOrderCreateProps): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const draftOrderRepo = transactionManager.withRepository( - this.draftOrderRepository_ - ) - - if (!data.region_id) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `region_id is required to create a draft order` - ) - } - - const { - shipping_methods, - no_notification_order, - items, - idempotency_key, - discounts, - ...rawCart - } = data - - const cartServiceTx = - this.cartService_.withTransaction(transactionManager) - - let createdCart = await cartServiceTx.create({ - type: CartType.DRAFT_ORDER, - ...rawCart, - }) - - const draftOrder = draftOrderRepo.create({ - cart_id: createdCart.id, - no_notification_order, - idempotency_key, - }) - - const result = await draftOrderRepo.save(draftOrder) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(DraftOrderService.Events.CREATED, { - id: result.id, - }) - - const lineItemServiceTx = - this.lineItemService_.withTransaction(transactionManager) - - const itemsToGenerate: GenerateInputData[] = [] - const itemsToCreate: Partial[] = [] - - // prepare that for next steps - ;(items ?? []).forEach((item) => { - if (item.variant_id) { - itemsToGenerate.push({ - variantId: item.variant_id, - quantity: item.quantity, - metadata: item.metadata, - unit_price: item.unit_price, - }) - return - } - - let price - if (!isDefined(item.unit_price) || item.unit_price < 0) { - price = 0 - } else { - price = item.unit_price - } - - itemsToCreate.push({ - cart_id: createdCart.id, - has_shipping: true, - title: item.title || "Custom item", - allow_discounts: false, - unit_price: price, - quantity: item.quantity, - metadata: item.metadata, - }) - }) - - const promises: Promise[] = [] - - // generate line item link to a variant - if (itemsToGenerate.length) { - const generatedLines = await lineItemServiceTx.generate( - itemsToGenerate, - { - region_id: data.region_id, - } - ) - - const toCreate = generatedLines.map((line) => ({ - ...line, - cart_id: createdCart.id, - })) - - promises.push(lineItemServiceTx.create(toCreate)) - } - - // custom line items can be added to a draft order - if (itemsToCreate.length) { - promises.push(lineItemServiceTx.create(itemsToCreate)) - } - - const shippingMethodToCreate: Partial[] = [] - - shipping_methods.forEach((method) => { - if (isDefined(method.price)) { - shippingMethodToCreate.push({ - shipping_option_id: method.option_id, - cart_id: createdCart.id, - price: method.price, - }) - return - } - }) - - if (shippingMethodToCreate.length) { - await this.customShippingOptionService_ - .withTransaction(transactionManager) - .create(shippingMethodToCreate) - } - - createdCart = await cartServiceTx.retrieveWithTotals(createdCart.id, { - relations: [ - "shipping_methods", - "shipping_methods.shipping_option", - "items.variant.product.profiles", - "payment_sessions", - ], - }) - - shipping_methods.forEach((method) => { - promises.push( - cartServiceTx.addShippingMethod( - createdCart, - method.option_id, - method.data - ) - ) - }) - - await promiseAll(promises) - - if (discounts?.length) { - await cartServiceTx.update(createdCart.id, { discounts }) - } - - return result - } - ) - } - - /** - * Registers a draft order as completed, when an order has been completed. - * @param draftOrderId - id of draft order to complete - * @param orderId - id of order completed from draft order cart - * @return the created order - */ - async registerCartCompletion( - draftOrderId: string, - orderId: string - ): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const draftOrderRepo = transactionManager.withRepository( - this.draftOrderRepository_ - ) - return await draftOrderRepo.update( - { - id: draftOrderId, - }, - { - status: DraftOrderStatus.COMPLETED, - completed_at: new Date(), - order_id: orderId, - } - ) - } - ) - } - - /** - * Updates a draft order with the given data - * @param id - id of the draft order - * @param data - values to update the order with - * @return the updated draft order - */ - async update( - id: string, - data: { no_notification_order: boolean } - ): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const draftOrderRepo = transactionManager.withRepository( - this.draftOrderRepository_ - ) - const draftOrder = await this.retrieve(id) - - if (draftOrder.status === DraftOrderStatus.COMPLETED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Can't update a draft order which is complete" - ) - } - - let touched = false - if (data.no_notification_order !== undefined) { - touched = true - draftOrder.no_notification_order = data.no_notification_order - } - - if (touched) { - await draftOrderRepo.save(draftOrder) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(DraftOrderService.Events.UPDATED, { - id: draftOrder.id, - }) - } - - return draftOrder - } - ) - } -} - -export default DraftOrderService diff --git a/packages/medusa/src/services/file.ts b/packages/medusa/src/services/file.ts deleted file mode 100644 index adaaa2930e..0000000000 --- a/packages/medusa/src/services/file.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { AbstractFileService } from "../interfaces" -import { - FileServiceGetUploadStreamResult, - FileServiceUploadResult, - GetUploadedFileType, - UploadStreamDescriptorType, -} from "@medusajs/types" - -class DefaultFileService extends AbstractFileService { - async upload( - fileData: Express.Multer.File - ): Promise { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Please add a file service plugin in order to manipulate files in Medusa" - ) - } - async uploadProtected( - fileData: Express.Multer.File - ): Promise { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Please add a file service plugin in order to manipulate files in Medusa" - ) - } - async delete(fileData: Record): Promise { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Please add a file service plugin in order to manipulate files in Medusa" - ) - } - async getUploadStreamDescriptor( - fileData: UploadStreamDescriptorType - ): Promise { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Please add a file service plugin in order to manipulate files in Medusa" - ) - } - async getDownloadStream( - fileData: GetUploadedFileType - ): Promise { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Please add a file service plugin in order to manipulate files in Medusa" - ) - } - async getPresignedDownloadUrl( - fileData: GetUploadedFileType - ): Promise { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Please add a file service plugin in order to manipulate files in Medusa" - ) - } - protected manager_: EntityManager - protected transactionManager_: EntityManager | undefined -} - -export default DefaultFileService diff --git a/packages/medusa/src/services/fulfillment-provider.ts b/packages/medusa/src/services/fulfillment-provider.ts deleted file mode 100644 index 1f2d9e3d7b..0000000000 --- a/packages/medusa/src/services/fulfillment-provider.ts +++ /dev/null @@ -1,195 +0,0 @@ -import { promiseAll } from "@medusajs/utils" -import { MedusaError } from "medusa-core-utils" -import BaseFulfillmentService from "medusa-interfaces" -import { EntityManager } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { - Cart, - Fulfillment, - FulfillmentProvider, - LineItem, - Order, - ShippingMethod, - ShippingOption, -} from "../models" -import { FulfillmentProviderRepository } from "../repositories/fulfillment-provider" -import { CreateFulfillmentOrder } from "../types/fulfillment" -import { - CreateReturnType, - FulfillmentOptions, -} from "../types/fulfillment-provider" -import { MedusaContainer } from "../types/global" - -type FulfillmentProviderKey = `fp_${string}` - -type FulfillmentProviderContainer = MedusaContainer & { - fulfillmentProviderRepository: typeof FulfillmentProviderRepository - manager: EntityManager -} & { - [key in `${FulfillmentProviderKey}`]: typeof BaseFulfillmentService -} - -type CalculateOptionPriceInput = { - provider_id: string - data: Record -} - -/** - * Helps retrieve fulfillment providers - */ -class FulfillmentProviderService extends TransactionBaseService { - protected readonly container_: FulfillmentProviderContainer - // eslint-disable-next-line max-len - protected readonly fulfillmentProviderRepository_: typeof FulfillmentProviderRepository - - constructor(container: FulfillmentProviderContainer) { - super(container) - - const { fulfillmentProviderRepository } = container - - this.container_ = container - this.fulfillmentProviderRepository_ = fulfillmentProviderRepository - } - - async registerInstalledProviders(providers: string[]): Promise { - return await this.atomicPhase_(async (manager) => { - const fulfillmentProviderRepo = manager.withRepository( - this.fulfillmentProviderRepository_ - ) - await fulfillmentProviderRepo.update({}, { is_installed: false }) - - for (const p of providers) { - const n = fulfillmentProviderRepo.create({ id: p, is_installed: true }) - await fulfillmentProviderRepo.save(n) - } - }) - } - - async list(): Promise { - const fpRepo = this.activeManager_.withRepository( - this.fulfillmentProviderRepository_ - ) - - return await fpRepo.find({}) - } - - async listFulfillmentOptions( - providerIds: string[] - ): Promise { - return await promiseAll( - providerIds.map(async (p) => { - const provider = this.retrieveProvider(p) - return { - provider_id: p, - options: (await provider.getFulfillmentOptions()) as Record< - string, - unknown - >[], - } - }) - ) - } - - /** - * @param providerId - the provider id - * @return the payment fulfillment provider - */ - retrieveProvider(providerId: string): typeof BaseFulfillmentService { - try { - return this.container_[`fp_${providerId}`] - } catch (err) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Could not find a fulfillment provider with id: ${providerId}` - ) - } - } - - async createFulfillment( - method: ShippingMethod, - items: LineItem[], - order: CreateFulfillmentOrder, - fulfillment: Omit - ): Promise> { - const provider = this.retrieveProvider(method.shipping_option.provider_id) - return provider.createFulfillment( - method.data, - items, - order, - fulfillment - ) as unknown as Record - } - - async canCalculate(option: CalculateOptionPriceInput): Promise { - const provider = this.retrieveProvider(option.provider_id) - return provider.canCalculate(option.data) as unknown as boolean - } - - async validateFulfillmentData( - option: ShippingOption, - data: Record, - cart: Cart | Record - ): Promise> { - const provider = this.retrieveProvider(option.provider_id) - return provider.validateFulfillmentData( - option.data, - data, - cart - ) as unknown as Record - } - - async cancelFulfillment(fulfillment: Fulfillment): Promise { - const provider = this.retrieveProvider(fulfillment.provider_id) - return provider.cancelFulfillment( - fulfillment.data - ) as unknown as Fulfillment - } - - async calculatePrice( - option: ShippingOption, - data: Record, - cart?: Order | Cart - ): Promise { - const provider = this.retrieveProvider(option.provider_id) - return (await provider.calculatePrice( - option.data, - data, - cart - )) as unknown as number - } - - async validateOption(option: ShippingOption): Promise { - const provider = this.retrieveProvider(option.provider_id) - return provider.validateOption(option.data) as unknown as boolean - } - - async createReturn( - returnOrder: CreateReturnType - ): Promise> { - const option = returnOrder.shipping_method.shipping_option - const provider = this.retrieveProvider(option.provider_id) - return provider.createReturn(returnOrder) as unknown as Record< - string, - unknown - > - } - - /** - * Fetches documents from the fulfillment provider - * @param providerId - the id of the provider - * @param fulfillmentData - the data relating to the fulfillment - * @param documentType - the typ of - * @returns document to fetch - */ - // TODO: consider removal in favor of "getReturnDocuments" and "getShipmentDocuments" - async retrieveDocuments( - providerId: string, - fulfillmentData: Record, - documentType: "invoice" | "label" - ): Promise { - const provider = this.retrieveProvider(providerId) - return provider.retrieveDocuments(fulfillmentData, documentType) - } -} - -export default FulfillmentProviderService diff --git a/packages/medusa/src/services/fulfillment.ts b/packages/medusa/src/services/fulfillment.ts deleted file mode 100644 index 304eaab483..0000000000 --- a/packages/medusa/src/services/fulfillment.ts +++ /dev/null @@ -1,359 +0,0 @@ -import { promiseAll } from "@medusajs/utils" -import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { ProductVariantInventoryService, ShippingProfileService } from "." -import { TransactionBaseService } from "../interfaces" -import { Fulfillment, LineItem, ShippingMethod } from "../models" -import { FulfillmentRepository } from "../repositories/fulfillment" -import { LineItemRepository } from "../repositories/line-item" -import { TrackingLinkRepository } from "../repositories/tracking-link" -import { FindConfig } from "../types/common" -import { - CreateFulfillmentOrder, - CreateShipmentConfig, - FulfillmentItemPartition, - FulFillmentItemType, -} from "../types/fulfillment" -import { buildQuery } from "../utils" -import FulfillmentProviderService from "./fulfillment-provider" -import LineItemService from "./line-item" -import TotalsService from "./totals" - -type InjectedDependencies = { - manager: EntityManager - totalsService: TotalsService - shippingProfileService: ShippingProfileService - lineItemService: LineItemService - fulfillmentProviderService: FulfillmentProviderService - fulfillmentRepository: typeof FulfillmentRepository - trackingLinkRepository: typeof TrackingLinkRepository - lineItemRepository: typeof LineItemRepository - productVariantInventoryService: ProductVariantInventoryService -} - -/** - * Handles Fulfillments - */ -class FulfillmentService extends TransactionBaseService { - protected readonly totalsService_: TotalsService - protected readonly lineItemService_: LineItemService - protected readonly shippingProfileService_: ShippingProfileService - protected readonly fulfillmentProviderService_: FulfillmentProviderService - protected readonly fulfillmentRepository_: typeof FulfillmentRepository - protected readonly trackingLinkRepository_: typeof TrackingLinkRepository - protected readonly lineItemRepository_: typeof LineItemRepository - // eslint-disable-next-line max-len - protected readonly productVariantInventoryService_: ProductVariantInventoryService - - constructor({ - totalsService, - fulfillmentRepository, - trackingLinkRepository, - shippingProfileService, - lineItemService, - fulfillmentProviderService, - lineItemRepository, - productVariantInventoryService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.lineItemRepository_ = lineItemRepository - this.totalsService_ = totalsService - this.fulfillmentRepository_ = fulfillmentRepository - this.trackingLinkRepository_ = trackingLinkRepository - this.shippingProfileService_ = shippingProfileService - this.lineItemService_ = lineItemService - this.fulfillmentProviderService_ = fulfillmentProviderService - this.productVariantInventoryService_ = productVariantInventoryService - } - - partitionItems_( - shippingMethods: ShippingMethod[], - items: LineItem[] - ): FulfillmentItemPartition[] { - const partitioned: FulfillmentItemPartition[] = [] - - if (shippingMethods.length === 1) { - return [{ items, shipping_method: shippingMethods[0] }] - } - - // partition order items to their dedicated shipping method - for (const method of shippingMethods) { - const temp: FulfillmentItemPartition = { - shipping_method: method, - items: [], - } - - // for each method find the items in the order, that are associated - // with the profile on the current shipping method - const methodProfile = method.shipping_option.profile_id - - temp.items = items.filter(({ variant }) => { - return variant.product.profile_id === methodProfile - }) - partitioned.push(temp) - } - return partitioned - } - - /** - * Retrieves the order line items, given an array of items. - * @param order - the order to get line items from - * @param items - the items to get - * @return the line items generated by the transformer. - */ - async getFulfillmentItems_( - order: CreateFulfillmentOrder, - items: FulFillmentItemType[] - ): Promise<(LineItem | null)[]> { - const toReturn = await promiseAll( - items.map(async ({ item_id, quantity }) => { - const item = order.items.find((i) => i.id === item_id) - return this.validateFulfillmentLineItem_(item, quantity) - }) - ) - - return toReturn.filter((i) => !!i) - } - - /** - * Checks that a given quantity of a line item can be fulfilled. Fails if the - * fulfillable quantity is lower than the requested fulfillment quantity. - * Fulfillable quantity is calculated by subtracting the already fulfilled - * quantity from the quantity that was originally purchased. - * @param item - the line item to check has sufficient fulfillable - * quantity. - * @param quantity - the quantity that is requested to be fulfilled. - * @return a line item that has the requested fulfillment quantity - * set. - */ - validateFulfillmentLineItem_( - item: LineItem | undefined, - quantity: number - ): LineItem | null { - const lineItemRepo = this.activeManager_.withRepository( - this.lineItemRepository_ - ) - - if (!item) { - // This will in most cases be called by a webhook so to ensure that - // things go through smoothly in instances where extra items outside - // of Medusa are added we allow unknown items - return null - } - - if (quantity > item.quantity - item.fulfilled_quantity!) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot fulfill more items than have been purchased" - ) - } - return lineItemRepo.create({ - ...item, - quantity, - }) - } - - /** - * Retrieves a fulfillment by its id. - * @param fulfillmentId - the id of the fulfillment to retrieve - * @param config - optional values to include with fulfillmentRepository query - * @return the fulfillment - */ - async retrieve( - fulfillmentId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(fulfillmentId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"fulfillmentId" must be defined` - ) - } - - const fulfillmentRepository = this.activeManager_.withRepository( - this.fulfillmentRepository_ - ) - - const query = buildQuery({ id: fulfillmentId }, config) - - const fulfillment = await fulfillmentRepository.findOne(query) - - if (!fulfillment) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Fulfillment with id: ${fulfillmentId} was not found` - ) - } - return fulfillment - } - - /** - * Creates an order fulfillment - * If items needs to be fulfilled by different provider, we make - * sure to partition those items, and create fulfillment for - * those partitions. - * @param order - order to create fulfillment for - * @param itemsToFulfill - the items in the order to fulfill - * @param custom - potential custom values to add - * @return the created fulfillments - */ - async createFulfillment( - order: CreateFulfillmentOrder, - itemsToFulfill: FulFillmentItemType[], - custom: Partial = {} - ): Promise { - return await this.atomicPhase_(async (manager) => { - const fulfillmentRepository = manager.withRepository( - this.fulfillmentRepository_ - ) - - const lineItems = await this.getFulfillmentItems_(order, itemsToFulfill) - - const { shipping_methods } = order - - // partition order items to their dedicated shipping method - const fulfillments = this.partitionItems_( - shipping_methods, - lineItems as LineItem[] - ) - - const created = await promiseAll( - fulfillments.map(async ({ shipping_method, items }) => { - const ful = fulfillmentRepository.create({ - ...custom, - provider_id: shipping_method.shipping_option.provider_id, - items: items.map((i) => ({ item_id: i.id, quantity: i.quantity })), - data: {}, - }) - - const result = await fulfillmentRepository.save(ful) - - result.data = - await this.fulfillmentProviderService_.createFulfillment( - shipping_method, - items, - { ...order }, - { ...result } - ) - - return fulfillmentRepository.save(result) - }) - ) - - return created - }) - } - - /** - * Cancels a fulfillment with the fulfillment provider. Will decrement the - * fulfillment_quantity on the line items associated with the fulfillment. - * Throws if the fulfillment has already been shipped. - * @param fulfillmentOrId - the fulfillment object or id. - * @return the result of the save operation - * - */ - async cancelFulfillment( - fulfillmentOrId: Fulfillment | string - ): Promise { - return await this.atomicPhase_(async (manager) => { - const id = - typeof fulfillmentOrId === "string" - ? fulfillmentOrId - : fulfillmentOrId.id - - const fulfillment = await this.retrieve(id, { - relations: ["items", "claim_order", "swap"], - }) - - if (fulfillment.shipped_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `The fulfillment has already been shipped. Shipped fulfillments cannot be canceled` - ) - } - - await this.fulfillmentProviderService_.cancelFulfillment(fulfillment) - - fulfillment.canceled_at = new Date() - - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - - await promiseAll( - fulfillment.items.map(async (fItem) => { - const item = await lineItemServiceTx.retrieve(fItem.item_id) - const fulfilledQuantity = item.fulfilled_quantity! - fItem.quantity - await lineItemServiceTx.update(item.id, { - fulfilled_quantity: fulfilledQuantity, - }) - }) - ) - - const fulfillmentRepo = manager.withRepository( - this.fulfillmentRepository_ - ) - const canceled = await fulfillmentRepo.save(fulfillment) - return canceled - }) - } - - /** - * Creates a shipment by marking a fulfillment as shipped. Adds - * tracking links and potentially more metadata. - * @param fulfillmentId - the fulfillment to ship - * @param trackingLinks - tracking links for the shipment - * @param config - potential configuration settings, such as no_notification and metadata - * @return the shipped fulfillment - */ - async createShipment( - fulfillmentId: string, - trackingLinks?: { tracking_number: string }[], - config: CreateShipmentConfig = { - metadata: {}, - no_notification: undefined, - } - ): Promise { - const { metadata, no_notification } = config - - return await this.atomicPhase_(async (manager) => { - const fulfillmentRepository = manager.withRepository( - this.fulfillmentRepository_ - ) - const trackingLinkRepo = manager.withRepository( - this.trackingLinkRepository_ - ) - - const fulfillment = await this.retrieve(fulfillmentId, { - relations: ["items"], - }) - - if (fulfillment.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Fulfillment has been canceled" - ) - } - - const now = new Date() - fulfillment.shipped_at = now - - fulfillment.tracking_links = (trackingLinks || []).map((tl) => - trackingLinkRepo.create(tl) - ) - - if (isDefined(no_notification)) { - fulfillment.no_notification = no_notification - } - - fulfillment.metadata = { - ...fulfillment.metadata, - ...metadata, - } - - return await fulfillmentRepository.save(fulfillment) - }) - } -} - -export default FulfillmentService diff --git a/packages/medusa/src/services/gift-card.ts b/packages/medusa/src/services/gift-card.ts deleted file mode 100644 index a31f684eb0..0000000000 --- a/packages/medusa/src/services/gift-card.ts +++ /dev/null @@ -1,309 +0,0 @@ -import { isDefined, MedusaError } from "medusa-core-utils" -import randomize from "randomatic" -import { EntityManager } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { GiftCard, Region } from "../models" -import { GiftCardRepository } from "../repositories/gift-card" -import { GiftCardTransactionRepository } from "../repositories/gift-card-transaction" -import { FindConfig, QuerySelector, Selector } from "../types/common" -import { - CreateGiftCardInput, - CreateGiftCardTransactionInput, - UpdateGiftCardInput, -} from "../types/gift-card" -import { buildQuery, setMetadata } from "../utils" -import EventBusService from "./event-bus" -import RegionService from "./region" -import {selectorConstraintsToString} from "@medusajs/utils"; - -type InjectedDependencies = { - manager: EntityManager - giftCardRepository: typeof GiftCardRepository - giftCardTransactionRepository: typeof GiftCardTransactionRepository - regionService: RegionService - eventBusService: EventBusService -} -/** - * Provides layer to manipulate gift cards. - */ -class GiftCardService extends TransactionBaseService { - protected readonly giftCardRepository_: typeof GiftCardRepository - // eslint-disable-next-line max-len - protected readonly giftCardTransactionRepo_: typeof GiftCardTransactionRepository - protected readonly regionService_: RegionService - protected readonly eventBus_: EventBusService - - static Events = { - CREATED: "gift_card.created", - } - - constructor({ - giftCardRepository, - giftCardTransactionRepository, - regionService, - eventBusService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.giftCardRepository_ = giftCardRepository - this.giftCardTransactionRepo_ = giftCardTransactionRepository - this.regionService_ = regionService - this.eventBus_ = eventBusService - } - - /** - * Generates a 16 character gift card code - * @return the generated gift card code - */ - static generateCode(): string { - const code = [ - randomize("A0", 4), - randomize("A0", 4), - randomize("A0", 4), - randomize("A0", 4), - ].join("-") - - return code - } - - /** - * @param selector - the query object for find - * @param config - the configuration used to find the objects. contains relations, skip, and take. - * @return the result of the find operation - */ - async listAndCount( - selector: QuerySelector = {}, - config: FindConfig = { relations: [], skip: 0, take: 10 } - ): Promise<[GiftCard[], number]> { - const giftCardRepo = this.activeManager_.withRepository( - this.giftCardRepository_ - ) - - let q: string | undefined - if (isDefined(selector.q)) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - - return await giftCardRepo.listGiftCardsAndCount(query, q) - } - - /** - * @param selector - the query object for find - * @param config - the configuration used to find the objects. contains relations, skip, and take. - * @return the result of the find operation - */ - async list( - selector: QuerySelector = {}, - config: FindConfig = { relations: [], skip: 0, take: 10 } - ): Promise { - const [cards] = await this.listAndCount(selector, config) - return cards - } - - async createTransaction( - data: CreateGiftCardTransactionInput - ): Promise { - const gctRepo = this.activeManager_.withRepository( - this.giftCardTransactionRepo_ - ) - const created = gctRepo.create(data) - const saved = await gctRepo.save(created) - return saved.id - } - - /** - * Creates a gift card with provided data given that the data is validated. - * @param giftCard - the gift card data to create - * @return the result of the create operation - */ - async create(giftCard: CreateGiftCardInput): Promise { - return await this.atomicPhase_(async (manager) => { - const giftCardRepo = manager.withRepository(this.giftCardRepository_) - - // Will throw if region does not exist - const region = await this.regionService_ - .withTransaction(manager) - .retrieve(giftCard.region_id) - - const code = GiftCardService.generateCode() - const taxRate = GiftCardService.resolveTaxRate( - giftCard.tax_rate || null, - region - ) - const toCreate = { - code, - ...giftCard, - region_id: region.id, - tax_rate: taxRate, - } - - const created = giftCardRepo.create(toCreate) - const result = await giftCardRepo.save(created) - - await this.eventBus_ - .withTransaction(manager) - .emit(GiftCardService.Events.CREATED, { - id: result.id, - }) - - return result - }) - } - - /** - * The tax_rate of the giftcard can depend on whether regions tax gift cards, an input - * provided by the user or the tax rate. Based on these conditions, tax_rate changes. - * @return the tax rate for the gift card - */ - protected static resolveTaxRate( - giftCardTaxRate: number | null, - region: Region - ): number | null { - // A gift card is always associated with a region. If the region doesn't tax gift cards, - // return null - if (!region.gift_cards_taxable) { - return null - } - - // If a tax rate has been provided as an input from an external input, use that - // This would handle cases where gift cards are created as a part of an order where taxes better defined - // or to handle usecases outside of the opinions of the core. - if (giftCardTaxRate) { - return giftCardTaxRate - } - - // Outside the context of the taxRate input, it picks up the tax rate directly from the region - return region.tax_rate || null - } - - protected async retrieve_( - selector: Selector, - config: FindConfig = {} - ): Promise { - const giftCardRepo = this.activeManager_.withRepository( - this.giftCardRepository_ - ) - - const query = buildQuery(selector, config) - query.relationLoadStrategy = "query" - - const giftCard = await giftCardRepo.findOne(query) - - if (!giftCard) { - const selectorConstraints = selectorConstraintsToString(selector) - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Gift card with ${selectorConstraints} was not found` - ) - } - - return giftCard - } - - /** - * Gets a gift card by id. - * @param giftCardId - id of gift card to retrieve - * @param config - optional values to include with gift card query - * @return the gift card - */ - async retrieve( - giftCardId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(giftCardId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"giftCardId" must be defined` - ) - } - - return await this.retrieve_({ id: giftCardId }, config) - } - - async retrieveByCode( - code: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(code)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"code" must be defined` - ) - } - - return await this.retrieve_({ code }, config) - } - - /** - * Updates a giftCard. - * @param giftCardId - giftCard id of giftCard to update - * @param update - the data to update the giftCard with - * @return the result of the update operation - */ - async update( - giftCardId: string, - update: UpdateGiftCardInput - ): Promise { - return await this.atomicPhase_(async (manager) => { - const giftCardRepo = manager.withRepository(this.giftCardRepository_) - - const giftCard = await this.retrieve(giftCardId) - - const { region_id, metadata, balance, ...rest } = update - - if (region_id && region_id !== giftCard.region_id) { - const region = await this.regionService_ - .withTransaction(manager) - .retrieve(region_id) - giftCard.region_id = region.id - } - - if (metadata) { - giftCard.metadata = setMetadata(giftCard, metadata) - } - - if (isDefined(balance)) { - if (balance < 0 || giftCard.value < balance) { - throw new MedusaError( - MedusaError.Types.INVALID_ARGUMENT, - "new balance is invalid" - ) - } - - giftCard.balance = balance - } - - for (const [key, value] of Object.entries(rest)) { - giftCard[key] = value - } - - return await giftCardRepo.save(giftCard) - }) - } - - /** - * Deletes a gift card idempotently - * @param giftCardId - id of gift card to delete - * @return the result of the delete operation - */ - async delete(giftCardId: string): Promise { - const giftCardRepo = this.activeManager_.withRepository( - this.giftCardRepository_ - ) - - const giftCard = await giftCardRepo.findOne({ where: { id: giftCardId } }) - - if (!giftCard) { - return - } - - return await giftCardRepo.softRemove(giftCard) - } -} - -export default GiftCardService diff --git a/packages/medusa/src/services/index.ts b/packages/medusa/src/services/index.ts index b9430eaf76..e4395133dc 100644 --- a/packages/medusa/src/services/index.ts +++ b/packages/medusa/src/services/index.ts @@ -1,58 +1,5 @@ -export { default as AnalyticsConfigService } from "./analytics-config" -export { default as AuthService } from "./auth" -export { default as BatchJobService } from "./batch-job" -export { default as CartService } from "./cart" -export { default as ClaimService } from "./claim" -export { default as ClaimItemService } from "./claim-item" -export { default as CurrencyService } from "./currency" -export { default as CustomShippingOptionService } from "./custom-shipping-option" -export { default as CustomerService } from "./customer" -export { default as CustomerGroupService } from "./customer-group" -export { default as DiscountService } from "./discount" -export { default as DiscountConditionService } from "./discount-condition" -export { default as DraftOrderService } from "./draft-order" export { default as EventBusService } from "./event-bus" -export { default as FulfillmentService } from "./fulfillment" -export { default as FulfillmentProviderService } from "./fulfillment-provider" -export { default as GiftCardService } from "./gift-card" -export { default as IdempotencyKeyService } from "./idempotency-key" -export { default as LineItemService } from "./line-item" -export { default as LineItemAdjustmentService } from "./line-item-adjustment" export { default as MiddlewareService } from "./middleware" -export { default as NewTotalsService } from "./new-totals" -export { default as NoteService } from "./note" -export { default as NotificationService } from "./notification" -export { default as OauthService } from "./oauth" -export { default as OrderService } from "./order" -export { default as OrderEditService } from "./order-edit" -export { default as OrderEditItemChangeService } from "./order-edit-item-change" -export { default as PaymentService } from "./payment" -export { default as PaymentCollectionService } from "./payment-collection" -export { default as PaymentProviderService } from "./payment-provider" -export { default as PriceListService } from "./price-list" -export { default as PricingService } from "./pricing" -export { default as ProductService } from "./product" -export { default as ProductCategoryService } from "./product-category" -export { default as ProductCollectionService } from "./product-collection" -export { default as ProductTypeService } from "./product-type" -export { default as ProductVariantService } from "./product-variant" -export { default as ProductVariantInventoryService } from "./product-variant-inventory" -export { default as RegionService } from "./region" -export { default as ReturnService } from "./return" -export { default as ReturnReasonService } from "./return-reason" -export { default as SalesChannelService } from "./sales-channel" -export { default as SalesChannelInventoryService } from "./sales-channel-inventory" -export { default as SalesChannelLocationService } from "./sales-channel-location" -export { default as SearchService } from "./search" -export { default as ShippingOptionService } from "./shipping-option" -export { default as ShippingProfileService } from "./shipping-profile" export { default as StagedJobService } from "./staged-job" -export { default as StoreService } from "./store" -export { default as StrategyResolverService } from "./strategy-resolver" -export { default as SwapService } from "./swap" -export { default as SystemPaymentProviderService } from "./system-payment-provider" -export { default as TaxProviderService } from "./tax-provider" -export { default as TaxRateService } from "./tax-rate" -export { default as TokenService } from "./token" -export { default as TotalsService } from "./totals" -export { default as UserService } from "./user" +export { default as IdempotencyKeyService } from "./idempotency-key" +export { default as JobSchedulerService } from "./job-scheduler" diff --git a/packages/medusa/src/services/invite.ts b/packages/medusa/src/services/invite.ts deleted file mode 100644 index 3cfb556aa4..0000000000 --- a/packages/medusa/src/services/invite.ts +++ /dev/null @@ -1,275 +0,0 @@ -import jwt, { JwtPayload } from "jsonwebtoken" -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { UserService } from "." -import { User } from ".." -import { TransactionBaseService } from "../interfaces" -import { UserRoles } from "../models/user" -import { InviteRepository } from "../repositories/invite" -import { UserRepository } from "../repositories/user" -import { ConfigModule } from "../types/global" -import { ListInvite } from "../types/invites" -import { buildQuery } from "../utils" -import EventBusService from "./event-bus" - -// 7 days -const DEFAULT_VALID_DURATION = 1000 * 60 * 60 * 24 * 7 - -type InviteServiceProps = { - manager: EntityManager - userService: UserService - userRepository: typeof UserRepository - inviteRepository: typeof InviteRepository - eventBusService: EventBusService -} - -class InviteService extends TransactionBaseService { - static Events = { - CREATED: "invite.created", - } - - protected readonly userService_: UserService - protected readonly userRepo_: typeof UserRepository - protected readonly inviteRepository_: typeof InviteRepository - protected readonly eventBus_: EventBusService - - protected readonly configModule_: ConfigModule - - constructor( - { - userService, - userRepository, - inviteRepository, - eventBusService, - }: InviteServiceProps, - configModule: ConfigModule - ) { - // @ts-ignore - // eslint-disable-next-line prefer-rest-params - super(...arguments) - - this.configModule_ = configModule - this.userService_ = userService - this.userRepo_ = userRepository - this.inviteRepository_ = inviteRepository - this.eventBus_ = eventBusService - } - - generateToken(data): string { - const { jwt_secret } = this.configModule_.projectConfig - if (jwt_secret) { - return jwt.sign(data, jwt_secret) - } - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Please configure jwt_secret" - ) - } - - async list(selector, config = {}): Promise { - const inviteRepo = this.activeManager_.withRepository(InviteRepository) - - const query = buildQuery(selector, config) - - return await inviteRepo.find(query) - } - - /** - * Updates an account_user. - * @param user - user emails - * @param role - role to assign to the user - * @param validDuration - role to assign to the user - * @return the result of create - */ - async create( - user: string, - role: UserRoles, - validDuration = DEFAULT_VALID_DURATION - ): Promise { - return await this.atomicPhase_(async (manager) => { - const inviteRepository = - this.activeManager_.withRepository(InviteRepository) - - const userRepo = this.activeManager_.withRepository(UserRepository) - - const userEntity = await userRepo.findOne({ - where: { email: user }, - }) - - if (userEntity) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Can't invite a user with an existing account" - ) - } - - let invite = await inviteRepository.findOne({ - where: { user_email: user }, - }) - // if user is trying to send another invite for the same account + email, but with a different role - // then change the role on the invite as long as the invite has not been accepted yet - if (invite && !invite.accepted && invite.role !== role) { - invite.role = role - - invite = await inviteRepository.save(invite) - } else if (!invite) { - // if no invite is found, create a new one - const created = inviteRepository.create({ - role, - token: "", - user_email: user, - }) - - invite = await inviteRepository.save(created) - } - - invite.token = this.generateToken({ - invite_id: invite.id, - role, - user_email: user, - }) - - invite.expires_at = new Date() - invite.expires_at.setMilliseconds( - invite.expires_at.getMilliseconds() + validDuration - ) - - invite = await inviteRepository.save(invite) - - await this.eventBus_ - .withTransaction(manager) - .emit(InviteService.Events.CREATED, { - id: invite.id, - token: invite.token, - user_email: invite.user_email, - }) - }) - } - - /** - * Deletes an invite from a given user id. - * @param inviteId - the id of the invite to delete. Must be - * castable as an ObjectId - * @return the result of the delete operation. - */ - async delete(inviteId): Promise { - return await this.atomicPhase_(async (manager) => { - const inviteRepo: typeof InviteRepository = - manager.withRepository(InviteRepository) - - // Should not fail, if invite does not exist, since delete is idempotent - const invite = await inviteRepo.findOne({ where: { id: inviteId } }) - - if (!invite) { - return - } - - await inviteRepo.delete({ id: invite.id }) - }) - } - - async accept(token, user_): Promise { - let decoded - try { - decoded = this.verifyToken(token) - } catch (err) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Token is not valid" - ) - } - - const { invite_id, user_email } = decoded - - return await this.atomicPhase_(async (m) => { - const userRepo = m.withRepository(this.userRepo_) - const inviteRepo: typeof InviteRepository = m.withRepository( - this.inviteRepository_ - ) - - const invite = await inviteRepo.findOne({ where: { id: invite_id } }) - - if ( - !invite || - invite?.user_email !== user_email || - new Date() > invite.expires_at - ) { - throw new MedusaError(MedusaError.Types.INVALID_DATA, `Invalid invite`) - } - - const exists = await userRepo.findOne({ - where: { email: user_email.toLowerCase() }, - select: ["id"], - }) - - if (exists) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "User already joined" - ) - } - - // use the email of the user who actually accepted the invite - const user = await this.userService_.withTransaction(m).create( - { - email: invite.user_email, - role: invite.role, - first_name: user_.first_name, - last_name: user_.last_name, - }, - user_.password - ) - - await inviteRepo.delete({ id: invite.id }) - - return user - }, "SERIALIZABLE") - } - - verifyToken(token): JwtPayload | string { - const { jwt_secret } = this.configModule_.projectConfig - - if (jwt_secret) { - return jwt.verify(token, jwt_secret) - } - - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Please configure jwt_secret" - ) - } - - async resend(id): Promise { - const inviteRepo = this.activeManager_.withRepository(InviteRepository) - - const invite = await inviteRepo.findOne({ where: { id } }) - - if (!invite) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Invite doesn't exist` - ) - } - - invite.token = this.generateToken({ - invite_id: invite.id, - role: invite.role, - user_email: invite.user_email, - }) - - invite.expires_at = new Date() - invite.expires_at.setDate(invite.expires_at.getDate() + 7) - - await inviteRepo.save(invite) - - await this.eventBus_ - .withTransaction(this.activeManager_) - .emit(InviteService.Events.CREATED, { - id: invite.id, - token: invite.token, - user_email: invite.user_email, - }) - } -} - -export default InviteService diff --git a/packages/medusa/src/services/line-item-adjustment.ts b/packages/medusa/src/services/line-item-adjustment.ts deleted file mode 100644 index fa19745d45..0000000000 --- a/packages/medusa/src/services/line-item-adjustment.ts +++ /dev/null @@ -1,309 +0,0 @@ -import { promiseAll } from "@medusajs/utils" -import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager, FindOperator, In } from "typeorm" - -import { TransactionBaseService } from "../interfaces" -import { Cart, DiscountRuleType, LineItem, LineItemAdjustment } from "../models" -import { LineItemAdjustmentRepository } from "../repositories/line-item-adjustment" -import { FindConfig } from "../types/common" -import { FilterableLineItemAdjustmentProps } from "../types/line-item-adjustment" -import { CalculationContextData } from "../types/totals" -import { buildQuery, setMetadata } from "../utils" -import DiscountService from "./discount" - -type LineItemAdjustmentServiceProps = { - manager: EntityManager - lineItemAdjustmentRepository: typeof LineItemAdjustmentRepository - discountService: DiscountService -} - -type AdjustmentContext = { - variant: { product_id: string } -} - -type GeneratedAdjustment = { - amount: number - discount_id: string - description: string -} - -/** - * Provides layer to manipulate line item adjustments. - */ -class LineItemAdjustmentService extends TransactionBaseService { - private readonly lineItemAdjustmentRepo_: typeof LineItemAdjustmentRepository - private readonly discountService: DiscountService - - constructor({ - lineItemAdjustmentRepository, - discountService, - }: LineItemAdjustmentServiceProps) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.lineItemAdjustmentRepo_ = lineItemAdjustmentRepository - this.discountService = discountService - } - - /** - * Retrieves a line item adjustment by id. - * @param lineItemAdjustmentId - the id of the line item adjustment to retrieve - * @param config - the config to retrieve the line item adjustment by - * @return the line item adjustment. - */ - async retrieve( - lineItemAdjustmentId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(lineItemAdjustmentId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"lineItemAdjustmentId" must be defined` - ) - } - - const lineItemAdjustmentRepo = this.activeManager_.withRepository( - this.lineItemAdjustmentRepo_ - ) - - const query = buildQuery({ id: lineItemAdjustmentId }, config) - const lineItemAdjustment = await lineItemAdjustmentRepo.findOne(query) - - if (!lineItemAdjustment) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Line item adjustment with id: ${lineItemAdjustmentId} was not found` - ) - } - - return lineItemAdjustment - } - - /** - * Creates a line item adjustment - * @param data - the line item adjustment to create - * @return line item adjustment - */ - async create(data: Partial): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const lineItemAdjustmentRepo = manager.withRepository( - this.lineItemAdjustmentRepo_ - ) - - const lineItemAdjustment = lineItemAdjustmentRepo.create(data) - - return await lineItemAdjustmentRepo.save(lineItemAdjustment) - }) - } - - /** - * Creates a line item adjustment - * @param id - the line item adjustment id to update - * @param data - the line item adjustment to create - * @return line item adjustment - */ - async update( - id: string, - data: Partial - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const lineItemAdjustmentRepo = manager.withRepository( - this.lineItemAdjustmentRepo_ - ) - - const lineItemAdjustment = await this.retrieve(id) - - const { metadata, ...rest } = data - - if (metadata) { - lineItemAdjustment.metadata = setMetadata(lineItemAdjustment, metadata) - } - - for (const [key, value] of Object.entries(rest)) { - lineItemAdjustment[key] = value - } - - const result = await lineItemAdjustmentRepo.save(lineItemAdjustment) - return result - }) - } - - /** - * Lists line item adjustments - * @param selector - the query object for find - * @param config - the config to be used for find - * @return the result of the find operation - */ - async list( - selector: FilterableLineItemAdjustmentProps = {}, - config: FindConfig = { skip: 0, take: 20 } - ): Promise { - const lineItemAdjustmentRepo = this.activeManager_.withRepository( - this.lineItemAdjustmentRepo_ - ) - - const query = buildQuery(selector, config) - return await lineItemAdjustmentRepo.find(query) - } - - /** - * Deletes line item adjustments matching a selector - * @param selectorOrIds - the query object for find or the line item adjustment id - * @return the result of the delete operation - */ - async delete( - selectorOrIds: - | string - | string[] - | (FilterableLineItemAdjustmentProps & { - discount_id?: FindOperator - }) - ): Promise { - return this.atomicPhase_(async (manager) => { - const lineItemAdjustmentRepo = manager.withRepository( - this.lineItemAdjustmentRepo_ - ) - - if (typeof selectorOrIds === "string" || Array.isArray(selectorOrIds)) { - const ids = - typeof selectorOrIds === "string" ? [selectorOrIds] : selectorOrIds - await lineItemAdjustmentRepo.delete({ id: In(ids) }) - return - } - - const query = buildQuery(selectorOrIds) - - const lineItemAdjustments = await lineItemAdjustmentRepo.find(query) - - await lineItemAdjustmentRepo.remove(lineItemAdjustments) - }) - } - - /** - * Creates adjustment for a line item - * @param calculationContextData - the calculationContextData object holding discounts - * @param generatedLineItem - the line item for which a line item adjustment might be created - * @param context - the line item for which a line item adjustment might be created - * @return a line item adjustment or undefined if no adjustment was created - */ - async generateAdjustments( - calculationContextData: CalculationContextData, - generatedLineItem: LineItem, - context: AdjustmentContext - ): Promise { - const lineItem = { - ...generatedLineItem, - } as LineItem - - return this.atomicPhase_(async (manager) => { - // if lineItem should not be discounted - // or lineItem is a return line item - // or the cart does not have any discounts - // then do nothing - if ( - !lineItem.allow_discounts || - lineItem.is_return || - !calculationContextData?.discounts?.length - ) { - return [] - } - - const [discount] = calculationContextData.discounts.filter( - (d) => d.rule.type !== DiscountRuleType.FREE_SHIPPING - ) - - // if no discount is applied to the cart then return - if (!discount) { - return [] - } - - const discountServiceTx = this.discountService.withTransaction(manager) - - const lineItemProduct = context.variant.product_id - - const isValid = await discountServiceTx.validateDiscountForProduct( - discount.rule_id, - lineItemProduct - ) - - // if discount is not valid for line item, then do nothing - if (!isValid) { - return [] - } - - // In case of a generated line item the id is not available, it is mocked instead to be used for totals calculations - lineItem.id = lineItem.id ?? new Date().getTime() - const amount = await discountServiceTx.calculateDiscountForLineItem( - discount.id, - lineItem, - calculationContextData - ) - - // if discounted amount is 0, then do nothing - if (amount === 0) { - return [] - } - - return [ - { - amount, - discount_id: discount.id, - description: "discount", - }, - ] - }) - } - - /** - * Creates adjustment for a line item - * @param cart - the cart object holding discounts - * @param lineItem - the line item for which a line item adjustment might be created - * @return a line item adjustment or undefined if no adjustment was created - */ - async createAdjustmentForLineItem( - cart: Cart, - lineItem: LineItem - ): Promise { - const adjustments = await this.generateAdjustments(cart, lineItem, { - variant: lineItem.variant, - }) - - const createdAdjustments: LineItemAdjustment[] = [] - for (const adjustment of adjustments) { - const created = await this.create({ - item_id: lineItem.id, - ...adjustment, - }) - - createdAdjustments.push(created) - } - - return createdAdjustments - } - - /** - * Creates adjustment for a line item - * @param cart - the cart object holding discounts - * @param lineItem - the line item for which a line item adjustment might be created - * @return if a lineItem was given, returns a line item adjustment or undefined if no adjustment was created - * otherwise returns an array of line item adjustments for each line item in the cart - */ - async createAdjustments( - cart: Cart, - lineItem?: LineItem - ): Promise { - if (lineItem) { - return await this.createAdjustmentForLineItem(cart, lineItem) - } - - if (!cart.items) { - return [] - } - - return await promiseAll( - cart.items.map(async (li) => this.createAdjustmentForLineItem(cart, li)) - ) - } -} - -export default LineItemAdjustmentService diff --git a/packages/medusa/src/services/line-item.ts b/packages/medusa/src/services/line-item.ts deleted file mode 100644 index d70fb6d101..0000000000 --- a/packages/medusa/src/services/line-item.ts +++ /dev/null @@ -1,675 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { EntityManager, In } from "typeorm" -import { DeepPartial } from "typeorm/common/DeepPartial" - -import { - FlagRouter, - MedusaV2Flag, - selectorConstraintsToString, -} from "@medusajs/utils" -import { TransactionBaseService } from "../interfaces" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { - LineItem, - LineItemAdjustment, - LineItemTaxLine, - ProductVariant, -} from "../models" -import { CartRepository } from "../repositories/cart" -import { LineItemRepository } from "../repositories/line-item" -import { LineItemTaxLineRepository } from "../repositories/line-item-tax-line" -import { FindConfig, Selector } from "../types/common" -import { GenerateInputData, GenerateLineItemContext } from "../types/line-item" -import { ProductVariantPricing } from "../types/pricing" -import { buildQuery, isString, setMetadata } from "../utils" -import { - PricingService, - ProductService, - ProductVariantService, - RegionService, - TaxProviderService, -} from "./index" -import LineItemAdjustmentService from "./line-item-adjustment" - -type InjectedDependencies = { - manager: EntityManager - lineItemRepository: typeof LineItemRepository - lineItemTaxLineRepository: typeof LineItemTaxLineRepository - cartRepository: typeof CartRepository - productVariantService: ProductVariantService - productService: ProductService - pricingService: PricingService - regionService: RegionService - lineItemAdjustmentService: LineItemAdjustmentService - taxProviderService: TaxProviderService - featureFlagRouter: FlagRouter -} - -class LineItemService extends TransactionBaseService { - protected readonly lineItemRepository_: typeof LineItemRepository - protected readonly itemTaxLineRepo_: typeof LineItemTaxLineRepository - protected readonly cartRepository_: typeof CartRepository - protected readonly productVariantService_: ProductVariantService - protected readonly productService_: ProductService - protected readonly pricingService_: PricingService - protected readonly regionService_: RegionService - protected readonly featureFlagRouter_: FlagRouter - protected readonly lineItemAdjustmentService_: LineItemAdjustmentService - protected readonly taxProviderService_: TaxProviderService - - constructor({ - lineItemRepository, - lineItemTaxLineRepository, - productVariantService, - productService, - pricingService, - regionService, - cartRepository, - lineItemAdjustmentService, - taxProviderService, - featureFlagRouter, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.lineItemRepository_ = lineItemRepository - this.itemTaxLineRepo_ = lineItemTaxLineRepository - this.productVariantService_ = productVariantService - this.productService_ = productService - this.pricingService_ = pricingService - this.regionService_ = regionService - this.cartRepository_ = cartRepository - this.lineItemAdjustmentService_ = lineItemAdjustmentService - this.taxProviderService_ = taxProviderService - this.featureFlagRouter_ = featureFlagRouter - } - - async list( - selector: Selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise { - const lineItemRepo = this.activeManager_.withRepository( - this.lineItemRepository_ - ) - const query = buildQuery(selector, config) - return await lineItemRepo.find(query) - } - - /** - * Retrieves a line item by its id. - * @param id - the id of the line item to retrieve - * @param config - the config to be used at query building - * @return the line item - */ - async retrieve(id: string, config = {}): Promise { - const lineItemRepository = this.activeManager_.withRepository( - this.lineItemRepository_ - ) - - const query = buildQuery({ id }, config) - - const lineItem = await lineItemRepository.findOne(query) - - if (!lineItem) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Line item with ${id} was not found` - ) - } - - return lineItem - } - - /** - * Creates return line items for a given cart based on the return items in a - * return. - * @param returnId - the id to generate return items from. - * @param cartId - the cart to assign the return line items to. - * @return the created line items - */ - async createReturnLines( - returnId: string, - cartId: string - ): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const lineItemRepo = transactionManager.withRepository( - this.lineItemRepository_ - ) - - const itemTaxLineRepo = transactionManager.withRepository( - this.itemTaxLineRepo_ - ) - - const returnLineItems = await lineItemRepo - .findByReturn(returnId) - .then((lineItems) => { - return lineItems.map((lineItem) => - lineItemRepo.create({ - cart_id: cartId, - thumbnail: lineItem.thumbnail, - is_return: true, - title: lineItem.title, - variant_id: lineItem.variant_id, - unit_price: -1 * lineItem.unit_price, - quantity: lineItem.return_item.quantity, - allow_discounts: lineItem.allow_discounts, - includes_tax: !!lineItem.includes_tax, - tax_lines: lineItem.tax_lines.map((taxLine) => { - return itemTaxLineRepo.create({ - name: taxLine.name, - code: taxLine.code, - rate: taxLine.rate, - metadata: taxLine.metadata, - }) - }), - metadata: lineItem.metadata, - adjustments: lineItem.adjustments.map((adjustment) => { - return { - amount: -1 * adjustment.amount, - description: adjustment.description, - discount_id: adjustment.discount_id, - metadata: adjustment.metadata, - } - }), - }) - ) - }) - - return await lineItemRepo.save(returnLineItems) - } - ) - } - - /** - * Generate a single or multiple line item without persisting the data into the db - * @param variantIdOrData - * @param regionIdOrContext - * @param quantity - * @param context - */ - async generate< - T = string | GenerateInputData | GenerateInputData[], - TResult = T extends string - ? LineItem - : T extends LineItem - ? LineItem - : LineItem[] - >( - variantIdOrData: T, - regionIdOrContext: T extends string ? string : GenerateLineItemContext, - quantity?: number, - context: GenerateLineItemContext = {} - ): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - this.validateGenerateArguments( - variantIdOrData, - regionIdOrContext, - quantity - ) - - // Resolve data - const data = isString(variantIdOrData) - ? { - variantId: variantIdOrData, - quantity: quantity as number, - } - : variantIdOrData - - const resolvedContext = isString(variantIdOrData) - ? context - : (regionIdOrContext as GenerateLineItemContext) - - const regionId = ( - isString(variantIdOrData) - ? regionIdOrContext - : resolvedContext.region_id - ) as string - - const resolvedData = ( - Array.isArray(data) ? data : [data] - ) as GenerateInputData[] - - const resolvedDataMap = new Map( - resolvedData.map((d) => [d.variantId, d]) - ) - - // Retrieve variants - const variants = await this.productVariantService_.list( - { - id: resolvedData.map((d) => d.variantId), - }, - { - relations: ["product"], - } - ) - - // Validate that all variants has been found - const inputDataVariantId = new Set(resolvedData.map((d) => d.variantId)) - const foundVariants = new Set(variants.map((v) => v.id)) - const notFoundVariants = new Set( - [...inputDataVariantId].filter((x) => !foundVariants.has(x)) - ) - - if (notFoundVariants.size) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Unable to generate the line items, some variant has not been found: ${[ - ...notFoundVariants, - ].join(", ")}` - ) - } - - // Prepare data to retrieve variant pricing - const variantsMap = new Map() - const variantsToCalculatePricingFor: { - variantId: string - quantity: number - }[] = [] - - for (const variant of variants) { - variantsMap.set(variant.id, variant) - - const variantResolvedData = resolvedDataMap.get(variant.id) - if ( - resolvedContext.unit_price == null && - variantResolvedData?.unit_price == null - ) { - variantsToCalculatePricingFor.push({ - variantId: variant.id, - quantity: variantResolvedData!.quantity, - }) - } - } - - let variantsPricing = {} - - if (variantsToCalculatePricingFor.length) { - variantsPricing = await this.pricingService_ - .withTransaction(transactionManager) - .getProductVariantsPricing(variantsToCalculatePricingFor, { - region_id: regionId, - customer_id: context?.customer_id, - include_discount_prices: true, - }) - } - - // Generate line items - const generatedItems: LineItem[] = [] - - for (const variantData of resolvedData) { - const variant = variantsMap.get( - variantData.variantId - ) as ProductVariant - const variantPricing = variantsPricing[variantData.variantId] - - const lineItem = await this.generateLineItem( - variant, - variantData.quantity, - { - ...resolvedContext, - unit_price: variantData.unit_price ?? resolvedContext.unit_price, - metadata: variantData.metadata ?? resolvedContext.metadata, - variantPricing, - } - ) - - if (resolvedContext.cart) { - const adjustments = await this.lineItemAdjustmentService_ - .withTransaction(transactionManager) - .generateAdjustments(resolvedContext.cart, lineItem, { variant }) - lineItem.adjustments = - adjustments as unknown as LineItemAdjustment[] - } - - generatedItems.push(lineItem) - } - - return (Array.isArray(data) - ? generatedItems - : generatedItems[0]) as unknown as TResult - } - ) - } - - protected async generateLineItem( - variant: { - id: string - title: string - product_id: string - product: { - title: string - thumbnail: string | null - discountable: boolean - is_giftcard: boolean - } - }, - quantity: number, - context: GenerateLineItemContext & { - variantPricing: ProductVariantPricing - } - ): Promise { - let unit_price = Number(context.unit_price) < 0 ? 0 : context.unit_price - let unitPriceIncludesTax = false - let shouldMerge = false - - if (context.unit_price == null) { - shouldMerge = true - - unitPriceIncludesTax = - !!context.variantPricing?.calculated_price_includes_tax - unit_price = context.variantPricing?.calculated_price ?? undefined - } - - if (unit_price == null) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Cannot generate line item for variant "${ - variant.title ?? variant.product.title ?? variant.id - }" without a price` - ) - } - - const rawLineItem: Partial = { - unit_price: unit_price, - title: variant.product.title, - description: variant.title, - thumbnail: variant.product.thumbnail, - variant_id: variant.id, - quantity: quantity || 1, - allow_discounts: variant.product.discountable, - is_giftcard: variant.product.is_giftcard, - metadata: context?.metadata || {}, - should_merge: shouldMerge, - } - - if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) { - rawLineItem.product_id = variant.product_id - } - - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) - ) { - rawLineItem.includes_tax = unitPriceIncludesTax - } - - rawLineItem.order_edit_id = context.order_edit_id || null - - const lineItemRepo = this.activeManager_.withRepository( - this.lineItemRepository_ - ) - - const lineItem = lineItemRepo.create(rawLineItem) - lineItem.variant = variant as ProductVariant - - return lineItem - } - - /** - * Create a line item - * @param data - the line item object to create - * @return the created line item - */ - async create< - T = LineItem | LineItem[], - TResult = T extends LineItem[] ? LineItem[] : LineItem - >(data: T): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const lineItemRepository = transactionManager.withRepository( - this.lineItemRepository_ - ) - - const data_ = ( - Array.isArray(data) ? data : [data] - ) as DeepPartial[] - - const items = lineItemRepository.create(data_) - const lineItems = await lineItemRepository.save(items) - - return (Array.isArray(data) - ? lineItems - : lineItems[0]) as unknown as TResult - } - ) - } - - /** - * Updates a line item - * @param idOrSelector - the id or selector of the line item(s) to update - * @param data - the properties to update the line item(s) - * @return the updated line item(s) - */ - async update( - idOrSelector: string | Selector, - data: Partial - ): Promise { - const { metadata, ...rest } = data - - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const lineItemRepository = transactionManager.withRepository( - this.lineItemRepository_ - ) - - const selector = - typeof idOrSelector === "string" ? { id: idOrSelector } : idOrSelector - - let lineItems = await this.list(selector) - - if (!lineItems.length) { - const selectorConstraints = selectorConstraintsToString(selector) - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Line item with ${selectorConstraints} was not found` - ) - } - - lineItems = lineItems.map((item) => { - item.metadata = metadata ? setMetadata(item, metadata) : item.metadata - return Object.assign(item, rest) - }) - - return await lineItemRepository.save(lineItems) - } - ) - } - - async delete(ids: string[]): Promise - async delete(id: string): Promise - - /** - * Deletes a line item. - * @param id - the id of the line item to delete - * @return the result of the delete operation - */ - async delete(id: string | string[]): Promise { - const ids = Array.isArray(id) ? id : [id] - - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const lineItemRepository = transactionManager.withRepository( - this.lineItemRepository_ - ) - - const lineItems = await lineItemRepository.find({ - where: { id: In(ids) }, - }) - - if (!lineItems?.length) { - return Array.isArray(id) ? [] : void 0 - } - - const removedItems = await lineItemRepository.remove(lineItems) - return Array.isArray(id) ? removedItems : removedItems[0] - } - ) - } - - /** - * @deprecated no the cascade on the entity takes care of it - * Deletes a line item with the tax lines. - * @param id - the id of the line item to delete - * @return the result of the delete operation - */ - async deleteWithTaxLines(id: string): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - await this.taxProviderService_ - .withTransaction(transactionManager) - .clearLineItemsTaxLines([id]) - - return await this.delete(id) - } - ) - } - - /** - * Create a line item tax line. - * @param args - tax line partial passed to the repo create method - * @return a new line item tax line - */ - public createTaxLine(args: DeepPartial): LineItemTaxLine { - const itemTaxLineRepo = this.activeManager_.withRepository( - this.itemTaxLineRepo_ - ) - - return itemTaxLineRepo.create(args) - } - - async cloneTo( - ids: string | string[], - data: DeepPartial = {}, - options: { setOriginalLineItemId?: boolean } = { - setOriginalLineItemId: true, - } - ): Promise { - ids = typeof ids === "string" ? [ids] : ids - return await this.atomicPhase_(async (manager) => { - let lineItems: DeepPartial[] = await this.list( - { - id: In(ids as string[]), - }, - { - relations: ["tax_lines", "adjustments"], - } - ) - - const lineItemRepository = manager.withRepository( - this.lineItemRepository_ - ) - - const { - order_id, - swap_id, - claim_order_id, - cart_id, - order_edit_id, - ...lineItemData - } = data - - if ( - !order_id && - !swap_id && - !claim_order_id && - !cart_id && - !order_edit_id - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Unable to clone a line item that is not attached to at least one of: order_edit, order, swap, claim or cart." - ) - } - - lineItems = lineItems.map((item) => ({ - ...item, - ...lineItemData, - id: undefined, - order_id, - swap_id, - claim_order_id, - cart_id, - order_edit_id, - original_item_id: options?.setOriginalLineItemId ? item.id : undefined, - tax_lines: item.tax_lines?.map((tax_line) => ({ - ...tax_line, - id: undefined, - item_id: undefined, - })), - adjustments: item.adjustments?.map((adj) => ({ - ...adj, - id: undefined, - item_id: undefined, - })), - })) - - const clonedLineItemEntities = lineItemRepository.create(lineItems) - return await lineItemRepository.save(clonedLineItemEntities) - }) - } - - protected validateGenerateArguments< - T = string | GenerateInputData | GenerateInputData[], - TResult = T extends string - ? LineItem - : T extends LineItem - ? LineItem - : LineItem[] - >( - variantIdOrData: string | T, - regionIdOrContext: T extends string ? string : GenerateLineItemContext, - quantity?: number - ): void | never { - const errorMessage = - "Unable to generate the line item because one or more required argument(s) are missing" - - if (isString(variantIdOrData)) { - if (!quantity || !regionIdOrContext || !isString(regionIdOrContext)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `${errorMessage}. Ensure quantity, regionId, and variantId are passed` - ) - } - - if (!variantIdOrData) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `${errorMessage}. Ensure variant id is passed` - ) - } - return - } - - const resolvedContext = regionIdOrContext as GenerateLineItemContext - - if (!resolvedContext?.region_id) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `${errorMessage}. Ensure region or region_id are passed` - ) - } - - const variantsData = Array.isArray(variantIdOrData) - ? variantIdOrData - : [variantIdOrData] - - const hasMissingVariantId = variantsData.some((d) => !d?.variantId) - - if (hasMissingVariantId) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `${errorMessage}. Ensure a variant id is passed for each variant` - ) - } - } -} - -export default LineItemService diff --git a/packages/medusa/src/services/new-totals.ts b/packages/medusa/src/services/new-totals.ts deleted file mode 100644 index 9df49230b0..0000000000 --- a/packages/medusa/src/services/new-totals.ts +++ /dev/null @@ -1,770 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { - ITaxCalculationStrategy, - TaxCalculationContext, - TransactionBaseService, -} from "../interfaces" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { - Discount, - DiscountRuleType, - GiftCard, - LineItem, - LineItemTaxLine, - Region, - ShippingMethod, - ShippingMethodTaxLine, -} from "../models" -import { LineAllocationsMap } from "../types/totals" -import { calculatePriceTaxAmount } from "../utils" -import { TaxProviderService } from "./index" - -type LineItemTotals = { - unit_price: number - quantity: number - subtotal: number - tax_total: number - total: number - original_total: number - original_tax_total: number - tax_lines: LineItemTaxLine[] - discount_total: number - - raw_discount_total: number -} - -type GiftCardTransaction = { - tax_rate: number | null - is_taxable: boolean | null - amount: number - gift_card: GiftCard -} - -type ShippingMethodTotals = { - price: number - tax_total: number - total: number - subtotal: number - original_total: number - original_tax_total: number - tax_lines: ShippingMethodTaxLine[] -} - -type InjectedDependencies = { - manager: EntityManager - taxProviderService: TaxProviderService - taxCalculationStrategy: ITaxCalculationStrategy - featureFlagRouter: FlagRouter -} - -export default class NewTotalsService extends TransactionBaseService { - protected readonly taxProviderService_: TaxProviderService - protected readonly featureFlagRouter_: FlagRouter - protected readonly taxCalculationStrategy_: ITaxCalculationStrategy - - constructor({ - taxProviderService, - featureFlagRouter, - taxCalculationStrategy, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.taxProviderService_ = taxProviderService - this.featureFlagRouter_ = featureFlagRouter - this.taxCalculationStrategy_ = taxCalculationStrategy - } - - /** - * Calculate and return the items totals for either the legacy calculation or the new calculation - * @param items - * @param param1 - */ - async getLineItemTotals( - items: LineItem | LineItem[], - { - includeTax, - calculationContext, - taxRate, - }: { - includeTax?: boolean - calculationContext: TaxCalculationContext - taxRate?: number | null - } - ): Promise<{ [lineItemId: string]: LineItemTotals }> { - items = Array.isArray(items) ? items : [items] - - let lineItemsTaxLinesMap: { [lineItemId: string]: LineItemTaxLine[] } = {} - - if (!taxRate && includeTax) { - // Use existing tax lines if they are present - const itemContainsTaxLines = items.some((item) => item.tax_lines?.length) - if (itemContainsTaxLines) { - items.forEach((item) => { - lineItemsTaxLinesMap[item.id] = item.tax_lines ?? [] - }) - } else { - const { lineItemsTaxLines } = await this.taxProviderService_ - .withTransaction(this.activeManager_) - .getTaxLinesMap(items, calculationContext) - lineItemsTaxLinesMap = lineItemsTaxLines - } - } - - const calculationMethod = taxRate - ? this.getLineItemTotalsLegacy.bind(this) - : this.getLineItemTotals_.bind(this) - - const itemsTotals: { [lineItemId: string]: LineItemTotals } = {} - for (const item of items) { - const lineItemAllocation = - calculationContext.allocation_map[item.id] || {} - - itemsTotals[item.id] = await calculationMethod(item, { - taxRate, - includeTax, - lineItemAllocation, - taxLines: lineItemsTaxLinesMap[item.id], - calculationContext, - }) - } - - return itemsTotals - } - - /** - * Calculate and return the totals for an item - * @param item - * @param param1 - * @returns - */ - protected async getLineItemTotals_( - item: LineItem, - { - includeTax, - lineItemAllocation, - /** - * Only needed to force the usage of the specified tax lines, often in the case where the item does not hold the tax lines - */ - taxLines, - calculationContext, - }: { - includeTax?: boolean - lineItemAllocation: LineAllocationsMap[number] - taxLines?: LineItemTaxLine[] - calculationContext: TaxCalculationContext - } - ): Promise { - let subtotal = item.unit_price * item.quantity - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && - item.includes_tax - ) { - subtotal = 0 // in that case we need to know the tax rate to compute it later - } - - const raw_discount_total = lineItemAllocation.discount?.amount ?? 0 - const discount_total = Math.round(raw_discount_total) - - const totals: LineItemTotals = { - unit_price: item.unit_price, - quantity: item.quantity, - subtotal, - discount_total, - total: subtotal - discount_total, - original_total: subtotal, - original_tax_total: 0, - tax_total: 0, - tax_lines: item.tax_lines ?? [], - - raw_discount_total: raw_discount_total, - } - - if (includeTax) { - totals.tax_lines = totals.tax_lines.length - ? totals.tax_lines - : (taxLines as LineItemTaxLine[]) - - if (!totals.tax_lines && item.variant_id) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Tax Lines must be joined to calculate taxes" - ) - } - } - - if (item.is_return) { - if (!isDefined(item.tax_lines) && item.variant_id) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Return Line Items must join tax lines" - ) - } - } - - if (totals.tax_lines?.length > 0) { - totals.tax_total = await this.taxCalculationStrategy_.calculate( - [item], - totals.tax_lines, - calculationContext - ) - - const noDiscountContext = { - ...calculationContext, - allocation_map: {}, // Don't account for discounts - } - - totals.original_tax_total = await this.taxCalculationStrategy_.calculate( - [item], - totals.tax_lines, - noDiscountContext - ) - - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && - item.includes_tax - ) { - totals.subtotal += - totals.unit_price * totals.quantity - totals.original_tax_total - totals.total += totals.subtotal - totals.original_total += totals.subtotal - } - - totals.total += totals.tax_total - totals.original_total += totals.original_tax_total - } - - return totals - } - - /** - * Calculate and return the legacy calculated totals using the tax rate - * @param item - * @param param1 - */ - protected async getLineItemTotalsLegacy( - item: LineItem, - { - taxRate, - lineItemAllocation, - calculationContext, - }: { - lineItemAllocation: LineAllocationsMap[number] - calculationContext: TaxCalculationContext - taxRate: number - } - ): Promise { - let subtotal = item.unit_price * item.quantity - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && - item.includes_tax - ) { - subtotal = 0 // in that case we need to know the tax rate to compute it later - } - - const raw_discount_total = lineItemAllocation.discount?.amount ?? 0 - const discount_total = Math.round(raw_discount_total) - - const totals: LineItemTotals = { - unit_price: item.unit_price, - quantity: item.quantity, - subtotal, - discount_total, - total: subtotal - discount_total, - original_total: subtotal, - original_tax_total: 0, - tax_total: 0, - tax_lines: [], - - raw_discount_total, - } - - taxRate = taxRate / 100 - - const includesTax = - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && item.includes_tax - const taxIncludedInPrice = !item.includes_tax - ? 0 - : Math.round( - calculatePriceTaxAmount({ - price: item.unit_price, - taxRate: taxRate, - includesTax, - }) - ) - totals.subtotal = Math.round( - (item.unit_price - taxIncludedInPrice) * item.quantity - ) - totals.total = totals.subtotal - - totals.original_tax_total = Math.round(totals.subtotal * taxRate) - totals.tax_total = Math.round((totals.subtotal - discount_total) * taxRate) - - totals.total += totals.tax_total - - if (includesTax) { - totals.original_total += totals.subtotal - } - - totals.original_total += totals.original_tax_total - - return totals - } - - /** - * Return the amount that can be refund on a line item - * @param lineItem - * @param param1 - */ - getLineItemRefund( - lineItem: { - id: string - unit_price: number - includes_tax: boolean - quantity: number - tax_lines: LineItemTaxLine[] - }, - { - calculationContext, - taxRate, - }: { calculationContext: TaxCalculationContext; taxRate?: number | null } - ): number { - /* - * Used for backcompat with old tax system - */ - if (taxRate != null) { - return this.getLineItemRefundLegacy(lineItem, { - calculationContext, - taxRate, - }) - } - - const includesTax = - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && lineItem.includes_tax - - const discountAmount = - (calculationContext.allocation_map[lineItem.id]?.discount?.unit_amount || - 0) * lineItem.quantity - - if (!isDefined(lineItem.tax_lines)) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Cannot compute line item refund amount, tax lines are missing from the line item" - ) - } - - const totalTaxRate = lineItem.tax_lines.reduce((acc, next) => { - return acc + next.rate / 100 - }, 0) - - const taxAmountIncludedInPrice = !includesTax - ? 0 - : Math.round( - calculatePriceTaxAmount({ - price: lineItem.unit_price, - taxRate: totalTaxRate, - includesTax, - }) - ) - - const lineSubtotal = - (lineItem.unit_price - taxAmountIncludedInPrice) * lineItem.quantity - - discountAmount - - const taxTotal = lineItem.tax_lines.reduce((acc, next) => { - return acc + Math.round(lineSubtotal * (next.rate / 100)) - }, 0) - - return lineSubtotal + taxTotal - } - - /** - * @param lineItem - * @param param1 - * @protected - */ - protected getLineItemRefundLegacy( - lineItem: { - id: string - unit_price: number - includes_tax: boolean - quantity: number - }, - { - calculationContext, - taxRate, - }: { calculationContext: TaxCalculationContext; taxRate: number } - ): number { - const includesTax = - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && lineItem.includes_tax - - const taxAmountIncludedInPrice = !includesTax - ? 0 - : Math.round( - calculatePriceTaxAmount({ - price: lineItem.unit_price, - taxRate: taxRate / 100, - includesTax, - }) - ) - - const discountAmount = - calculationContext.allocation_map[lineItem.id]?.discount?.amount ?? 0 - - const lineSubtotal = - (lineItem.unit_price - taxAmountIncludedInPrice) * lineItem.quantity - - discountAmount - - return Math.round(lineSubtotal * (1 + taxRate / 100)) - } - - /** - * Calculate and return the gift cards totals - * @param giftCardableAmount - * @param param1 - */ - async getGiftCardTotals( - giftCardableAmount: number, - { - giftCardTransactions, - region, - giftCards, - }: { - region: Region - giftCardTransactions?: GiftCardTransaction[] - giftCards?: GiftCard[] - } - ): Promise<{ - total: number - tax_total: number - }> { - if (!giftCards && !giftCardTransactions) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Cannot calculate the gift card totals. Neither the gift cards or gift card transactions have been provided" - ) - } - - if (giftCardTransactions?.length) { - return this.getGiftCardTransactionsTotals({ - giftCardTransactions, - region, - }) - } - - const result = { - total: 0, - tax_total: 0, - } - - if (!giftCards?.length) { - return result - } - - // If a gift card is not taxable, the tax_rate for the giftcard will be null - const { totalGiftCardBalance, totalTaxFromGiftCards } = giftCards.reduce( - (acc, giftCard) => { - let taxableAmount = 0 - - acc.totalGiftCardBalance += giftCard.balance - - taxableAmount = Math.min(acc.giftCardableBalance, giftCard.balance) - // skip tax, if the taxable amount is not a positive number or tax rate is not set - if (taxableAmount <= 0 || !giftCard.tax_rate) { - return acc - } - - const taxAmountFromGiftCard = Math.round( - taxableAmount * (giftCard.tax_rate / 100) - ) - - acc.totalTaxFromGiftCards += taxAmountFromGiftCard - // Update the balance, pass it over to the next gift card (if any) for calculating tax on balance. - acc.giftCardableBalance -= taxableAmount - - return acc - }, - { - totalGiftCardBalance: 0, - totalTaxFromGiftCards: 0, - giftCardableBalance: giftCardableAmount, - } - ) - - result.tax_total = Math.round(totalTaxFromGiftCards) - result.total = Math.min(giftCardableAmount, totalGiftCardBalance) - - return result - } - - /** - * Calculate and return the gift cards totals based on their transactions - * @param param0 - */ - getGiftCardTransactionsTotals({ - giftCardTransactions, - region, - }: { - giftCardTransactions: GiftCardTransaction[] - region: { gift_cards_taxable: boolean; tax_rate: number } - }): { total: number; tax_total: number } { - return giftCardTransactions.reduce( - (acc, next) => { - let taxMultiplier = (next.tax_rate || 0) / 100 - - // Previously we did not record whether a gift card was taxable or not. - // All gift cards where is_taxable === null are from the old system, - // where we defaulted to taxable gift cards. - // - // This is a backwards compatability fix for orders that were created - // before we added the gift card tax rate. - // We prioritize the giftCard.tax_rate as we create a snapshot of the tax - // on order creation to create gift cards on the gift card itself. - // If its created outside of the order, we refer to the region tax - if (next.is_taxable === null) { - if (region?.gift_cards_taxable || next.gift_card?.tax_rate) { - taxMultiplier = (next.gift_card?.tax_rate ?? region.tax_rate) / 100 - } - } - - return { - total: acc.total + next.amount, - tax_total: Math.round(acc.tax_total + next.amount * taxMultiplier), - } - }, - { - total: 0, - tax_total: 0, - } - ) - } - - /** - * Calculate and return the shipping methods totals for either the legacy calculation or the new calculation - * @param shippingMethods - * @param param1 - */ - async getShippingMethodTotals( - shippingMethods: ShippingMethod | ShippingMethod[], - { - includeTax, - discounts, - taxRate, - calculationContext, - }: { - includeTax?: boolean - calculationContext: TaxCalculationContext - discounts?: Discount[] - taxRate?: number | null - } - ): Promise<{ [shippingMethodId: string]: ShippingMethodTotals }> { - shippingMethods = Array.isArray(shippingMethods) - ? shippingMethods - : [shippingMethods] - - let shippingMethodsTaxLinesMap: { - [shippingMethodId: string]: ShippingMethodTaxLine[] - } = {} - - if (!taxRate && includeTax) { - // Use existing tax lines if they are present - const shippingMethodContainsTaxLines = shippingMethods.some( - (method) => method.tax_lines?.length - ) - if (shippingMethodContainsTaxLines) { - shippingMethods.forEach((sm) => { - shippingMethodsTaxLinesMap[sm.id] = sm.tax_lines ?? [] - }) - } else { - const calculationContextWithGivenMethod = { - ...calculationContext, - shipping_methods: shippingMethods, - } - const { shippingMethodsTaxLines } = await this.taxProviderService_ - .withTransaction(this.activeManager_) - .getTaxLinesMap([], calculationContextWithGivenMethod) - shippingMethodsTaxLinesMap = shippingMethodsTaxLines - } - } - - const calculationMethod = taxRate - ? this.getShippingMethodTotalsLegacy.bind(this) - : this.getShippingMethodTotals_.bind(this) - - const shippingMethodsTotals: { - [lineItemId: string]: ShippingMethodTotals - } = {} - for (const shippingMethod of shippingMethods) { - shippingMethodsTotals[shippingMethod.id] = await calculationMethod( - shippingMethod, - { - includeTax, - calculationContext, - taxLines: shippingMethodsTaxLinesMap[shippingMethod.id], - discounts, - taxRate, - } - ) - } - - return shippingMethodsTotals - } - - getGiftCardableAmount({ - gift_cards_taxable, - subtotal, - shipping_total, - discount_total, - tax_total, - }: { - gift_cards_taxable?: boolean - subtotal: number - shipping_total: number - discount_total: number - tax_total: number - }): number { - return ( - (gift_cards_taxable - ? subtotal + shipping_total - discount_total - : subtotal + shipping_total + tax_total - discount_total) || 0 - ) - } - - /** - * Calculate and return the shipping method totals - * @param shippingMethod - * @param param1 - */ - protected async getShippingMethodTotals_( - shippingMethod: ShippingMethod, - { - includeTax, - calculationContext, - taxLines, - discounts, - }: { - includeTax?: boolean - calculationContext: TaxCalculationContext - taxLines?: ShippingMethodTaxLine[] - discounts?: Discount[] - } - ) { - const totals: ShippingMethodTotals = { - price: shippingMethod.price, - original_total: shippingMethod.price, - total: shippingMethod.price, - subtotal: shippingMethod.price, - original_tax_total: 0, - tax_total: 0, - tax_lines: shippingMethod.tax_lines ?? [], - } - - if (includeTax) { - totals.tax_lines = totals.tax_lines.length - ? totals.tax_lines - : (taxLines as ShippingMethodTaxLine[]) - - if (!totals.tax_lines) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Tax Lines must be joined to calculate shipping taxes" - ) - } - } - - const calculationContext_: TaxCalculationContext = { - ...calculationContext, - shipping_methods: [shippingMethod], - } - - if (totals.tax_lines.length) { - const includesTax = - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && shippingMethod.includes_tax - - totals.original_tax_total = await this.taxCalculationStrategy_.calculate( - [], - totals.tax_lines, - calculationContext_ - ) - totals.tax_total = totals.original_tax_total - - if (includesTax) { - totals.subtotal -= totals.tax_total - } else { - totals.original_total += totals.original_tax_total - totals.total += totals.tax_total - } - } - - const hasFreeShipping = discounts?.some( - (d) => d.rule.type === DiscountRuleType.FREE_SHIPPING - ) - - if (hasFreeShipping) { - totals.total = 0 - totals.subtotal = 0 - totals.tax_total = 0 - } - - return totals - } - - /** - * Calculate and return the shipping method totals legacy using the tax rate - * @param shippingMethod - * @param param1 - */ - protected async getShippingMethodTotalsLegacy( - shippingMethod: ShippingMethod, - { - calculationContext, - discounts, - taxRate, - }: { - calculationContext: TaxCalculationContext - discounts?: Discount[] - taxRate: number - } - ): Promise { - const totals: ShippingMethodTotals = { - price: shippingMethod.price, - original_total: shippingMethod.price, - total: shippingMethod.price, - subtotal: shippingMethod.price, - original_tax_total: 0, - tax_total: 0, - tax_lines: [], - } - - totals.original_tax_total = Math.round(totals.price * (taxRate / 100)) - totals.tax_total = Math.round(totals.price * (taxRate / 100)) - - const hasFreeShipping = discounts?.some( - (d) => d.rule.type === DiscountRuleType.FREE_SHIPPING - ) - - if (hasFreeShipping) { - totals.total = 0 - totals.subtotal = 0 - totals.tax_total = 0 - } - - return totals - } -} diff --git a/packages/medusa/src/services/note.ts b/packages/medusa/src/services/note.ts deleted file mode 100644 index 1535194cc5..0000000000 --- a/packages/medusa/src/services/note.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { FindConfig, Selector } from "../types/common" -import { MedusaError, isDefined } from "medusa-core-utils" - -import { CreateNoteInput } from "../types/note" -import { EntityManager } from "typeorm" -import EventBusService from "./event-bus" -import { Note } from "../models" -import { NoteRepository } from "../repositories/note" -import { TransactionBaseService } from "../interfaces" -import { buildQuery } from "../utils" - -type InjectedDependencies = { - manager: EntityManager - noteRepository: typeof NoteRepository - eventBusService: EventBusService -} - -class NoteService extends TransactionBaseService { - static readonly Events = { - CREATED: "note.created", - UPDATED: "note.updated", - DELETED: "note.deleted", - } - - protected readonly noteRepository_: typeof NoteRepository - protected readonly eventBus_: EventBusService - - constructor({ noteRepository, eventBusService }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.noteRepository_ = noteRepository - this.eventBus_ = eventBusService - } - - /** - * Retrieves a specific note. - * @param noteId - the id of the note to retrieve. - * @param config - any options needed to query for the result. - * @return which resolves to the requested note. - */ - async retrieve( - noteId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(noteId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"noteId" must be defined` - ) - } - - const noteRepo = this.activeManager_.withRepository(this.noteRepository_) - - const query = buildQuery({ id: noteId }, config) - - const note = await noteRepo.findOne(query) - - if (!note) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Note with id: ${noteId} was not found.` - ) - } - - return note - } - - /** Fetches all notes related to the given selector - * @param selector - the query object for find - * @param config - the configuration used to find the objects. contains relations, skip, and take. - * @return notes related to the given search. - */ - async list( - selector: Selector, - config: FindConfig = { - /** - * How many Notes to skip in the resulting list of Notes. - */ - skip: 0, - /** - * How many Notes to take in the resulting list of Notes. - */ - take: 50, - /** - * Which relations to include in the resulting list of Notes. - */ - relations: [], - } - ): Promise { - const [result] = await this.listAndCount(selector, config) - - return result - } - - /** Fetches all notes related to the given selector - * @param selector - the query object for find - * @param config - the configuration used to find the objects. contains relations, skip, and take. - * @return notes related to the given search. - */ - async listAndCount( - selector: Selector, - config: FindConfig = { - /** - * How many Notes to skip in the resulting list of Notes. - */ - skip: 0, - /** - * How many Notes to take in the resulting list of Notes. - */ - take: 50, - /** - * Which relations to include in the resulting list of Notes. - */ - relations: [], - } - ): Promise<[Note[], number]> { - const noteRepo = this.activeManager_.withRepository(this.noteRepository_) - - const query = buildQuery(selector, config) - - return noteRepo.findAndCount(query) - } - - /** - * Creates a note associated with a given author - * @param data - the note to create - * @param config - any configurations if needed, including meta data - * @return resolves to the creation result - */ - async create( - data: CreateNoteInput, - config: { metadata: Record } = { metadata: {} } - ): Promise { - const { metadata } = config - - const { resource_id, resource_type, value, author_id } = data - - return await this.atomicPhase_(async (manager) => { - const noteRepo = manager.withRepository(this.noteRepository_) - - const toCreate = { - resource_id, - resource_type, - value, - author_id, - metadata, - } - - const note = noteRepo.create(toCreate) - const result = await noteRepo.save(note) - - await this.eventBus_ - .withTransaction(manager) - .emit(NoteService.Events.CREATED, { id: result.id }) - - return result - }) - } - - /** - * Updates a given note with a new value - * @param noteId - the id of the note to update - * @param value - the new value - * @return resolves to the updated element - */ - async update(noteId: string, value: string): Promise { - return await this.atomicPhase_(async (manager) => { - const noteRepo = manager.withRepository(this.noteRepository_) - - const note = await this.retrieve(noteId) - - note.value = value - - const result = await noteRepo.save(note) - - await this.eventBus_ - .withTransaction(manager) - .emit(NoteService.Events.UPDATED, { id: result.id }) - - return result - }) - } - - /** - * Deletes a given note - * @param noteId - id of the note to delete - */ - async delete(noteId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const noteRepo = manager.withRepository(this.noteRepository_) - - const note = await this.retrieve(noteId) - - await noteRepo.softRemove(note) - - await this.eventBus_ - .withTransaction(manager) - .emit(NoteService.Events.DELETED, { id: noteId }) - }) - } -} - -export default NoteService diff --git a/packages/medusa/src/services/notification.ts b/packages/medusa/src/services/notification.ts deleted file mode 100644 index e758714b8b..0000000000 --- a/packages/medusa/src/services/notification.ts +++ /dev/null @@ -1,296 +0,0 @@ -import { - AbstractNotificationService, - TransactionBaseService, -} from "../interfaces" -import { FindConfig, Selector } from "../types/common" - -import { EntityManager } from "typeorm" -import { Logger } from "../types/global" -import { MedusaError } from "medusa-core-utils" -import { Notification } from "../models" -import { NotificationProviderRepository } from "../repositories/notification-provider" -import { NotificationRepository } from "../repositories/notification" -import { buildQuery } from "../utils" -import { promiseAll } from "@medusajs/utils" - -type InjectedDependencies = { - manager: EntityManager - logger: Logger - notificationRepository: typeof NotificationRepository - notificationProviderRepository: typeof NotificationProviderRepository -} -type NotificationProviderKey = `noti_${string}` - -class NotificationService extends TransactionBaseService { - protected subscribers_ = {} - protected attachmentGenerator_: unknown = null - protected readonly container_: InjectedDependencies & { - [key in `${NotificationProviderKey}`]: AbstractNotificationService - } - protected readonly logger_: Logger - protected readonly notificationRepository_: typeof NotificationRepository - // eslint-disable-next-line max-len - protected readonly notificationProviderRepository_: typeof NotificationProviderRepository - - constructor(container: InjectedDependencies) { - super(container) - - const { notificationProviderRepository, notificationRepository, logger } = - container - - this.container_ = container - - this.logger_ = logger - this.notificationRepository_ = notificationRepository - this.notificationProviderRepository_ = notificationProviderRepository - } - - /** - * Registers an attachment generator to the service. The generator can be - * used to generate on demand invoices or other documents. - * @param service the service to assign to the attachmentGenerator - */ - registerAttachmentGenerator(service: unknown): void { - this.attachmentGenerator_ = service - } - - /** - * Takes a list of notification provider ids and persists them in the database. - * @param providerIds - a list of provider ids - */ - async registerInstalledProviders(providerIds: string[]): Promise { - const { notificationProviderRepository } = this.container_ - const model = this.activeManager_.withRepository( - notificationProviderRepository - ) - await model.update({}, { is_installed: false }) - for (const id of providerIds) { - const n = model.create({ id, is_installed: true }) - await model.save(n) - } - } - - /** - * Retrieves a list of notifications. - * @param selector - the params to select the notifications by. - * @param config - the configuration to apply to the query - * @return the notifications that satisfy the query. - */ - async list( - selector: Selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise { - const [notifications] = await this.listAndCount(selector, config) - - return notifications - } - - /** - * Retrieves a list of notifications and total count. - * @param selector - the params to select the notifications by. - * @param config - the configuration to apply to the query - * @return the notifications that satisfy the query as well as the count. - */ - async listAndCount( - selector: Selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise<[Notification[], number]> { - const notiRepo = this.activeManager_.withRepository( - this.notificationRepository_ - ) - const query = buildQuery(selector, config) - return await notiRepo.findAndCount(query) - } - - /** - * Retrieves a notification with a given id - * @param id - the id of the notification - * @param config - the configuration to apply to the query - * @return the notification - */ - async retrieve( - id: string, - config: FindConfig = {} - ): Promise { - const notiRepository = this.activeManager_.withRepository( - this.notificationRepository_ - ) - - const query = buildQuery({ id }, config) - - const notification = await notiRepository.findOne(query) - - if (!notification) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Notification with id: ${id} was not found.` - ) - } - - return notification - } - - /** - * Subscribes a given provider to an event. - * @param eventName - the event to subscribe to - * @param providerId - the provider that the event will be sent to - */ - subscribe(eventName: string, providerId: string): void { - if (typeof providerId !== "string") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "providerId must be a string" - ) - } - - if (this.subscribers_[eventName]) { - this.subscribers_[eventName].push(providerId) - } else { - this.subscribers_[eventName] = [providerId] - } - } - - /** - * Finds a provider with a given id. Will throw a NOT_FOUND error if the - * resolution fails. - * @param id - the id of the provider - * @return the notification provider - */ - protected retrieveProvider_(id: string): AbstractNotificationService { - try { - return this.container_[`noti_${id}`] - } catch (err) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Could not find a notification provider with id: ${id}.` - ) - } - } - - /** - * Handles an event by relaying the event data to the subscribing providers. - * The result of the notification send will be persisted in the database in - * order to allow for resends. Will log any errors that are encountered. - * @param eventName - the event to handle - * @param data - the data the event was sent with - * @return the result of notification subscribed - */ - async handleEvent( - eventName: string, - data: Record - ): Promise { - const subs = this.subscribers_[eventName] - if (!subs) { - return Promise.resolve() - } - if (data["no_notification"] === true) { - return Promise.resolve() - } - - return promiseAll( - subs.map(async (providerId) => { - return this.send(eventName, data, providerId).catch((err) => { - this.logger_.log(err) - this.logger_.warn( - `An error occured while ${providerId} was processing a notification for ${eventName}: ${err.message}` - ) - }) - }) - ) - } - - /** - * Sends a notification, by calling the given provider's sendNotification - * method. Persists the Notification in the database. - * @param event - the name of the event - * @param eventData - the data the event was sent with - * @param providerId - the provider that should handle the event. - * @return the created notification - */ - async send( - event: string, - eventData: Record, - providerId: string - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const provider = this.retrieveProvider_(providerId) - const result = await provider.sendNotification( - event, - eventData, - this.attachmentGenerator_ - ) - - if (!result) { - return - } - - const { to, data } = result - const notiRepo = transactionManager.withRepository( - this.notificationRepository_ - ) - - const [resource_type] = event.split(".") as string[] - const resource_id = eventData.id as string - const customer_id = (eventData.customer_id as string) || null - - const created = notiRepo.create({ - resource_type, - resource_id, - customer_id, - to, - data, - event_name: event, - provider_id: providerId, - }) - - return await notiRepo.save(created) - }) - } - - /** - * Resends a notification by retrieving a prior notification and calling the - * underlying provider's resendNotification method. - * @param {string} id - the id of the notification - * @param {object} config - any configuration that might override the previous - * send - * @return {Notification} the newly created notification - */ - async resend( - id: string, - config: FindConfig = {} - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const notification = await this.retrieve(id) - - const provider = this.retrieveProvider_(notification.provider_id) - const { to, data } = await provider.resendNotification( - notification, - config, - this.attachmentGenerator_ - ) - - const notiRepo = transactionManager.withRepository( - this.notificationRepository_ - ) - const resendNoti: Record = { ...notification, id: null } - const created = notiRepo.create({ - ...resendNoti, - to, - data, - parent_id: id, - }) - - return notiRepo.save(created) - }) - } -} - -export default NotificationService diff --git a/packages/medusa/src/services/oauth.ts b/packages/medusa/src/services/oauth.ts deleted file mode 100644 index 2de2ee2d71..0000000000 --- a/packages/medusa/src/services/oauth.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { Oauth as OAuthModel } from "../models" -import { OauthRepository } from "../repositories/oauth" -import { Selector } from "../types/common" -import { MedusaContainer } from "../types/global" -import { CreateOauthInput, UpdateOauthInput } from "../types/oauth" -import { buildQuery } from "../utils" -import EventBusService from "./event-bus" - -type InjectedDependencies = MedusaContainer & { - manager: EntityManager - eventBusService: EventBusService - oauthRepository: typeof OauthRepository -} - -class Oauth extends TransactionBaseService { - static Events = { - TOKEN_GENERATED: "oauth.token_generated", - TOKEN_REFRESHED: "oauth.token_refreshed", - } - - protected container_: InjectedDependencies - protected oauthRepository_: typeof OauthRepository - protected eventBus_: EventBusService - - constructor(cradle: InjectedDependencies) { - super(cradle) - - this.container_ = cradle - this.oauthRepository_ = cradle.oauthRepository - this.eventBus_ = cradle.eventBusService - } - - async retrieveByName(appName: string): Promise { - const repo = this.activeManager_.withRepository(this.oauthRepository_) - const oauth = await repo.findOne({ - where: { - application_name: appName, - }, - }) - - if (!oauth) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Oauth application ${appName} not found` - ) - } - - return oauth - } - - async retrieve(oauthId: string): Promise { - if (!isDefined(oauthId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"oauthId" must be defined` - ) - } - - const repo = this.activeManager_.withRepository(this.oauthRepository_) - const oauth = await repo.findOne({ - where: { - id: oauthId, - }, - }) - - if (!oauth) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Oauth application with id ${oauthId} not found` - ) - } - - return oauth - } - - async list(selector: Selector): Promise { - const repo = this.activeManager_.withRepository(this.oauthRepository_) - - const query = buildQuery(selector, {}) - - return await repo.find(query) - } - - async create(data: CreateOauthInput): Promise { - const repo = this.activeManager_.withRepository(this.oauthRepository_) - - const application = repo.create({ - display_name: data.display_name, - application_name: data.application_name, - install_url: data.install_url, - uninstall_url: data.uninstall_url, - }) - - return await repo.save(application) - } - - async update(id: string, update: UpdateOauthInput): Promise { - const repo = this.activeManager_.withRepository(this.oauthRepository_) - const oauth = await this.retrieve(id) - - if ("data" in update) { - oauth.data = update.data - } - - return await repo.save(oauth) - } - - async registerOauthApp(appDetails: CreateOauthInput): Promise { - const { application_name } = appDetails - const existing = await this.retrieveByName(application_name) - if (existing) { - return existing - } - - return await this.create(appDetails) - } - - async generateToken( - appName: string, - code: string, - state: string - ): Promise { - const app = await this.retrieveByName(appName) - const service = this.container_[`${app.application_name}Oauth`] - if (!service) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `An OAuth handler for ${app.display_name} could not be found make sure the plugin is installed` - ) - } - - if (!(app.data.state === state)) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `${app.display_name} could not match state` - ) - } - - const authData = await service.generateToken(code) - - return await this.update(app.id, { - data: authData, - }).then(async (result) => { - await this.eventBus_.emit( - `${Oauth.Events.TOKEN_GENERATED}.${appName}`, - authData - ) - return result - }) - } - - async refreshToken(appName: string): Promise { - const app = await this.retrieveByName(appName) - const refreshToken = app.data.refresh_token - const service = this.container_[`${app.application_name}Oauth`] - if (!service) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `An OAuth handler for ${app.display_name} could not be found make sure the plugin is installed` - ) - } - - const authData = await service.refreshToken(refreshToken) - - return await this.update(app.id, { - data: authData, - }).then(async (result) => { - await this.eventBus_.emit( - `${Oauth.Events.TOKEN_REFRESHED}.${appName}`, - authData - ) - return result - }) - } -} - -export default Oauth diff --git a/packages/medusa/src/services/order-edit-item-change.ts b/packages/medusa/src/services/order-edit-item-change.ts deleted file mode 100644 index 08743310da..0000000000 --- a/packages/medusa/src/services/order-edit-item-change.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { EventBusTypes } from "@medusajs/types" -import { MedusaError } from "medusa-core-utils" -import { EntityManager, In } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { OrderItemChange } from "../models" -import { OrderItemChangeRepository } from "../repositories/order-item-change" -import { FindConfig, Selector } from "../types/common" -import { CreateOrderEditItemChangeInput } from "../types/order-edit" -import { buildQuery } from "../utils" -import { LineItemService } from "./index" -import TaxProviderService from "./tax-provider" -import { promiseAll } from "@medusajs/utils" - -type InjectedDependencies = { - manager: EntityManager - orderItemChangeRepository: typeof OrderItemChangeRepository - eventBusService: EventBusTypes.IEventBusService - lineItemService: LineItemService - taxProviderService: TaxProviderService -} - -export default class OrderEditItemChangeService extends TransactionBaseService { - static readonly Events = { - CREATED: "order-edit-item-change.CREATED", - DELETED: "order-edit-item-change.DELETED", - } - - // eslint-disable-next-line max-len - protected readonly orderItemChangeRepository_: typeof OrderItemChangeRepository - protected readonly eventBus_: EventBusTypes.IEventBusService - protected readonly lineItemService_: LineItemService - protected readonly taxProviderService_: TaxProviderService - - constructor({ - orderItemChangeRepository, - eventBusService, - lineItemService, - taxProviderService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.orderItemChangeRepository_ = orderItemChangeRepository - this.eventBus_ = eventBusService - this.lineItemService_ = lineItemService - this.taxProviderService_ = taxProviderService - } - - async retrieve( - id: string, - config: FindConfig = {} - ): Promise { - const orderItemChangeRepo = this.activeManager_.withRepository( - this.orderItemChangeRepository_ - ) - - const query = buildQuery({ id }, config) - const itemChange = await orderItemChangeRepo.findOne(query) - - if (!itemChange) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Order edit item change ${id} was not found` - ) - } - - return itemChange - } - - async list( - selector: Selector, - config: FindConfig = {} - ): Promise { - const orderItemChangeRepo = this.activeManager_.withRepository( - this.orderItemChangeRepository_ - ) - - const query = buildQuery(selector, config) - return await orderItemChangeRepo.find(query) - } - - async create(data: CreateOrderEditItemChangeInput): Promise { - return await this.atomicPhase_(async (manager) => { - const orderItemChangeRepo = manager.withRepository( - this.orderItemChangeRepository_ - ) - const changeEntity = orderItemChangeRepo.create(data) - const change = await orderItemChangeRepo.save(changeEntity) - - await this.eventBus_ - .withTransaction(manager) - .emit(OrderEditItemChangeService.Events.CREATED, { id: change.id }) - - return change - }) - } - - async delete(itemChangeIds: string | string[]): Promise { - itemChangeIds = Array.isArray(itemChangeIds) - ? itemChangeIds - : [itemChangeIds] - - return await this.atomicPhase_(async (manager) => { - const orderItemChangeRepo = manager.withRepository( - this.orderItemChangeRepository_ - ) - - const changes = await orderItemChangeRepo.find({ - where: { - id: In(itemChangeIds as string[]), - }, - }) - - const lineItemIdsToRemove = changes - .map((change) => { - return change.line_item_id - }) - .filter(Boolean) as string[] - - await orderItemChangeRepo.delete({ id: In(itemChangeIds as string[]) }) - - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - await promiseAll([ - ...lineItemIdsToRemove.map( - async (id) => await lineItemServiceTx.delete(id) - ), - this.taxProviderService_ - .withTransaction(manager) - .clearLineItemsTaxLines(lineItemIdsToRemove), - ]) - - await this.eventBus_ - .withTransaction(manager) - .emit(OrderEditItemChangeService.Events.DELETED, { ids: itemChangeIds }) - }) - } -} diff --git a/packages/medusa/src/services/order-edit.ts b/packages/medusa/src/services/order-edit.ts deleted file mode 100644 index f8f833e98f..0000000000 --- a/packages/medusa/src/services/order-edit.ts +++ /dev/null @@ -1,873 +0,0 @@ -import { - AddOrderEditLineItemInput, - CreateOrderEditInput, -} from "../types/order-edit" -import { - Cart, - Order, - OrderEdit, - OrderEditItemChangeType, - OrderEditStatus, -} from "../models" -import { - DeepPartial, - EntityManager, - FindOptionsWhere, - ILike, - IsNull, - Not, -} from "typeorm" -import { FindConfig, Selector } from "../types/common" -import { - LineItemAdjustmentService, - LineItemService, - NewTotalsService, - OrderEditItemChangeService, - OrderService, - TaxProviderService, - TotalsService, -} from "./index" -import { isDefined, MedusaError } from "medusa-core-utils" -import { buildQuery, isString } from "../utils" - -import EventBusService from "./event-bus" -import { IInventoryService } from "@medusajs/types" -import { OrderEditRepository } from "../repositories/order-edit" -import { TransactionBaseService } from "../interfaces" -import { promiseAll } from "@medusajs/utils" - -type InjectedDependencies = { - manager: EntityManager - orderEditRepository: typeof OrderEditRepository - - orderService: OrderService - totalsService: TotalsService - newTotalsService: NewTotalsService - lineItemService: LineItemService - eventBusService: EventBusService - taxProviderService: TaxProviderService - lineItemAdjustmentService: LineItemAdjustmentService - orderEditItemChangeService: OrderEditItemChangeService - - inventoryService?: IInventoryService -} - -export default class OrderEditService extends TransactionBaseService { - static readonly Events = { - CREATED: "order-edit.created", - UPDATED: "order-edit.updated", - DECLINED: "order-edit.declined", - REQUESTED: "order-edit.requested", - CANCELED: "order-edit.canceled", - CONFIRMED: "order-edit.confirmed", - } - - protected readonly orderEditRepository_: typeof OrderEditRepository - - protected readonly orderService_: OrderService - protected readonly totalsService_: TotalsService - protected readonly newTotalsService_: NewTotalsService - protected readonly lineItemService_: LineItemService - protected readonly eventBusService_: EventBusService - protected readonly taxProviderService_: TaxProviderService - protected readonly lineItemAdjustmentService_: LineItemAdjustmentService - protected readonly orderEditItemChangeService_: OrderEditItemChangeService - - protected get inventoryService_(): IInventoryService | undefined { - return this.__container__.inventoryService - } - - constructor({ - orderEditRepository, - orderService, - lineItemService, - eventBusService, - totalsService, - newTotalsService, - orderEditItemChangeService, - lineItemAdjustmentService, - taxProviderService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.orderEditRepository_ = orderEditRepository - this.orderService_ = orderService - this.lineItemService_ = lineItemService - this.eventBusService_ = eventBusService - this.totalsService_ = totalsService - this.newTotalsService_ = newTotalsService - this.orderEditItemChangeService_ = orderEditItemChangeService - this.lineItemAdjustmentService_ = lineItemAdjustmentService - this.taxProviderService_ = taxProviderService - } - - async retrieve( - orderEditId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(orderEditId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"orderEditId" must be defined` - ) - } - - const orderEditRepository = this.activeManager_.withRepository( - this.orderEditRepository_ - ) - - const query = buildQuery({ id: orderEditId }, config) - const orderEdit = await orderEditRepository.findOne(query) - - if (!orderEdit) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Order edit with id ${orderEditId} was not found` - ) - } - - return orderEdit - } - - async listAndCount( - selector: Selector & { q?: string }, - config?: FindConfig - ): Promise<[OrderEdit[], number]> { - const orderEditRepository = this.activeManager_.withRepository( - this.orderEditRepository_ - ) - - let q - if (isString(selector.q)) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - query.where = query.where as FindOptionsWhere - - if (q) { - query.where.internal_note = ILike(`%${q}%`) - } - - return await orderEditRepository.findAndCount(query) - } - - async list( - selector: Selector, - config?: FindConfig - ): Promise { - const [orderEdits] = await this.listAndCount(selector, config) - return orderEdits - } - - async create( - data: CreateOrderEditInput, - context: { createdBy: string } - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const activeOrderEdit = await this.retrieveActive(data.order_id) - if (activeOrderEdit) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `An active order edit already exists for the order ${data.order_id}` - ) - } - - const orderEditRepository = transactionManager.withRepository( - this.orderEditRepository_ - ) - - const orderEditToCreate = orderEditRepository.create({ - order_id: data.order_id, - internal_note: data.internal_note, - created_by: context.createdBy, - }) - - const orderEdit = await orderEditRepository.save(orderEditToCreate) - - const lineItemServiceTx = - this.lineItemService_.withTransaction(transactionManager) - - const orderLineItems = await lineItemServiceTx.list( - { - order_id: data.order_id, - }, - { - select: ["id"], - } - ) - const lineItemIds = orderLineItems.map(({ id }) => id) - await lineItemServiceTx.cloneTo(lineItemIds, { - order_edit_id: orderEdit.id, - }) - - await this.eventBusService_ - .withTransaction(transactionManager) - .emit(OrderEditService.Events.CREATED, { id: orderEdit.id }) - - return orderEdit - }) - } - - async update( - orderEditId: string, - data: DeepPartial - ): Promise { - return await this.atomicPhase_(async (manager) => { - const orderEditRepo = manager.withRepository(this.orderEditRepository_) - - const orderEdit = await this.retrieve(orderEditId) - - for (const key of Object.keys(data)) { - if (isDefined(data[key])) { - orderEdit[key] = data[key] - } - } - - const result = await orderEditRepo.save(orderEdit) - - await this.eventBusService_ - .withTransaction(manager) - .emit(OrderEditService.Events.UPDATED, { - id: result.id, - }) - - return result - }) - } - - async delete(id: string): Promise { - return await this.atomicPhase_(async (manager) => { - const orderEditRepo = manager.withRepository(this.orderEditRepository_) - - const edit = await this.retrieve(id).catch(() => void 0) - - if (!edit) { - return - } - - if (edit.status !== OrderEditStatus.CREATED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Cannot delete order edit with status ${edit.status}` - ) - } - - await this.deleteClonedItems(id) - await orderEditRepo.remove(edit) - }) - } - - async decline( - orderEditId: string, - context: { - declinedReason?: string - declinedBy?: string - } - ): Promise { - return await this.atomicPhase_(async (manager) => { - const orderEditRepo = manager.withRepository(this.orderEditRepository_) - - const { declinedBy, declinedReason } = context - - const orderEdit = await this.retrieve(orderEditId) - - if (orderEdit.status === OrderEditStatus.DECLINED) { - return orderEdit - } - - if (orderEdit.status !== OrderEditStatus.REQUESTED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Cannot decline an order edit with status ${orderEdit.status}.` - ) - } - - orderEdit.declined_at = new Date() - orderEdit.declined_by = declinedBy - orderEdit.declined_reason = declinedReason - - const result = await orderEditRepo.save(orderEdit) - - await this.eventBusService_ - .withTransaction(manager) - .emit(OrderEditService.Events.DECLINED, { - id: result.id, - }) - - return result - }) - } - - /** - * Create or update order edit item change line item and apply the quantity - * - If the item change already exists then update the quantity of the line item as well as the line adjustments - * - If the item change does not exist then create the item change of type update and apply the quantity as well as update the line adjustments - * @param orderEditId - * @param itemId - * @param data - */ - async updateLineItem( - orderEditId: string, - itemId: string, - data: { quantity: number } - ): Promise { - return await this.atomicPhase_(async (manager) => { - const orderEdit = await this.retrieve(orderEditId, { - select: [ - "id", - "order_id", - "created_at", - "requested_at", - "confirmed_at", - "declined_at", - "canceled_at", - ], - }) - - const isOrderEditActive = OrderEditService.isOrderEditActive(orderEdit) - if (!isOrderEditActive) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Can not update an item on the order edit ${orderEditId} with the status ${orderEdit.status}` - ) - } - - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - - const lineItem = await lineItemServiceTx.retrieve(itemId, { - select: ["id", "order_edit_id", "original_item_id"], - }) - - if (lineItem.order_edit_id !== orderEditId) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Invalid line item id ${itemId} it does not belong to the same order edit ${orderEdit.order_id}.` - ) - } - - const orderEditItemChangeServiceTx = - this.orderEditItemChangeService_.withTransaction(manager) - - // Can be of type update or add - let change = ( - await orderEditItemChangeServiceTx.list( - { line_item_id: itemId }, - { - select: ["line_item_id", "original_line_item_id"], - } - ) - ).pop() - - // if a change does not exist it means that we are updating an existing item and therefore creating an update change. - // otherwise we are updating either a change of type ADD or UPDATE - if (!change) { - change = await orderEditItemChangeServiceTx.create({ - type: OrderEditItemChangeType.ITEM_UPDATE, - order_edit_id: orderEditId, - original_line_item_id: lineItem.original_item_id as string, - line_item_id: itemId, - }) - } - - await lineItemServiceTx.update(change.line_item_id!, { - quantity: data.quantity, - }) - - await this.refreshAdjustments(orderEditId, { - preserveCustomAdjustments: true, - }) - }) - } - - async removeLineItem(orderEditId: string, lineItemId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const orderEdit = await this.retrieve(orderEditId, { - select: [ - "id", - "created_at", - "requested_at", - "confirmed_at", - "declined_at", - "canceled_at", - ], - }) - - const isOrderEditActive = OrderEditService.isOrderEditActive(orderEdit) - - if (!isOrderEditActive) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Can not update an item on the order edit ${orderEditId} with the status ${orderEdit.status}` - ) - } - - const lineItem = await this.lineItemService_ - .withTransaction(manager) - .retrieve(lineItemId, { - select: ["id", "order_edit_id", "original_item_id"], - }) - .catch(() => void 0) - - if (!lineItem) { - return - } - - if ( - lineItem.order_edit_id !== orderEditId || - !lineItem.original_item_id - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Invalid line item id ${lineItemId} it does not belong to the same order edit ${orderEdit.order_id}.` - ) - } - - await this.lineItemService_ - .withTransaction(manager) - .deleteWithTaxLines(lineItem.id) - - await this.refreshAdjustments(orderEditId) - - await this.orderEditItemChangeService_.withTransaction(manager).create({ - original_line_item_id: lineItem.original_item_id, - type: OrderEditItemChangeType.ITEM_REMOVE, - order_edit_id: orderEdit.id, - }) - }) - } - - async refreshAdjustments( - orderEditId: string, - config = { preserveCustomAdjustments: false } - ) { - const lineItemAdjustmentServiceTx = - this.lineItemAdjustmentService_.withTransaction(this.activeManager_) - - const orderEdit = await this.retrieve(orderEditId, { - relations: [ - "items", - "items.variant", - "items.adjustments", - "items.tax_lines", - "order", - "order.customer", - "order.discounts", - "order.discounts.rule", - "order.gift_cards", - "order.region", - "order.shipping_address", - "order.shipping_methods", - ], - }) - - const clonedItemAdjustmentIds: string[] = [] - - orderEdit.items.forEach((item) => { - if (item.adjustments?.length) { - item.adjustments.forEach((adjustment) => { - const preserveAdjustment = config.preserveCustomAdjustments - ? !!adjustment.discount_id - : true - - if (preserveAdjustment) { - clonedItemAdjustmentIds.push(adjustment.id) - } - }) - } - }) - - await lineItemAdjustmentServiceTx.delete(clonedItemAdjustmentIds) - - const localCart = { - ...orderEdit.order, - object: "cart", - items: orderEdit.items, - } as unknown as Cart - - await lineItemAdjustmentServiceTx.createAdjustments(localCart) - } - - async decorateTotals(orderEdit: OrderEdit): Promise { - const { order_id, items } = await this.retrieve(orderEdit.id, { - select: ["id", "order_id", "items"], - relations: [ - "items", - "items.tax_lines", - "items.adjustments", - "items.variant", - ], - }) - - const orderServiceTx = this.orderService_.withTransaction( - this.activeManager_ - ) - - const order = await orderServiceTx.retrieve(order_id, { - relations: [ - "discounts", - "discounts.rule", - "gift_cards", - "region", - "items", - "items.tax_lines", - "items.adjustments", - "items.variant", - "region.tax_rates", - "shipping_methods", - "shipping_methods.shipping_option", - "shipping_methods.tax_lines", - ], - }) - - const computedOrder = { ...order, items } as Order - await promiseAll([ - await orderServiceTx.decorateTotals(computedOrder), - await orderServiceTx.decorateTotals(order), - ]) - - orderEdit.items = computedOrder.items - orderEdit.discount_total = computedOrder.discount_total - orderEdit.gift_card_total = computedOrder.gift_card_total - orderEdit.gift_card_tax_total = computedOrder.gift_card_tax_total - orderEdit.shipping_total = computedOrder.shipping_total - orderEdit.subtotal = computedOrder.subtotal - orderEdit.tax_total = computedOrder.tax_total - orderEdit.total = computedOrder.total - orderEdit.difference_due = computedOrder.total - order.total - - return orderEdit - } - - async addLineItem( - orderEditId: string, - data: AddOrderEditLineItemInput - ): Promise { - return await this.atomicPhase_(async (manager) => { - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - - const orderEdit = await this.retrieve(orderEditId, { - relations: ["order", "order.region"], - }) - - if (!OrderEditService.isOrderEditActive(orderEdit)) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Can not add an item to the edit with status ${orderEdit.status}` - ) - } - - const regionId = orderEdit.order.region_id - - /** - * Create new line item and refresh adjustments for all cloned order edit items - */ - - const lineItemData = await lineItemServiceTx.generate( - data.variant_id, - regionId, - data.quantity, - { - customer_id: orderEdit.order.customer_id, - metadata: data.metadata, - order_edit_id: orderEditId, - } - ) - - let lineItem = await lineItemServiceTx.create(lineItemData) - lineItem = await lineItemServiceTx.retrieve(lineItem.id, { - relations: ["variant.product.profiles"], - }) - - await this.refreshAdjustments(orderEditId) - - /** - * Generate a change record - */ - await this.orderEditItemChangeService_.withTransaction(manager).create({ - type: OrderEditItemChangeType.ITEM_ADD, - line_item_id: lineItem.id, - order_edit_id: orderEditId, - }) - - /** - * Compute tax lines - */ - const localCart = { - ...orderEdit.order, - object: "cart", - items: [lineItem], - } as unknown as Cart - - const calcContext = await this.totalsService_ - .withTransaction(manager) - .getCalculationContext(localCart, { - exclude_shipping: true, - }) - - await this.taxProviderService_ - .withTransaction(manager) - .createTaxLines([lineItem], calcContext) - }) - } - - async deleteItemChange( - orderEditId: string, - itemChangeId: string - ): Promise { - return await this.atomicPhase_(async (manager) => { - const itemChange = await this.orderEditItemChangeService_.retrieve( - itemChangeId, - { select: ["id", "order_edit_id"] } - ) - - const orderEdit = await this.retrieve(orderEditId, { - select: ["id", "confirmed_at", "canceled_at"], - }) - - if (orderEdit.id !== itemChange.order_edit_id) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `The item change you are trying to delete doesn't belong to the OrderEdit with id: ${orderEditId}.` - ) - } - - if (orderEdit.confirmed_at !== null || orderEdit.canceled_at !== null) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Cannot delete and item change from a ${orderEdit.status} order edit` - ) - } - - return await this.orderEditItemChangeService_.delete(itemChangeId) - }) - } - - async requestConfirmation( - orderEditId: string, - context: { - requestedBy?: string - } = {} - ): Promise { - return await this.atomicPhase_(async (manager) => { - const orderEditRepo = manager.withRepository(this.orderEditRepository_) - - let orderEdit = await this.retrieve(orderEditId, { - relations: [ - "changes", - "changes.original_line_item", - "changes.original_line_item.variant", - ], - select: ["id", "order_id", "requested_at"], - }) - - if (!orderEdit.changes?.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Cannot request a confirmation on an edit with no changes" - ) - } - - if (orderEdit.requested_at) { - return orderEdit - } - - orderEdit.requested_at = new Date() - orderEdit.requested_by = context.requestedBy - - orderEdit = await orderEditRepo.save(orderEdit) - - await this.eventBusService_ - .withTransaction(manager) - .emit(OrderEditService.Events.REQUESTED, { id: orderEditId }) - - return orderEdit - }) - } - - async cancel( - orderEditId: string, - context: { canceledBy?: string } = {} - ): Promise { - return await this.atomicPhase_(async (manager) => { - const orderEditRepository = manager.withRepository( - this.orderEditRepository_ - ) - - const orderEdit = await this.retrieve(orderEditId) - - if (orderEdit.status === OrderEditStatus.CANCELED) { - return orderEdit - } - - if ( - [OrderEditStatus.CONFIRMED, OrderEditStatus.DECLINED].includes( - orderEdit.status - ) - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Cannot cancel order edit with status ${orderEdit.status}` - ) - } - - orderEdit.canceled_at = new Date() - orderEdit.canceled_by = context.canceledBy - - const saved = await orderEditRepository.save(orderEdit) - - await this.eventBusService_ - .withTransaction(manager) - .emit(OrderEditService.Events.CANCELED, { id: orderEditId }) - - return saved - }) - } - - async confirm( - orderEditId: string, - context: { confirmedBy?: string } = {} - ): Promise { - return await this.atomicPhase_(async (manager) => { - const orderEditRepository = manager.withRepository( - this.orderEditRepository_ - ) - - let orderEdit = await this.retrieve(orderEditId) - - if ( - [OrderEditStatus.CANCELED, OrderEditStatus.DECLINED].includes( - orderEdit.status - ) - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Cannot confirm an order edit with status ${orderEdit.status}` - ) - } - - if (orderEdit.status === OrderEditStatus.CONFIRMED) { - return orderEdit - } - - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - - const [originalOrderLineItems] = await promiseAll([ - lineItemServiceTx.update( - [ - { order_id: orderEdit.order_id, order_edit_id: Not(orderEditId) }, - { order_id: orderEdit.order_id, order_edit_id: IsNull() }, - ], - { order_id: null } - ), - lineItemServiceTx.update( - { order_edit_id: orderEditId }, - { order_id: orderEdit.order_id } - ), - ]) - - orderEdit.confirmed_at = new Date() - orderEdit.confirmed_by = context.confirmedBy - - orderEdit = await orderEditRepository.save(orderEdit) - - if (this.inventoryService_) { - const itemsIds = originalOrderLineItems.map((i) => i.id) - await this.inventoryService_!.deleteReservationItemsByLineItem( - itemsIds, - { - transactionManager: manager, - } - ) - } - - await this.eventBusService_ - .withTransaction(manager) - .emit(OrderEditService.Events.CONFIRMED, { id: orderEditId }) - - return orderEdit - }) - } - - protected async retrieveActive( - orderId: string, - config: FindConfig = {} - ): Promise { - const orderEditRepository = this.activeManager_.withRepository( - this.orderEditRepository_ - ) - - const query = buildQuery( - { - order_id: orderId, - confirmed_at: IsNull(), - canceled_at: IsNull(), - declined_at: IsNull(), - }, - config - ) - return await orderEditRepository.findOne(query) - } - - protected async deleteClonedItems(orderEditId: string): Promise { - const lineItemServiceTx = this.lineItemService_.withTransaction( - this.activeManager_ - ) - const lineItemAdjustmentServiceTx = - this.lineItemAdjustmentService_.withTransaction(this.activeManager_) - const taxProviderServiceTs = this.taxProviderService_.withTransaction( - this.activeManager_ - ) - - const clonedLineItems = await lineItemServiceTx.list( - { - order_edit_id: orderEditId, - }, - { - select: ["id", "tax_lines", "adjustments"], - relations: ["tax_lines", "adjustments"], - } - ) - const clonedItemIds = clonedLineItems.map((item) => item.id) - - const orderEdit = await this.retrieve(orderEditId, { - select: ["id", "changes"], - relations: [ - "changes", - "changes.original_line_item", - "changes.original_line_item.variant", - ], - }) - - await this.orderEditItemChangeService_.delete( - orderEdit.changes.map((change) => change.id) - ) - - await promiseAll( - [ - taxProviderServiceTs.clearLineItemsTaxLines(clonedItemIds), - clonedItemIds.map(async (id) => { - return await lineItemAdjustmentServiceTx.delete({ - item_id: id, - }) - }), - ].flat() - ) - - await promiseAll( - clonedItemIds.map(async (id) => { - return await lineItemServiceTx.delete(id) - }) - ) - } - - private static isOrderEditActive(orderEdit: OrderEdit): boolean { - return !( - orderEdit.status === OrderEditStatus.CONFIRMED || - orderEdit.status === OrderEditStatus.CANCELED || - orderEdit.status === OrderEditStatus.DECLINED - ) - } -} diff --git a/packages/medusa/src/services/order.ts b/packages/medusa/src/services/order.ts deleted file mode 100644 index c72337c8d8..0000000000 --- a/packages/medusa/src/services/order.ts +++ /dev/null @@ -1,2113 +0,0 @@ -import { IInventoryService } from "@medusajs/types" -import { - buildRelations, - buildSelects, - FlagRouter, - isDefined, - MedusaError, - MedusaV2Flag, - promiseAll, selectorConstraintsToString, -} from "@medusajs/utils" -import { - EntityManager, - FindManyOptions, - FindOptionsWhere, - ILike, - IsNull, - Not, - Raw, -} from "typeorm" -import { - CartService, - CustomerService, - DiscountService, - DraftOrderService, - FulfillmentProviderService, - FulfillmentService, - GiftCardService, - LineItemService, - NewTotalsService, - PaymentProviderService, - ProductVariantInventoryService, - RegionService, - ShippingOptionService, - ShippingProfileService, - TaxProviderService, - TotalsService, -} from "." -import { TransactionBaseService } from "../interfaces" -import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels" -import { - Address, - Cart, - ClaimOrder, - Fulfillment, - FulfillmentItem, - FulfillmentStatus, - GiftCard, - LineItem, - Order, - OrderStatus, - Payment, - PaymentStatus, - Return, - Swap, - TrackingLink, -} from "../models" -import { AddressRepository } from "../repositories/address" -import { OrderRepository } from "../repositories/order" -import { FindConfig, QuerySelector, Selector } from "../types/common" -import { - CreateFulfillmentOrder, - FulFillmentItemType, -} from "../types/fulfillment" -import { TotalsContext, UpdateOrderInput } from "../types/orders" -import { CreateShippingMethodDto } from "../types/shipping-options" -import { buildQuery, isString, setMetadata } from "../utils" -import EventBusService from "./event-bus" -import { RemoteLink } from "@medusajs/modules-sdk" - -export const ORDER_CART_ALREADY_EXISTS_ERROR = "Order from cart already exists" - -type InjectedDependencies = { - manager: EntityManager - orderRepository: typeof OrderRepository - customerService: CustomerService - paymentProviderService: PaymentProviderService - shippingOptionService: ShippingOptionService - shippingProfileService: ShippingProfileService - discountService: DiscountService - fulfillmentProviderService: FulfillmentProviderService - fulfillmentService: FulfillmentService - lineItemService: LineItemService - totalsService: TotalsService - newTotalsService: NewTotalsService - taxProviderService: TaxProviderService - regionService: RegionService - cartService: CartService - addressRepository: typeof AddressRepository - giftCardService: GiftCardService - draftOrderService: DraftOrderService - inventoryService: IInventoryService - eventBusService: EventBusService - featureFlagRouter: FlagRouter - productVariantInventoryService: ProductVariantInventoryService - remoteLink: RemoteLink -} - -class OrderService extends TransactionBaseService { - static readonly Events = { - GIFT_CARD_CREATED: "order.gift_card_created", - PAYMENT_CAPTURED: "order.payment_captured", - PAYMENT_CAPTURE_FAILED: "order.payment_capture_failed", - SHIPMENT_CREATED: "order.shipment_created", - FULFILLMENT_CREATED: "order.fulfillment_created", - FULFILLMENT_CANCELED: "order.fulfillment_canceled", - RETURN_REQUESTED: "order.return_requested", - ITEMS_RETURNED: "order.items_returned", - RETURN_ACTION_REQUIRED: "order.return_action_required", - REFUND_CREATED: "order.refund_created", - REFUND_FAILED: "order.refund_failed", - SWAP_CREATED: "order.swap_created", - PLACED: "order.placed", - UPDATED: "order.updated", - CANCELED: "order.canceled", - COMPLETED: "order.completed", - } - - protected readonly orderRepository_: typeof OrderRepository - protected readonly customerService_: CustomerService - protected readonly paymentProviderService_: PaymentProviderService - protected readonly shippingOptionService_: ShippingOptionService - protected readonly shippingProfileService_: ShippingProfileService - protected readonly discountService_: DiscountService - protected readonly fulfillmentProviderService_: FulfillmentProviderService - protected readonly fulfillmentService_: FulfillmentService - protected readonly lineItemService_: LineItemService - protected readonly totalsService_: TotalsService - protected readonly newTotalsService_: NewTotalsService - protected readonly taxProviderService_: TaxProviderService - protected readonly regionService_: RegionService - protected readonly cartService_: CartService - protected readonly addressRepository_: typeof AddressRepository - protected readonly giftCardService_: GiftCardService - protected readonly draftOrderService_: DraftOrderService - protected readonly inventoryService_: IInventoryService - protected readonly eventBus_: EventBusService - protected readonly featureFlagRouter_: FlagRouter - protected remoteLink_: RemoteLink - // eslint-disable-next-line max-len - protected readonly productVariantInventoryService_: ProductVariantInventoryService - - constructor({ - orderRepository, - customerService, - paymentProviderService, - shippingOptionService, - shippingProfileService, - discountService, - fulfillmentProviderService, - fulfillmentService, - lineItemService, - totalsService, - newTotalsService, - taxProviderService, - regionService, - cartService, - remoteLink, - addressRepository, - giftCardService, - draftOrderService, - eventBusService, - featureFlagRouter, - productVariantInventoryService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.orderRepository_ = orderRepository - this.customerService_ = customerService - this.paymentProviderService_ = paymentProviderService - this.shippingProfileService_ = shippingProfileService - this.fulfillmentProviderService_ = fulfillmentProviderService - this.lineItemService_ = lineItemService - this.totalsService_ = totalsService - this.newTotalsService_ = newTotalsService - this.taxProviderService_ = taxProviderService - this.regionService_ = regionService - this.fulfillmentService_ = fulfillmentService - this.discountService_ = discountService - this.giftCardService_ = giftCardService - this.eventBus_ = eventBusService - this.shippingOptionService_ = shippingOptionService - this.cartService_ = cartService - this.addressRepository_ = addressRepository - this.draftOrderService_ = draftOrderService - this.featureFlagRouter_ = featureFlagRouter - this.productVariantInventoryService_ = productVariantInventoryService - this.remoteLink_ = remoteLink - } - - /** - * @param selector the query object for find - * @param config the config to be used for find - * @return the result of the find operation - */ - async list( - selector: Selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise { - const [orders] = await this.listAndCount(selector, config) - return orders - } - - /** - * @param {Object} selector - the query object for find - * @param {Object} config - the config to be used for find - * @return {Promise} the result of the find operation - */ - async listAndCount( - selector: QuerySelector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise<[Order[], number]> { - const orderRepo = this.activeManager_.withRepository(this.orderRepository_) - - let q - if (selector.q) { - q = selector.q - delete selector.q - - config.relations = config.relations - ? Array.from( - new Set([...config.relations, "shipping_address", "customer"]) - ) - : ["shipping_address", "customer"] - } - - const query = buildQuery(selector, config) as FindManyOptions - - if (q) { - const where = query.where as FindOptionsWhere - - delete where.display_id - delete where.email - - // Inner join like constraints - const innerJoinLikeConstraints = { - customer: { - id: Not(IsNull()), - }, - shipping_address: { - id: Not(IsNull()), - }, - } - - query.where = [ - { - ...query.where, - ...innerJoinLikeConstraints, - shipping_address: { - ...innerJoinLikeConstraints.shipping_address, - id: Not(IsNull()), - first_name: ILike(`%${q}%`), - }, - }, - { - ...query.where, - ...innerJoinLikeConstraints, - email: ILike(`%${q}%`), - }, - { - ...query.where, - ...innerJoinLikeConstraints, - display_id: Raw((alias) => `CAST(${alias} as varchar) ILike :q`, { - q: `%${q}%`, - }), - }, - { - ...query.where, - ...innerJoinLikeConstraints, - customer: { - ...innerJoinLikeConstraints.customer, - first_name: ILike(`%${q}%`), - }, - }, - { - ...query.where, - ...innerJoinLikeConstraints, - customer: { - ...innerJoinLikeConstraints.customer, - last_name: ILike(`%${q}%`), - }, - }, - { - ...query.where, - ...innerJoinLikeConstraints, - customer: { - ...innerJoinLikeConstraints.customer, - phone: ILike(`%${q}%`), - }, - }, - ] - } - - const { select, relations, totalsToSelect } = - this.transformQueryForTotals(config) - - query.select = buildSelects(select || []) - const rels = buildRelations(this.getTotalsRelations({ relations })) - - delete query.relations - - const raw = await orderRepo.findWithRelations(rels, query) - const count = await orderRepo.count(query) - const orders = await promiseAll( - raw.map(async (r) => await this.decorateTotals(r, totalsToSelect)) - ) - - return [orders, count] - } - - protected transformQueryForTotals(config: FindConfig): { - relations: string[] | undefined - select: FindConfig["select"] - totalsToSelect: FindConfig["select"] - } { - let { select, relations } = config - - if (!select) { - return { - select, - relations, - totalsToSelect: [], - } - } - - const totalFields = [ - "subtotal", - "tax_total", - "shipping_total", - "discount_total", - "gift_card_total", - "total", - "paid_total", - "refunded_total", - "refundable_amount", - "items.refundable", - "swaps.additional_items.refundable", - "claims.additional_items.refundable", - ] - - const totalsToSelect = select.filter((v) => totalFields.includes(v)) - if (totalsToSelect.length > 0) { - const relationSet = new Set(relations) - relationSet.add("items.tax_lines") - relationSet.add("items.adjustments") - relationSet.add("items.variant.product.profiles") - relationSet.add("swaps") - relationSet.add("swaps.additional_items") - relationSet.add("swaps.additional_items.tax_lines") - relationSet.add("swaps.additional_items.adjustments") - relationSet.add("claims") - relationSet.add("claims.additional_items") - relationSet.add("claims.additional_items.tax_lines") - relationSet.add("claims.additional_items.adjustments") - relationSet.add("discounts") - relationSet.add("discounts.rule") - relationSet.add("gift_cards") - relationSet.add("gift_card_transactions") - relationSet.add("gift_card_transactions.gift_card") - relationSet.add("refunds") - relationSet.add("shipping_methods") - relationSet.add("shipping_methods.tax_lines") - relationSet.add("region") - relations = [...relationSet] - - select = select.filter((v) => !totalFields.includes(v)) - } - - const toSelect = [...select] - if (toSelect.length > 0 && toSelect.indexOf("tax_rate") === -1) { - toSelect.push("tax_rate") - } - - return { - relations, - select: toSelect.length ? toSelect : undefined, - totalsToSelect, - } - } - - /** - * Gets an order by id. - * @param orderId - id or selector of order to retrieve - * @param config - config of order to retrieve - * @return the order document - */ - async retrieve( - orderId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(orderId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"orderId" must be defined` - ) - } - - const { totalsToSelect } = this.transformQueryForTotals(config) - - if (totalsToSelect?.length) { - return await this.retrieveLegacy(orderId, config) - } - - const orderRepo = this.activeManager_.withRepository(this.orderRepository_) - - const query = buildQuery({ id: orderId }, config) - - if (!(config.select || []).length) { - query.select = undefined - } - - const queryRelations = { ...query.relations } - delete query.relations - - const raw = await orderRepo.findOneWithRelations(queryRelations, query) - - if (!raw) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Order with id ${orderId} was not found` - ) - } - - return raw - } - - protected async retrieveLegacy( - orderIdOrSelector: string | Selector, - config: FindConfig = {} - ): Promise { - const orderRepo = this.activeManager_.withRepository(this.orderRepository_) - - const { select, relations, totalsToSelect } = - this.transformQueryForTotals(config) - - const selector = isString(orderIdOrSelector) - ? { id: orderIdOrSelector } - : orderIdOrSelector - - const query = buildQuery(selector, config) - - if (relations && relations.length > 0) { - query.relations = buildRelations(relations) - } - - query.select = select?.length ? buildSelects(select) : undefined - - const rels = query.relations - delete query.relations - - const raw = await orderRepo.findOneWithRelations(rels, query) - - if (!raw) { - const selectorConstraints = selectorConstraintsToString(selector) - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Order with ${selectorConstraints} was not found` - ) - } - - return await this.decorateTotals(raw, totalsToSelect) - } - - async retrieveWithTotals( - orderId: string, - options: FindConfig = {}, - context: TotalsContext = {} - ): Promise { - const relations = this.getTotalsRelations(options) - const order = await this.retrieve(orderId, { ...options, relations }) - - return await this.decorateTotals(order, context) - } - - /** - * Gets an order by cart id. - * @param cartId - cart id to find order - * @param config - the config to be used to find order - * @return the order document - */ - async retrieveByCartId( - cartId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(cartId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"cartId" must be defined` - ) - } - - const orderRepo = this.activeManager_.withRepository(this.orderRepository_) - - const query = buildQuery({ cart_id: cartId }, config) - - if (!(config.select || []).length) { - query.select = undefined - } - - const queryRelations = { ...query.relations } - delete query.relations - - const raw = await orderRepo.findOneWithRelations(queryRelations, query) - - if (!raw) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Order with cart id ${cartId} was not found` - ) - } - - return raw - } - - async retrieveByCartIdWithTotals( - cartId: string, - options: FindConfig = {} - ): Promise { - const relations = this.getTotalsRelations(options) - const order = await this.retrieveByCartId(cartId, { ...options, relations }) - return await this.decorateTotals(order, {}) - } - - /** - * Gets an order by id. - * @param externalId - id of order to retrieve - * @param config - query config to get order by - * @return the order document - */ - async retrieveByExternalId( - externalId: string, - config: FindConfig = {} - ): Promise { - const orderRepo = this.activeManager_.withRepository(this.orderRepository_) - - const { select, relations, totalsToSelect } = - this.transformQueryForTotals(config) - - const selector = { - where: { external_id: externalId }, - } - - let queryRelations - if (relations && relations.length > 0) { - queryRelations = relations - } - queryRelations = this.getTotalsRelations({ relations: queryRelations }) - - const querySelect = select?.length ? select : undefined - - const query = buildQuery(selector, { - select: querySelect, - relations: queryRelations, - } as FindConfig) - - const rels = { ...query.relations } - delete query.relations - - const raw = await orderRepo.findOneWithRelations(rels, query) - if (!raw) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Order with external id ${externalId} was not found` - ) - } - - return await this.decorateTotals(raw, totalsToSelect) - } - - /** - * @param orderId - id of the order to complete - * @return the result of the find operation - */ - async completeOrder(orderId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const order = await this.retrieve(orderId) - - if (order.status === "canceled") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "A canceled order cannot be completed" - ) - } - - await this.eventBus_ - .withTransaction(manager) - .emit(OrderService.Events.COMPLETED, { - id: orderId, - no_notification: order.no_notification, - }) - - order.status = OrderStatus.COMPLETED - - const orderRepo = manager.withRepository(this.orderRepository_) - return orderRepo.save(order) - }) - } - - /** - * Creates an order from a cart - * @return resolves to the creation result. - * @param cartOrId - */ - async createFromCart(cartOrId: string | Cart): Promise { - return await this.atomicPhase_(async (manager) => { - const cartServiceTx = this.cartService_.withTransaction(manager) - - const exists = !!(await this.retrieveByCartId( - isString(cartOrId) ? cartOrId : cartOrId?.id, - { - select: ["id"], - } - ).catch(() => void 0)) - - if (exists) { - throw new MedusaError( - MedusaError.Types.DUPLICATE_ERROR, - ORDER_CART_ALREADY_EXISTS_ERROR - ) - } - - const cart = isString(cartOrId) - ? await cartServiceTx.retrieveWithTotals(cartOrId, { - relations: ["region", "payment", "items"], - }) - : cartOrId - - if (cart.items.length === 0) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Cannot create order from empty cart" - ) - } - - if (!cart.customer_id) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Cannot create an order from the cart without a customer" - ) - } - - const { payment, region, total } = cart - - // Would be the case if a discount code is applied that covers the item - // total - if (total !== 0) { - if (!payment) { - throw new MedusaError( - MedusaError.Types.INVALID_ARGUMENT, - "Cart does not contain a payment method" - ) - } - - const paymentStatus = await this.paymentProviderService_ - .withTransaction(manager) - .getStatus(payment) - - if (paymentStatus !== "authorized") { - throw new MedusaError( - MedusaError.Types.INVALID_ARGUMENT, - "Payment method is not authorized" - ) - } - } - - const orderRepo = manager.withRepository(this.orderRepository_) - - // TODO: Due to cascade insert we have to remove the tax_lines that have been added by the cart decorate totals. - // Is the cascade insert really used? Also, is it really necessary to pass the entire entities when creating or updating? - // We normally should only pass what is needed? - const shippingMethods = cart.shipping_methods.map((method) => { - ;(method.tax_lines as any) = undefined - return method - }) - - const toCreate = { - payment_status: "awaiting", - discounts: cart.discounts, - gift_cards: cart.gift_cards, - shipping_methods: shippingMethods, - shipping_address_id: cart.shipping_address_id, - billing_address_id: cart.billing_address_id, - region_id: cart.region_id, - email: cart.email, - customer_id: cart.customer_id, - cart_id: cart.id, - currency_code: region.currency_code, - metadata: cart.metadata || {}, - } as Partial - - if ( - cart.sales_channel_id && - this.featureFlagRouter_.isFeatureEnabled(SalesChannelFeatureFlag.key) && - !this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key) - ) { - toCreate.sales_channel_id = cart.sales_channel_id - } - - if (cart.type === "draft_order") { - const draft = await this.draftOrderService_ - .withTransaction(manager) - .retrieveByCartId(cart.id) - - toCreate.draft_order_id = draft.id - toCreate.no_notification = draft.no_notification_order - } - - const rawOrder = orderRepo.create(toCreate) - const order = await orderRepo.save(rawOrder) - - if ( - this.featureFlagRouter_.isFeatureEnabled([ - SalesChannelFeatureFlag.key, - MedusaV2Flag.key, - ]) - ) { - await this.remoteLink_.create({ - orderService: { - order_id: order.id, - }, - salesChannelService: { - sales_channel_id: cart.sales_channel_id as string, - }, - }) - } - - if (total !== 0 && payment) { - await this.paymentProviderService_ - .withTransaction(manager) - .updatePayment(payment.id, { - order_id: order.id, - }) - } - - if (!isDefined(cart.subtotal) || !isDefined(cart.discount_total)) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Unable to compute gift cardable amount during order creation from cart. The cart is missing the subtotal and/or discount_total" - ) - } - - let giftCardableAmountBalance = cart.gift_card_total ?? 0 - - const giftCardService = this.giftCardService_.withTransaction(manager) - - // Order the gift cards by first ends_at date, then remaining amount. To ensure largest possible amount left, for longest possible time. - const orderedGiftCards = cart.gift_cards.sort((a, b) => { - const aEnd = a.ends_at ?? new Date(2100, 1, 1) - const bEnd = b.ends_at ?? new Date(2100, 1, 1) - return aEnd.getTime() - bEnd.getTime() || a.balance - b.balance - }) - - for (const giftCard of orderedGiftCards) { - const newGiftCardBalance = Math.max( - 0, - giftCard.balance - giftCardableAmountBalance - ) - const giftCardBalanceUsed = giftCard.balance - newGiftCardBalance - - await giftCardService.update(giftCard.id, { - balance: newGiftCardBalance, - is_disabled: newGiftCardBalance === 0, - }) - - await giftCardService.createTransaction({ - gift_card_id: giftCard.id, - order_id: order.id, - amount: giftCardBalanceUsed, - is_taxable: !!giftCard.tax_rate, - tax_rate: giftCard.tax_rate, - }) - - giftCardableAmountBalance = - giftCardableAmountBalance - giftCardBalanceUsed - - if (giftCardableAmountBalance == 0) { - break - } - } - - const shippingOptionServiceTx = - this.shippingOptionService_.withTransaction(manager) - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - - await promiseAll( - [ - cart.items.map((lineItem): Promise[] => { - const toReturn: Promise[] = [ - lineItemServiceTx.update(lineItem.id, { order_id: order.id }), - ] - - if (lineItem.is_giftcard) { - toReturn.push( - ...this.createGiftCardsFromLineItem_(order, lineItem, manager) - ) - } - - return toReturn - }), - cart.shipping_methods.map(async (method): Promise => { - // TODO: Due to cascade insert we have to remove the tax_lines that have been added by the cart decorate totals. - // Is the cascade insert really used? Also, is it really necessary to pass the entire entities when creating or updating? - // We normally should only pass what is needed? - ;(method.tax_lines as any) = undefined - return shippingOptionServiceTx.updateShippingMethod(method.id, { - order_id: order.id, - }) - }), - ].flat(Infinity) - ) - - await this.eventBus_ - .withTransaction(manager) - .emit(OrderService.Events.PLACED, { - id: order.id, - no_notification: order.no_notification, - }) - - await cartServiceTx.update(cart.id, { completed_at: new Date() }) - - return order - }) - } - - protected createGiftCardsFromLineItem_( - order: Order, - lineItem: LineItem, - manager: EntityManager - ): Promise[] { - const createGiftCardPromises: Promise[] = [] - - // LineItem type doesn't promise either the subtotal or quantity. Adding a check here provides - // additional type safety/strictness - if (!lineItem.subtotal || !lineItem.quantity) { - return createGiftCardPromises - } - - // Subtotal is the pure value of the product/variant excluding tax, discounts, etc. - // We divide here by quantity to get the value of the product/variant as a lineItem - // contains quantity. The subtotal is multiplicative of pure price per product and quantity - const taxExclusivePrice = lineItem.subtotal / lineItem.quantity - // The tax_lines contains all the taxes that is applicable on the purchase of the gift card - // On utilizing the gift card, the same set of taxRate will apply to gift card - // We calculate the summation of all taxes and add that as a snapshot in the giftcard.tax_rate column - const giftCardTaxRate = lineItem.tax_lines.reduce( - (sum, taxLine) => sum + taxLine.rate, - 0 - ) - - const giftCardTxnService = this.giftCardService_.withTransaction(manager) - - for (let qty = 0; qty < lineItem.quantity; qty++) { - const createGiftCardPromise = giftCardTxnService.create({ - region_id: order.region_id, - order_id: order.id, - value: taxExclusivePrice, - balance: taxExclusivePrice, - metadata: lineItem.metadata, - tax_rate: giftCardTaxRate || null, - }) - - createGiftCardPromises.push(createGiftCardPromise) - } - - return createGiftCardPromises - } - - /** - * Adds a shipment to the order to indicate that an order has left the - * warehouse. Will ask the fulfillment provider for any documents that may - * have been created in regards to the shipment. - * @param orderId - the id of the order that has been shipped - * @param fulfillmentId - the fulfillment that has now been shipped - * @param trackingLinks - array of tracking numbers associated with the shipment - * @param config - the config of the order that has been shipped - * @return the resulting order following the update. - */ - async createShipment( - orderId: string, - fulfillmentId: string, - trackingLinks?: TrackingLink[], - config: { - no_notification?: boolean - metadata: Record - } = { - metadata: {}, - no_notification: undefined, - } - ): Promise { - const { metadata, no_notification } = config - - return await this.atomicPhase_(async (manager) => { - const order = await this.retrieve(orderId, { relations: ["items"] }) - const shipment = await this.fulfillmentService_ - .withTransaction(manager) - .retrieve(fulfillmentId) - - if (order.status === "canceled") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "A canceled order cannot be fulfilled as shipped" - ) - } - - if (!shipment || shipment.order_id !== orderId) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - "Could not find fulfillment" - ) - } - - const evaluatedNoNotification = - no_notification !== undefined - ? no_notification - : shipment.no_notification - - const shipmentRes = await this.fulfillmentService_ - .withTransaction(manager) - .createShipment(fulfillmentId, trackingLinks, { - metadata, - no_notification: evaluatedNoNotification, - }) - - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - - order.fulfillment_status = FulfillmentStatus.SHIPPED - for (const item of order.items) { - const shipped = shipmentRes.items.find((si) => si.item_id === item.id) - if (shipped) { - const shippedQty = (item.shipped_quantity || 0) + shipped.quantity - if (shippedQty !== item.quantity) { - order.fulfillment_status = FulfillmentStatus.PARTIALLY_SHIPPED - } - - await lineItemServiceTx.update(item.id, { - shipped_quantity: shippedQty, - }) - } else { - if (item.shipped_quantity !== item.quantity) { - order.fulfillment_status = FulfillmentStatus.PARTIALLY_SHIPPED - } - } - } - - const orderRepo = manager.withRepository(this.orderRepository_) - const result = await orderRepo.save(order) - - await this.eventBus_ - .withTransaction(manager) - .emit(OrderService.Events.SHIPMENT_CREATED, { - id: orderId, - fulfillment_id: shipmentRes.id, - no_notification: evaluatedNoNotification, - }) - - return result - }) - } - - /** - * Updates the order's billing address. - * @param order - the order to update - * @param address - the value to set the billing address to - * @return the result of the update operation - */ - protected async updateBillingAddress( - order: Order, - address: Address - ): Promise { - const addrRepo = this.activeManager_.withRepository(this.addressRepository_) - address.country_code = address.country_code?.toLowerCase() ?? null - - const region = await this.regionService_ - .withTransaction(this.activeManager_) - .retrieve(order.region_id, { - relations: ["countries"], - }) - - if (!region.countries.find(({ iso_2 }) => address.country_code === iso_2)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Shipping country must be in the order region" - ) - } - - address.country_code = address.country_code?.toLowerCase() ?? null - - if (order.billing_address_id) { - const addr = await addrRepo.findOne({ - where: { id: order.billing_address_id }, - }) - - if (address.metadata) { - address.metadata = setMetadata(addr, address.metadata) - } - - await addrRepo.save({ ...addr, ...address }) - } else { - if (address.metadata) { - address.metadata = setMetadata(null, address.metadata) - } - - order.billing_address = addrRepo.create({ ...address }) - } - } - - /** - * Updates the order's shipping address. - * @param order - the order to update - * @param address - the value to set the shipping address to - * @return the result of the update operation - */ - protected async updateShippingAddress( - order: Order, - address: Address - ): Promise { - const addrRepo = this.activeManager_.withRepository(this.addressRepository_) - address.country_code = address.country_code?.toLowerCase() ?? null - - const region = await this.regionService_ - .withTransaction(this.activeManager_) - .retrieve(order.region_id, { - relations: ["countries"], - }) - - if (!region.countries.find(({ iso_2 }) => address.country_code === iso_2)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Shipping country must be in the order region" - ) - } - - if (order.shipping_address_id) { - const addr = await addrRepo.findOne({ - where: { id: order.shipping_address_id }, - }) - - await addrRepo.save({ ...addr, ...address }) - } else { - order.shipping_address = addrRepo.create({ ...address }) - } - } - - async addShippingMethod( - orderId: string, - optionId: string, - data?: Record, - config: CreateShippingMethodDto = {} - ): Promise { - return await this.atomicPhase_(async (manager) => { - const order = await this.retrieveWithTotals(orderId, { - relations: [ - "shipping_methods", - "shipping_methods.shipping_option", - "items.variant.product.profiles", - ], - }) - const { shipping_methods } = order - - if (order.status === "canceled") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "A shipping method cannot be added to a canceled order" - ) - } - - const newMethod = await this.shippingOptionService_ - .withTransaction(manager) - .createShippingMethod(optionId, data ?? {}, { order, ...config }) - - const shippingOptionServiceTx = - this.shippingOptionService_.withTransaction(manager) - - const methods = [newMethod] - if (shipping_methods.length) { - for (const sm of shipping_methods) { - if ( - sm.shipping_option.profile_id === - newMethod.shipping_option.profile_id - ) { - await shippingOptionServiceTx.deleteShippingMethods(sm) - } else { - methods.push(sm) - } - } - } - - const result = await this.retrieve(orderId) - await this.eventBus_ - .withTransaction(manager) - .emit(OrderService.Events.UPDATED, { id: result.id }) - return result - }) - } - - /** - * Updates an order. Metadata updates should - * use dedicated method, e.g. `setMetadata` etc. The function - * will throw errors if metadata updates are attempted. - * @param orderId - the id of the order. Must be a string that - * can be casted to an ObjectId - * @param update - an object with the update values. - * @return resolves to the update result. - */ - async update(orderId: string, update: UpdateOrderInput): Promise { - return await this.atomicPhase_(async (manager) => { - const order = await this.retrieve(orderId) - - if (order.status === "canceled") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "A canceled order cannot be updated" - ) - } - - if ( - (update.payment || update.items) && - (order.fulfillment_status !== "not_fulfilled" || - order.payment_status !== "awaiting" || - order.status !== "pending") - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Can't update shipping, billing, items and payment method when order is processed" - ) - } - - if (update.status || update.fulfillment_status || update.payment_status) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Can't update order statuses. This will happen automatically. Use metadata in order for additional statuses" - ) - } - - const { - metadata, - shipping_address, - billing_address, - no_notification, - items, - ...rest - } = update - - if (update.metadata) { - order.metadata = setMetadata(order, metadata ?? {}) - } - - if (update.shipping_address) { - await this.updateShippingAddress(order, shipping_address as Address) - } - - if (update.billing_address) { - await this.updateBillingAddress(order, billing_address as Address) - } - - if (update.no_notification) { - order.no_notification = no_notification ?? false - } - - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - if (update.items) { - for (const item of items as LineItem[]) { - await lineItemServiceTx.create({ - ...item, - order_id: orderId, - }) - } - } - - for (const [key, value] of Object.entries(rest)) { - order[key] = value - } - - const orderRepo = manager.withRepository(this.orderRepository_) - const result = await orderRepo.save(order) - - await this.eventBus_ - .withTransaction(manager) - .emit(OrderService.Events.UPDATED, { - id: orderId, - no_notification: order.no_notification, - }) - return result - }) - } - - /** - * Cancels an order. - * Throws if fulfillment process has been initiated. - * Throws if payment process has been initiated. - * @param orderId - id of order to cancel. - * @return result of the update operation. - */ - async cancel(orderId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const order = await this.retrieve(orderId, { - relations: [ - "refunds", - "fulfillments", - "payments", - "returns", - "claims", - "swaps", - "items", - ], - }) - - if (order.refunds?.length > 0) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Order with refund(s) cannot be canceled" - ) - } - - const throwErrorIf = ( - arr: (Fulfillment | Return | Swap | ClaimOrder)[], - pred: (obj: Fulfillment | Return | Swap | ClaimOrder) => boolean, - type: string - ): void | never => { - if (arr?.filter(pred).length) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `All ${type} must be canceled before canceling an order` - ) - } - } - - const notCanceled = (o): boolean => !o.canceled_at - - throwErrorIf(order.fulfillments, notCanceled, "fulfillments") - throwErrorIf( - order.returns, - (r) => (r as Return).status !== "canceled", - "returns" - ) - throwErrorIf(order.swaps, notCanceled, "swaps") - throwErrorIf(order.claims, notCanceled, "claims") - - const inventoryServiceTx = - this.productVariantInventoryService_.withTransaction(manager) - - await promiseAll( - order.items.map(async (item) => { - if (item.variant_id) { - return await inventoryServiceTx.deleteReservationsByLineItem( - item.id, - item.variant_id, - item.quantity - ) - } - }) - ) - - const paymentProviderServiceTx = - this.paymentProviderService_.withTransaction(manager) - for (const p of order.payments) { - await paymentProviderServiceTx.cancelPayment(p) - } - - order.status = OrderStatus.CANCELED - order.fulfillment_status = FulfillmentStatus.CANCELED - order.payment_status = PaymentStatus.CANCELED - order.canceled_at = new Date() - - const orderRepo = manager.withRepository(this.orderRepository_) - const result = await orderRepo.save(order) - - await this.eventBus_ - .withTransaction(manager) - .emit(OrderService.Events.CANCELED, { - id: order.id, - no_notification: order.no_notification, - }) - return result - }) - } - - /** - * Captures payment for an order. - * @param orderId - id of order to capture payment for. - * @return result of the update operation. - */ - async capturePayment(orderId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const orderRepo = manager.withRepository(this.orderRepository_) - const order = await this.retrieve(orderId, { relations: ["payments"] }) - - if (order.status === "canceled") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "A canceled order cannot capture payment" - ) - } - - const paymentProviderServiceTx = - this.paymentProviderService_.withTransaction(manager) - - const payments: Payment[] = [] - for (const p of order.payments) { - if (p.captured_at === null) { - const result = await paymentProviderServiceTx - .capturePayment(p) - .catch(async (err) => { - await this.eventBus_ - .withTransaction(manager) - .emit(OrderService.Events.PAYMENT_CAPTURE_FAILED, { - id: orderId, - payment_id: p.id, - error: err, - no_notification: order.no_notification, - }) - }) - - if (result) { - payments.push(result) - } else { - payments.push(p) - } - } else { - payments.push(p) - } - } - - order.payments = payments - order.payment_status = payments.every((p) => p.captured_at !== null) - ? PaymentStatus.CAPTURED - : PaymentStatus.REQUIRES_ACTION - - const result = await orderRepo.save(order) - - if (order.payment_status === PaymentStatus.CAPTURED) { - await this.eventBus_ - .withTransaction(manager) - .emit(OrderService.Events.PAYMENT_CAPTURED, { - id: result.id, - no_notification: order.no_notification, - }) - } - - return result - }) - } - - /** - * Checks that a given quantity of a line item can be fulfilled. Fails if the - * fulfillable quantity is lower than the requested fulfillment quantity. - * Fulfillable quantity is calculated by subtracting the already fulfilled - * quantity from the quantity that was originally purchased. - * @param item - the line item to check has sufficient fulfillable - * quantity. - * @param quantity - the quantity that is requested to be fulfilled. - * @return a line item that has the requested fulfillment quantity - * set. - */ - protected validateFulfillmentLineItem( - item: LineItem, - quantity: number - ): LineItem | null { - if (!item) { - // This will in most cases be called by a webhook so to ensure that - // things go through smoothly in instances where extra items outside - // of Medusa are added we allow unknown items - return null - } - - if (quantity > item.quantity - item.fulfilled_quantity!) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot fulfill more items than have been purchased" - ) - } - return { - ...item, - quantity, - } as LineItem - } - - /** - * Creates fulfillments for an order. - * In a situation where the order has more than one shipping method, - * we need to partition the order items, such that they can be sent - * to their respective fulfillment provider. - * @param orderId - id of order to fulfil. - * @param itemsToFulfill - items to fulfil. - * @param config - the config to fulfil. - * @return result of the update operation. - */ - async createFulfillment( - orderId: string, - itemsToFulfill: FulFillmentItemType[], - config: { - no_notification?: boolean - location_id?: string - metadata?: Record - } = {} - ): Promise { - const { metadata, no_notification, location_id } = config - - return await this.atomicPhase_(async (manager) => { - // NOTE: we are telling the service to calculate all totals for us which - // will add to what is fetched from the database. We want this to happen - // so that we get all order details. These will thereafter be forwarded - // to the fulfillment provider. - const order = await this.retrieve(orderId, { - select: [ - "subtotal", - "shipping_total", - "discount_total", - "tax_total", - "gift_card_total", - "total", - ], - relations: [ - "discounts", - "discounts.rule", - "region", - "fulfillments", - "shipping_address", - "billing_address", - "shipping_methods", - "shipping_methods.shipping_option", - "items.adjustments", - "items.variant.product.profiles", - "payments", - ], - }) - - if (order.status === OrderStatus.CANCELED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "A canceled order cannot be fulfilled" - ) - } - - if (!order.shipping_methods?.length) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot fulfill an order that lacks shipping methods" - ) - } - - const fulfillments = await this.fulfillmentService_ - .withTransaction(manager) - .createFulfillment( - order as unknown as CreateFulfillmentOrder, - itemsToFulfill, - { - metadata: metadata ?? {}, - no_notification: no_notification, - order_id: orderId, - location_id: location_id, - } - ) - let successfullyFulfilled: FulfillmentItem[] = [] - for (const f of fulfillments) { - successfullyFulfilled = [...successfullyFulfilled, ...f.items] - } - - order.fulfillment_status = FulfillmentStatus.FULFILLED - - // Update all line items to reflect fulfillment - for (const item of order.items) { - const fulfillmentItem = successfullyFulfilled.find( - (f) => item.id === f.item_id - ) - - if (fulfillmentItem) { - const fulfilledQuantity = - (item.fulfilled_quantity || 0) + fulfillmentItem.quantity - - // Update the fulfilled quantity - await this.lineItemService_.withTransaction(manager).update(item.id, { - fulfilled_quantity: fulfilledQuantity, - }) - - if (item.quantity !== fulfilledQuantity) { - order.fulfillment_status = FulfillmentStatus.PARTIALLY_FULFILLED - } - } else { - if (item.quantity !== item.fulfilled_quantity) { - order.fulfillment_status = FulfillmentStatus.PARTIALLY_FULFILLED - } - } - } - const orderRepo = manager.withRepository(this.orderRepository_) - - order.fulfillments = [...order.fulfillments, ...fulfillments] - - const result = await orderRepo.save(order) - - const evaluatedNoNotification = - no_notification !== undefined ? no_notification : order.no_notification - - const eventsToEmit = fulfillments.map((fulfillment) => ({ - eventName: OrderService.Events.FULFILLMENT_CREATED, - data: { - id: orderId, - fulfillment_id: fulfillment.id, - no_notification: evaluatedNoNotification, - }, - })) - await this.eventBus_.withTransaction(manager).emit(eventsToEmit) - - return result - }) - } - - /** - * Cancels a fulfillment (if related to an order) - * @param fulfillmentId - the ID of the fulfillment to cancel - * @return updated order - */ - async cancelFulfillment(fulfillmentId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const canceled = await this.fulfillmentService_ - .withTransaction(manager) - .cancelFulfillment(fulfillmentId) - - if (!canceled.order_id) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Fufillment not related to an order` - ) - } - - const order = await this.retrieve(canceled.order_id) - - order.fulfillment_status = FulfillmentStatus.CANCELED - - const orderRepo = manager.withRepository(this.orderRepository_) - const updated = await orderRepo.save(order) - - await this.eventBus_ - .withTransaction(manager) - .emit(OrderService.Events.FULFILLMENT_CANCELED, { - id: order.id, - fulfillment_id: canceled.id, - no_notification: canceled.no_notification, - }) - - return updated - }) - } - - /** - * Retrieves the order line items, given an array of items. - * @param order - the order to get line items from - * @param items - the items to get - * @param transformer - a function to apply to each of the items - * retrieved from the order, should return a line item. If the transformer - * returns an undefined value the line item will be filtered from the - * returned array. - * @return the line items generated by the transformer. - */ - protected async getFulfillmentItems( - order: Order, - items: FulFillmentItemType[], - transformer: (item: LineItem | undefined, quantity: number) => unknown - ): Promise { - return ( - await promiseAll( - items.map(async ({ item_id, quantity }) => { - const item = order.items.find((i) => i.id === item_id) - return transformer(item, quantity) - }) - ) - ).filter((i) => !!i) as LineItem[] - } - - /** - * Archives an order. It only alloved, if the order has been fulfilled - * and payment has been captured. - * @param orderId - the order to archive - * @return the result of the update operation - */ - async archive(orderId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const order = await this.retrieve(orderId) - - if (order.status !== ("completed" || "refunded")) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Can't archive an unprocessed order" - ) - } - - order.status = OrderStatus.ARCHIVED - const orderRepo = manager.withRepository(this.orderRepository_) - return await orderRepo.save(order) - }) - } - - /** - * Refunds a given amount back to the customer. - * @param orderId - id of the order to refund. - * @param refundAmount - the amount to refund. - * @param reason - the reason to refund. - * @param note - note for refund. - * @param config - the config for refund. - * @return the result of the refund operation. - */ - async createRefund( - orderId: string, - refundAmount: number, - reason: string, - note?: string, - config: { no_notification?: boolean } = { - no_notification: undefined, - } - ): Promise { - const { no_notification } = config - - return await this.atomicPhase_(async (manager) => { - const orderRepo = manager.withRepository(this.orderRepository_) - - const order = await this.retrieve(orderId, { - select: ["refundable_amount", "total", "refunded_total"], - relations: ["payments"], - }) - - if (order.status === "canceled") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "A canceled order cannot be refunded" - ) - } - - if (refundAmount > order.refundable_amount) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot refund more than the original order amount" - ) - } - - const refund = await this.paymentProviderService_ - .withTransaction(manager) - .refundPayment(order.payments, refundAmount, reason, note) - - let result = await this.retrieveWithTotals(orderId, { - relations: ["payments"], - }) - - if (result.refunded_total > 0 && result.refundable_amount > 0) { - result.payment_status = PaymentStatus.PARTIALLY_REFUNDED - result = await orderRepo.save(result) - } - - if ( - result.paid_total > 0 && - result.refunded_total === result.paid_total - ) { - result.payment_status = PaymentStatus.REFUNDED - result = await orderRepo.save(result) - } - - const evaluatedNoNotification = - no_notification !== undefined ? no_notification : order.no_notification - - await this.eventBus_ - .withTransaction(manager) - .emit(OrderService.Events.REFUND_CREATED, { - id: result.id, - refund_id: refund.id, - no_notification: evaluatedNoNotification, - }) - return result - }) - } - - protected async decorateTotalsLegacy( - order: Order, - totalsFields: string[] = [] - ): Promise { - if (totalsFields.some((field) => ["subtotal", "total"].includes(field))) { - const calculationContext = - await this.totalsService_.getCalculationContext(order, { - exclude_shipping: true, - }) - order.items = await promiseAll( - (order.items || []).map(async (item) => { - const itemTotals = await this.totalsService_.getLineItemTotals( - item, - order, - { - include_tax: true, - calculation_context: calculationContext, - } - ) - - return Object.assign(item, itemTotals) - }) - ) - } - - for (const totalField of totalsFields) { - switch (totalField) { - case "shipping_total": { - order.shipping_total = await this.totalsService_.getShippingTotal( - order - ) - break - } - case "gift_card_total": { - const giftCardBreakdown = await this.totalsService_.getGiftCardTotal( - order - ) - order.gift_card_total = giftCardBreakdown.total - order.gift_card_tax_total = giftCardBreakdown.tax_total - break - } - case "discount_total": { - order.discount_total = await this.totalsService_.getDiscountTotal( - order - ) - break - } - case "tax_total": { - order.tax_total = await this.totalsService_.getTaxTotal(order) - break - } - case "subtotal": { - order.subtotal = await this.totalsService_.getSubtotal(order) - break - } - case "total": { - order.total = await this.totalsService_ - .withTransaction(this.activeManager_) - .getTotal(order) - break - } - case "refunded_total": { - order.refunded_total = this.totalsService_.getRefundedTotal(order) - break - } - case "paid_total": { - order.paid_total = this.totalsService_.getPaidTotal(order) - break - } - case "refundable_amount": { - const paid_total = this.totalsService_.getPaidTotal(order) - const refunded_total = this.totalsService_.getRefundedTotal(order) - order.refundable_amount = paid_total - refunded_total - break - } - case "items.refundable": { - const items: LineItem[] = [] - for (const item of order.items) { - items.push({ - ...item, - refundable: await this.totalsService_.getLineItemRefund(order, { - ...item, - quantity: item.quantity - (item.returned_quantity || 0), - } as LineItem), - } as LineItem) - } - order.items = items - break - } - case "swaps.additional_items.refundable": { - for (const s of order.swaps) { - const items: LineItem[] = [] - for (const item of s.additional_items) { - items.push({ - ...item, - refundable: await this.totalsService_.getLineItemRefund(order, { - ...item, - quantity: item.quantity - (item.returned_quantity || 0), - } as LineItem), - } as LineItem) - } - s.additional_items = items - } - break - } - case "claims.additional_items.refundable": { - for (const c of order.claims) { - const items: LineItem[] = [] - for (const item of c.additional_items) { - items.push({ - ...item, - refundable: await this.totalsService_.getLineItemRefund(order, { - ...item, - quantity: item.quantity - (item.returned_quantity || 0), - } as LineItem), - } as LineItem) - } - c.additional_items = items - } - break - } - default: { - break - } - } - } - return order - } - - async decorateTotals(order: Order, totalsFields?: string[]): Promise - - async decorateTotals(order: Order, context?: TotalsContext): Promise - - /** - * Calculate and attach the different total fields on the object - * @param order - * @param totalsFieldsOrContext - */ - async decorateTotals( - order: Order, - totalsFieldsOrContext?: string[] | TotalsContext - ): Promise { - if (Array.isArray(totalsFieldsOrContext)) { - if (totalsFieldsOrContext.length) { - return await this.decorateTotalsLegacy(order, totalsFieldsOrContext) - } - totalsFieldsOrContext = {} - } - - const newTotalsServiceTx = this.newTotalsService_.withTransaction( - this.activeManager_ - ) - - const calculationContext = await this.totalsService_.getCalculationContext( - order - ) - - const { returnable_items } = totalsFieldsOrContext?.includes ?? {} - - const returnableItems: LineItem[] | undefined = isDefined(returnable_items) - ? [] - : undefined - - const isReturnableItem = (item) => - returnable_items && - (item.returned_quantity ?? 0) < (item.shipped_quantity ?? 0) - - const allItems: LineItem[] = [...(order.items ?? [])] - - if (returnable_items) { - // All items must receive their totals and if some of them are returnable - // They will be pushed to `returnable_items` at a later point - allItems.push( - ...(order.swaps?.map((s) => s.additional_items ?? []).flat() ?? []), - ...(order.claims?.map((c) => c.additional_items ?? []).flat() ?? []) - ) - } - - const orderShippingMethods = [...(order.shipping_methods ?? [])] - - const itemsTotals = await newTotalsServiceTx.getLineItemTotals(allItems, { - taxRate: order.tax_rate, - includeTax: true, - calculationContext, - }) - const shippingTotals = await newTotalsServiceTx.getShippingMethodTotals( - orderShippingMethods, - { - taxRate: order.tax_rate, - discounts: order.discounts, - includeTax: true, - calculationContext, - } - ) - - order.subtotal = 0 - order.discount_total = 0 - order.shipping_total = 0 - order.refunded_total = - Math.round(order.refunds?.reduce((acc, next) => acc + next.amount, 0)) || - 0 - 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 - - order.items = (order.items || []).map((item) => { - item.quantity = item.quantity - (item.returned_quantity || 0) - const refundable = newTotalsServiceTx.getLineItemRefund(item, { - calculationContext, - taxRate: order.tax_rate, - }) - - Object.assign(item, itemsTotals[item.id] ?? {}, { refundable }) - - order.subtotal += item.subtotal ?? 0 - order.discount_total += item.raw_discount_total ?? 0 - item_tax_total += item.tax_total ?? 0 - - if (isReturnableItem(item)) { - returnableItems?.push(item) - } - - return item - }) - - order.shipping_methods = (order.shipping_methods || []).map( - (shippingMethod) => { - const methodWithTotals = Object.assign( - shippingMethod, - shippingTotals[shippingMethod.id] ?? {} - ) - - order.shipping_total += methodWithTotals.subtotal ?? 0 - shipping_tax_total += methodWithTotals.tax_total ?? 0 - - return methodWithTotals - } - ) - - order.item_tax_total = item_tax_total - order.shipping_tax_total = shipping_tax_total - order.tax_total = item_tax_total + shipping_tax_total - - const giftCardableAmount = this.newTotalsService_.getGiftCardableAmount({ - gift_cards_taxable: order.region?.gift_cards_taxable, - subtotal: order.subtotal, - discount_total: order.discount_total, - shipping_total: order.shipping_total, - tax_total: order.tax_total, - }) - - const giftCardTotal = await this.newTotalsService_.getGiftCardTotals( - giftCardableAmount, - { - region: order.region, - giftCards: order.gift_cards, - giftCardTransactions: order.gift_card_transactions ?? [], - } - ) - order.gift_card_total = giftCardTotal.total || 0 - order.gift_card_tax_total = giftCardTotal.tax_total || 0 - - order.tax_total -= order.gift_card_tax_total - - for (const swap of order.swaps ?? []) { - swap.additional_items = swap.additional_items.map((item) => { - item.quantity = item.quantity - (item.returned_quantity || 0) - const refundable = newTotalsServiceTx.getLineItemRefund(item, { - calculationContext, - taxRate: order.tax_rate, - }) - - Object.assign(item, itemsTotals[item.id] ?? {}, { refundable }) - - if (isReturnableItem(item)) { - returnableItems?.push(item) - } - - return item - }) - } - - for (const claim of order.claims ?? []) { - claim.additional_items = claim.additional_items.map((item) => { - item.quantity = item.quantity - (item.returned_quantity || 0) - const refundable = newTotalsServiceTx.getLineItemRefund(item, { - calculationContext, - taxRate: order.tax_rate, - }) - - Object.assign(item, itemsTotals[item.id] ?? {}, { refundable }) - - if (isReturnableItem(item)) { - returnableItems?.push(item) - } - - return item - }) - } - - order.raw_discount_total = order.discount_total - order.discount_total = Math.round(order.discount_total) - - order.total = - order.subtotal + - order.shipping_total + - order.tax_total - - (order.gift_card_total + order.discount_total) - - order.returnable_items = returnableItems - - return order - } - - /** - * Handles receiving a return. This will create a - * refund to the customer. If the returned items don't match the requested - * items the return status will be updated to requires_action. This behaviour - * is useful in situations where a custom refund amount is requested, but the - * returned items are not matching the requested items. Setting the - * allowMismatch argument to true, will process the return, ignoring any - * mismatches. - * @param orderId - the order to return. - * @param receivedReturn - the received return - * @param customRefundAmount - the custom refund amount return - * @return the result of the update operation - */ - async registerReturnReceived( - orderId: string, - receivedReturn: Return, - customRefundAmount?: number - ): Promise { - return await this.atomicPhase_(async (manager) => { - const order = await this.retrieve(orderId, { - select: ["total", "refunded_total", "refundable_amount"], - relations: ["items", "returns", "payments"], - }) - - if (order.status === "canceled") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "A canceled order cannot be registered as received" - ) - } - - if (!receivedReturn || receivedReturn.order_id !== orderId) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Received return does not exist` - ) - } - - const refundAmount = customRefundAmount ?? receivedReturn.refund_amount - - const orderRepo = manager.withRepository(this.orderRepository_) - - if (refundAmount > order.refundable_amount) { - order.fulfillment_status = FulfillmentStatus.REQUIRES_ACTION - const result = await orderRepo.save(order) - await this.eventBus_ - .withTransaction(manager) - .emit(OrderService.Events.RETURN_ACTION_REQUIRED, { - id: result.id, - return_id: receivedReturn.id, - no_notification: receivedReturn.no_notification, - }) - return result - } - - let isFullReturn = true - for (const i of order.items) { - if (i.returned_quantity !== i.quantity) { - isFullReturn = false - } - } - - if (refundAmount > 0) { - const refund = await this.paymentProviderService_ - .withTransaction(manager) - .refundPayment(order.payments, refundAmount, "return") - - order.refunds = [...(order.refunds || []), refund] - } - - if (isFullReturn) { - order.fulfillment_status = FulfillmentStatus.RETURNED - } else { - order.fulfillment_status = FulfillmentStatus.PARTIALLY_RETURNED - } - - const result = await orderRepo.save(order) - await this.eventBus_ - .withTransaction(manager) - .emit(OrderService.Events.ITEMS_RETURNED, { - id: order.id, - return_id: receivedReturn.id, - no_notification: receivedReturn.no_notification, - }) - return result - }) - } - - private getTotalsRelations(config: FindConfig): string[] { - const relationSet = new Set(config.relations) - - relationSet.add("items") - relationSet.add("items.tax_lines") - relationSet.add("items.adjustments") - relationSet.add("items.variant") - relationSet.add("swaps") - relationSet.add("swaps.additional_items") - relationSet.add("swaps.additional_items.tax_lines") - relationSet.add("swaps.additional_items.adjustments") - relationSet.add("claims") - relationSet.add("claims.additional_items") - relationSet.add("claims.additional_items.tax_lines") - relationSet.add("claims.additional_items.adjustments") - relationSet.add("discounts") - relationSet.add("discounts.rule") - relationSet.add("gift_cards") - relationSet.add("gift_card_transactions") - relationSet.add("refunds") - relationSet.add("shipping_methods") - relationSet.add("shipping_methods.tax_lines") - relationSet.add("region") - relationSet.add("payments") - - return Array.from(relationSet.values()) - } -} - -export default OrderService diff --git a/packages/medusa/src/services/payment-collection.ts b/packages/medusa/src/services/payment-collection.ts deleted file mode 100644 index b7effdc3e5..0000000000 --- a/packages/medusa/src/services/payment-collection.ts +++ /dev/null @@ -1,618 +0,0 @@ -import { isDefined, MedusaError } from "medusa-core-utils" -import { DeepPartial, EntityManager } from "typeorm" - -import { - PaymentCollection, - PaymentCollectionStatus, - PaymentSession, - PaymentSessionStatus, -} from "../models" -import { PaymentCollectionRepository } from "../repositories/payment-collection" -import { FindConfig } from "../types/common" -import { buildQuery, isString, setMetadata } from "../utils" -import { CustomerService, PaymentProviderService } from "./index" - -import { TransactionBaseService } from "../interfaces" -import { CreatePaymentInput, PaymentSessionInput } from "../types/payment" -import { - CreatePaymentCollectionInput, - PaymentCollectionsSessionsBatchInput, - PaymentCollectionsSessionsInput, -} from "../types/payment-collection" -import EventBusService from "./event-bus" -import { promiseAll } from "@medusajs/utils" - -type InjectedDependencies = { - manager: EntityManager - paymentCollectionRepository: typeof PaymentCollectionRepository - paymentProviderService: PaymentProviderService - eventBusService: EventBusService - customerService: CustomerService -} - -export default class PaymentCollectionService extends TransactionBaseService { - static readonly Events = { - CREATED: "payment-collection.created", - UPDATED: "payment-collection.updated", - DELETED: "payment-collection.deleted", - PAYMENT_AUTHORIZED: "payment-collection.payment_authorized", - } - - protected readonly eventBusService_: EventBusService - protected readonly paymentProviderService_: PaymentProviderService - protected readonly customerService_: CustomerService - // eslint-disable-next-line max-len - protected readonly paymentCollectionRepository_: typeof PaymentCollectionRepository - - constructor({ - paymentCollectionRepository, - paymentProviderService, - customerService, - eventBusService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.paymentCollectionRepository_ = paymentCollectionRepository - this.paymentProviderService_ = paymentProviderService - this.eventBusService_ = eventBusService - this.customerService_ = customerService - } - - /** - * Retrieves a payment collection by id. - * @param paymentCollectionId - the id of the payment collection - * @param config - the config to retrieve the payment collection - * @return the payment collection. - */ - async retrieve( - paymentCollectionId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(paymentCollectionId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"paymentCollectionId" must be defined` - ) - } - - const paymentCollectionRepository = this.activeManager_.withRepository( - this.paymentCollectionRepository_ - ) - - let paymentCollection: PaymentCollection[] = [] - if (paymentCollectionId) { - const query = buildQuery({ id: paymentCollectionId }, config) - paymentCollection = await paymentCollectionRepository.find(query) - } - - if (!paymentCollection.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Payment collection with id ${paymentCollectionId} was not found` - ) - } - - return paymentCollection[0] - } - - /** - * Creates a new payment collection. - * @param data - info to create the payment collection - * @return the payment collection created. - */ - async create(data: CreatePaymentCollectionInput): Promise { - return await this.atomicPhase_(async (manager) => { - const paymentCollectionRepository = manager.withRepository( - this.paymentCollectionRepository_ - ) - - const paymentCollectionToCreate = paymentCollectionRepository.create({ - region_id: data.region_id, - type: data.type, - status: PaymentCollectionStatus.NOT_PAID, - currency_code: data.currency_code, - amount: data.amount, - metadata: data.metadata, - created_by: data.created_by, - description: data.description, - }) - - const paymentCollection = await paymentCollectionRepository.save( - paymentCollectionToCreate - ) - - await this.eventBusService_ - .withTransaction(manager) - .emit(PaymentCollectionService.Events.CREATED, paymentCollection) - - return paymentCollection - }) - } - - /** - * Updates a payment collection. - * @param paymentCollectionId - the id of the payment collection to update - * @param data - info to be updated - * @return the payment collection updated. - */ - async update( - paymentCollectionId: string, - data: DeepPartial - ): Promise { - return await this.atomicPhase_(async (manager) => { - const paymentCollectionRepo = manager.withRepository( - this.paymentCollectionRepository_ - ) - - const paymentCollection = await this.retrieve(paymentCollectionId) - - for (const key of Object.keys(data)) { - if (key === "metadata" && data.metadata) { - paymentCollection[key] = setMetadata(paymentCollection, data.metadata) - } else if (isDefined(data[key])) { - paymentCollection[key] = data[key] - } - } - - const result = await paymentCollectionRepo.save(paymentCollection) - - await this.eventBusService_ - .withTransaction(manager) - .emit(PaymentCollectionService.Events.UPDATED, result) - - return result - }) - } - - /** - * Deletes a payment collection. - * @param paymentCollectionId - the id of the payment collection to be removed - * @return the payment collection removed. - */ - async delete( - paymentCollectionId: string - ): Promise { - return await this.atomicPhase_(async (manager) => { - const paymentCollectionRepo = manager.withRepository( - this.paymentCollectionRepository_ - ) - - const paymentCollection = await this.retrieve(paymentCollectionId).catch( - () => void 0 - ) - - if (!paymentCollection) { - return - } - - if ( - ![ - PaymentCollectionStatus.CANCELED, - PaymentCollectionStatus.NOT_PAID, - ].includes(paymentCollection.status) - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Cannot delete payment collection with status ${paymentCollection.status}` - ) - } - - await paymentCollectionRepo.remove(paymentCollection) - - await this.eventBusService_ - .withTransaction(manager) - .emit(PaymentCollectionService.Events.DELETED, paymentCollection) - - return paymentCollection - }) - } - - private isValidTotalAmount( - total: number, - sessionsInput: PaymentCollectionsSessionsBatchInput[] - ): boolean { - const sum = sessionsInput.reduce((cur, sess) => cur + sess.amount, 0) - return total === sum - } - - /** - * Manages multiple payment sessions of a payment collection. - * @param paymentCollectionOrId - the id of the payment collection - * @param sessionsInput - array containing payment session info - * @param customerId - the id of the customer - * @return the payment collection and its payment sessions. - */ - async setPaymentSessionsBatch( - paymentCollectionOrId: string | PaymentCollection, - sessionsInput: PaymentCollectionsSessionsBatchInput[], - customerId: string - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const paymentCollectionRepository = manager.withRepository( - this.paymentCollectionRepository_ - ) - - const payCol: PaymentCollection = isString(paymentCollectionOrId) - ? await this.retrieve(paymentCollectionOrId, { - relations: [ - "region", - "region.payment_providers", - "payment_sessions", - ], - }) - : paymentCollectionOrId - - if (payCol.status !== PaymentCollectionStatus.NOT_PAID) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Cannot set payment sessions for a payment collection with status ${payCol.status}` - ) - } - - const payColRegionProviderMap = new Map( - payCol.region.payment_providers.map((provider) => { - return [provider.id, provider] - }) - ) - - sessionsInput = sessionsInput.filter((session) => { - return !!payColRegionProviderMap.get(session.provider_id) - }) - - if (!this.isValidTotalAmount(payCol.amount, sessionsInput)) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - `The sum of sessions is not equal to ${payCol.amount} on Payment Collection` - ) - } - - const customer = !isDefined(customerId) - ? null - : await this.customerService_ - .withTransaction(manager) - .retrieve(customerId, { - select: ["id", "email", "metadata"], - }) - .catch(() => null) - - const payColSessionMap = new Map( - (payCol.payment_sessions ?? []).map((session) => { - return [session.id, session] - }) - ) - - const paymentProviderTx = - this.paymentProviderService_.withTransaction(manager) - - const selectedSessionIds: string[] = [] - const paymentSessions: PaymentSession[] = [] - - for (const session of sessionsInput) { - const existingSession = - session.session_id && payColSessionMap.get(session.session_id) - - const inputData: PaymentSessionInput = { - cart: { - email: customer?.email || "", - context: {}, - shipping_methods: [], - shipping_address: null, - id: "", - region_id: payCol.region_id, - total: session.amount, - }, - resource_id: payCol.id, - currency_code: payCol.currency_code, - amount: session.amount, - provider_id: session.provider_id, - customer, - } - - let paymentSession - - if (existingSession) { - paymentSession = await paymentProviderTx.updateSession( - existingSession, - inputData - ) - } else { - paymentSession = await paymentProviderTx.createSession(inputData) - } - - selectedSessionIds.push(paymentSession.id) - paymentSessions.push(paymentSession) - } - - if (payCol.payment_sessions?.length) { - const removeSessions: PaymentSession[] = payCol.payment_sessions.filter( - ({ id }) => !selectedSessionIds.includes(id) - ) - - if (removeSessions.length) { - await paymentCollectionRepository.delete( - removeSessions.map((sess) => sess.id) - ) - - const paymentProviderTx = - this.paymentProviderService_.withTransaction(manager) - - await promiseAll( - removeSessions.map(async (sess) => - paymentProviderTx.deleteSession(sess) - ) - ).catch(() => void 0) - } - } - - payCol.payment_sessions = paymentSessions - - return await paymentCollectionRepository.save(payCol) - }) - } - - /** - * Manages a single payment sessions of a payment collection. - * @param paymentCollectionId - the id of the payment collection - * @param sessionInput - object containing payment session info - * @param customerId - the id of the customer - * @return the payment collection and its payment session. - */ - async setPaymentSession( - paymentCollectionId: string, - sessionInput: PaymentCollectionsSessionsInput, - customerId: string - ): Promise { - return await this.atomicPhase_(async () => { - const payCol = await this.retrieve(paymentCollectionId, { - relations: ["region", "region.payment_providers", "payment_sessions"], - }) - - const hasProvider = payCol?.region?.payment_providers.find( - (p) => p.id === sessionInput.provider_id - ) - - if (!hasProvider) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Payment provider not found" - ) - } - - const existingSession = payCol.payment_sessions?.find( - (sess) => sessionInput.provider_id === sess?.provider_id - ) - - return await this.setPaymentSessionsBatch( - payCol, - [ - { - ...sessionInput, - amount: payCol.amount, - session_id: existingSession?.id, - }, - ], - customerId - ) - }) - } - - /** - * Removes and recreate a payment session of a payment collection. - * @param paymentCollectionId - the id of the payment collection - * @param sessionId - the id of the payment session to be replaced - * @param customerId - the id of the customer - * @return the new payment session created. - */ - async refreshPaymentSession( - paymentCollectionId: string, - sessionId: string, - customerId: string - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const paymentCollectionRepository = manager.withRepository( - this.paymentCollectionRepository_ - ) - - const payCol = - await paymentCollectionRepository.getPaymentCollectionIdBySessionId( - sessionId, - { - relations: { - region: { - payment_providers: true, - }, - payment_sessions: true, - }, - } - ) - - if (paymentCollectionId !== payCol.id) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Payment Session ${sessionId} does not belong to Payment Collection ${paymentCollectionId}` - ) - } - - const session = payCol.payment_sessions.find( - (sess) => sessionId === sess?.id - ) - - if (!session) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Session with id ${sessionId} was not found` - ) - } - - const customer = !isDefined(customerId) - ? null - : await this.customerService_ - .withTransaction(manager) - .retrieve(customerId, { - select: ["id", "email", "metadata"], - }) - .catch(() => null) - - const inputData: PaymentSessionInput = { - cart: { - email: customer?.email || "", - context: {}, - shipping_methods: [], - shipping_address: null, - id: "", - region_id: payCol.region_id, - total: session.amount, - }, - resource_id: payCol.id, - currency_code: payCol.currency_code, - amount: session.amount, - provider_id: session.provider_id, - customer, - } - - const sessionRefreshed = await this.paymentProviderService_ - .withTransaction(manager) - .refreshSession(session, inputData) - - payCol.payment_sessions = payCol.payment_sessions.map((sess) => { - if (sess.id === sessionId) { - return sessionRefreshed - } - return sess - }) - - if (session.payment_authorized_at && payCol.authorized_amount) { - payCol.authorized_amount -= session.amount - } - - await paymentCollectionRepository.save(payCol) - - return sessionRefreshed - }) - } - - /** - * Marks a payment collection as authorized bypassing the payment flow. - * @param paymentCollectionId - the id of the payment collection - * @return the payment session authorized. - */ - async markAsAuthorized( - paymentCollectionId: string - ): Promise { - return await this.atomicPhase_(async (manager) => { - const paymentCollectionRepo = manager.withRepository( - this.paymentCollectionRepository_ - ) - - const paymentCollection = await this.retrieve(paymentCollectionId) - paymentCollection.status = PaymentCollectionStatus.AUTHORIZED - paymentCollection.authorized_amount = paymentCollection.amount - - const result = await paymentCollectionRepo.save(paymentCollection) - - await this.eventBusService_ - .withTransaction(manager) - .emit(PaymentCollectionService.Events.PAYMENT_AUTHORIZED, result) - - return result - }) - } - - /** - * Authorizes the payment sessions of a payment collection. - * @param paymentCollectionId - the id of the payment collection - * @param sessionIds - array of payment session ids to be authorized - * @param context - additional data required by payment providers - * @return the payment collection and its payment session. - */ - async authorizePaymentSessions( - paymentCollectionId: string, - sessionIds: string[], - context: Record = {} - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const paymentCollectionRepository = manager.withRepository( - this.paymentCollectionRepository_ - ) - - const payCol = await this.retrieve(paymentCollectionId, { - relations: ["payment_sessions", "payments"], - }) - - if (payCol.authorized_amount === payCol.amount) { - return payCol - } - - if (payCol.amount <= 0) { - payCol.authorized_amount = 0 - payCol.status = PaymentCollectionStatus.AUTHORIZED - return await paymentCollectionRepository.save(payCol) - } - - if (!payCol.payment_sessions?.length) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "You cannot complete a Payment Collection without a payment session." - ) - } - - const paymentProviderTx = - this.paymentProviderService_.withTransaction(manager) - - let authorizedAmount = 0 - for (let i = 0; i < payCol.payment_sessions.length; i++) { - const session = payCol.payment_sessions[i] - - if (session.payment_authorized_at) { - authorizedAmount += session.amount - continue - } - - if (!sessionIds.includes(session.id)) { - continue - } - - const paymentSession = await paymentProviderTx.authorizePayment( - session, - context - ) - - if (paymentSession) { - payCol.payment_sessions[i] = paymentSession - } - - if (paymentSession?.status === PaymentSessionStatus.AUTHORIZED) { - authorizedAmount += session.amount - - const inputData: CreatePaymentInput = { - amount: session.amount, - currency_code: payCol.currency_code, - provider_id: session.provider_id, - resource_id: payCol.id, - payment_session: paymentSession, - } - - payCol.payments.push(await paymentProviderTx.createPayment(inputData)) - } - } - - if (authorizedAmount === 0) { - payCol.status = PaymentCollectionStatus.AWAITING - } else if (authorizedAmount < payCol.amount) { - payCol.status = PaymentCollectionStatus.PARTIALLY_AUTHORIZED - } else if (authorizedAmount === payCol.amount) { - payCol.status = PaymentCollectionStatus.AUTHORIZED - } - - payCol.authorized_amount = authorizedAmount - const payColCopy = await paymentCollectionRepository.save(payCol) - - await this.eventBusService_ - .withTransaction(manager) - .emit(PaymentCollectionService.Events.PAYMENT_AUTHORIZED, payColCopy) - - return payCol - }) - } -} diff --git a/packages/medusa/src/services/payment-provider.ts b/packages/medusa/src/services/payment-provider.ts deleted file mode 100644 index a917838db9..0000000000 --- a/packages/medusa/src/services/payment-provider.ts +++ /dev/null @@ -1,962 +0,0 @@ -import { FlagRouter, promiseAll } from "@medusajs/utils" -import { isDefined, MedusaError } from "medusa-core-utils" -import { BasePaymentService } from "medusa-interfaces" -import { EOL } from "os" -import { EntityManager } from "typeorm" -import { - AbstractPaymentProcessor, - AbstractPaymentService, - isPaymentProcessorError, - PaymentContext, - PaymentProcessorError, - PaymentSessionResponse, - TransactionBaseService, -} from "../interfaces" -import { - Cart, - Payment, - PaymentProvider, - PaymentSession, - PaymentSessionStatus, - Refund, -} from "../models" -import { PaymentRepository } from "../repositories/payment" -import { PaymentProviderRepository } from "../repositories/payment-provider" -import { PaymentSessionRepository } from "../repositories/payment-session" -import { RefundRepository } from "../repositories/refund" -import { FindConfig, Selector } from "../types/common" -import { Logger } from "../types/global" -import { CreatePaymentInput, PaymentSessionInput } from "../types/payment" -import { buildQuery, isString } from "../utils" -import { CustomerService } from "./index" -import PaymentService from "./payment" - -type PaymentProviderKey = `pp_${string}` | "systemPaymentProviderService" -type InjectedDependencies = { - manager: EntityManager - paymentSessionRepository: typeof PaymentSessionRepository - paymentProviderRepository: typeof PaymentProviderRepository - paymentRepository: typeof PaymentRepository - refundRepository: typeof RefundRepository - paymentService: PaymentService - customerService: CustomerService - featureFlagRouter: FlagRouter - logger: Logger -} & { - [key in `${PaymentProviderKey}`]: - | AbstractPaymentService - | typeof BasePaymentService -} - -/** - * Helps retrieve payment providers - */ -export default class PaymentProviderService extends TransactionBaseService { - protected readonly container_: InjectedDependencies - protected readonly paymentSessionRepository_: typeof PaymentSessionRepository - // eslint-disable-next-line max-len - protected readonly paymentProviderRepository_: typeof PaymentProviderRepository - protected readonly paymentRepository_: typeof PaymentRepository - protected get paymentService_(): PaymentService { - // defer resolution. then it will use the cached resolved service - return this.container_.paymentService - } - protected readonly refundRepository_: typeof RefundRepository - protected readonly customerService_: CustomerService - protected readonly logger_: Logger - - protected readonly featureFlagRouter_: FlagRouter - - constructor(container: InjectedDependencies) { - super(container) - - this.container_ = container - this.paymentSessionRepository_ = container.paymentSessionRepository - this.paymentProviderRepository_ = container.paymentProviderRepository - this.paymentRepository_ = container.paymentRepository - this.refundRepository_ = container.refundRepository - this.customerService_ = container.customerService - this.featureFlagRouter_ = container.featureFlagRouter - this.logger_ = container.logger - } - - async registerInstalledProviders(providerIds: string[]): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const model = transactionManager.withRepository( - this.paymentProviderRepository_ - ) - await model.update({}, { is_installed: false }) - - await promiseAll( - providerIds.map(async (providerId) => { - const provider = model.create({ - id: providerId, - is_installed: true, - }) - return await model.save(provider) - }) - ) - }) - } - - async list(): Promise { - const ppRepo = this.activeManager_.withRepository( - this.paymentProviderRepository_ - ) - return await ppRepo.find() - } - - /** - * Retrieve a payment entity with the given id. - * @param paymentId - * @param relations - */ - async retrievePayment( - paymentId: string, - relations: string[] = [] - ): Promise { - if (!isDefined(paymentId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"paymentId" must be defined` - ) - } - - const paymentRepo = this.activeManager_.withRepository( - this.paymentRepository_ - ) - const query = { - where: { id: paymentId }, - relations: [] as string[], - } - - if (relations.length) { - query.relations = relations - } - - const payment = await paymentRepo.findOne(query) - - if (!payment) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Payment with ${paymentId} was not found` - ) - } - - return payment - } - - /** - * List all the payments according to the given selector and config. - * @param selector - * @param config - */ - async listPayments( - selector: Selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise { - const payRepo = this.activeManager_.withRepository(this.paymentRepository_) - const query = buildQuery(selector, config) - return await payRepo.find(query) - } - - /** - * Return the payment session for the given id. - * @param paymentSessionId - * @param relations - */ - async retrieveSession( - paymentSessionId: string, - relations: string[] = [] - ): Promise { - if (!isDefined(paymentSessionId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"paymentSessionId" must be defined` - ) - } - - const sessionRepo = this.activeManager_.withRepository( - this.paymentSessionRepository_ - ) - - const query = buildQuery({ id: paymentSessionId }, { relations }) - const session = await sessionRepo.findOne(query) - - if (!session) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Payment Session with ${paymentSessionId} was not found` - ) - } - - return session - } - - /** - * @deprecated - * @param providerId - * @param cart - */ - async createSession(providerId: string, cart: Cart): Promise - - /** - * Creates a payment session with the given provider. - * @param sessionInput - */ - async createSession( - sessionInput: PaymentSessionInput - ): Promise - - /** - * Creates a payment session with the given provider. - * @param providerIdOrSessionInput - the id of the provider to create payment with or the input data - * @param cart - a cart object used to calculate the amount, etc. from - * @return the payment session - */ - async createSession< - TInput extends string | PaymentSessionInput = string | PaymentSessionInput - >( - providerIdOrSessionInput: TInput, - ...[cart]: TInput extends string ? [Cart] : [never?] - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const providerId = isString(providerIdOrSessionInput) - ? providerIdOrSessionInput - : providerIdOrSessionInput.provider_id - - const data = ( - isString(providerIdOrSessionInput) ? cart : providerIdOrSessionInput - ) as Cart | PaymentSessionInput - - const provider = this.retrieveProvider< - AbstractPaymentService | AbstractPaymentProcessor - >(providerId) - const context = this.buildPaymentProcessorContext(data) - - if (!isDefined(context.currency_code) || !isDefined(context.amount)) { - throw new MedusaError( - MedusaError.Types.INVALID_ARGUMENT, - "`currency_code` and `amount` are required to create payment session." - ) - } - - let paymentResponse - if (provider instanceof AbstractPaymentProcessor) { - paymentResponse = await provider.initiatePayment({ - amount: context.amount, - context: context.context, - currency_code: context.currency_code, - customer: context.customer, - email: context.email, - billing_address: context.billing_address, - resource_id: context.resource_id, - paymentSessionData: {}, - }) - - if ("error" in paymentResponse) { - this.throwFromPaymentProcessorError(paymentResponse) - } - } else { - // Added to stay backward compatible - paymentResponse = await provider - .withTransaction(transactionManager) - .createPayment(context) - } - - const sessionData = paymentResponse.session_data ?? paymentResponse - - await this.processUpdateRequestsData( - { - customer: { id: context.customer?.id }, - }, - paymentResponse - ) - - return await this.saveSession(providerId, { - payment_session_id: !isString(providerIdOrSessionInput) - ? providerIdOrSessionInput.payment_session_id - : undefined, - cartId: context.id, - sessionData, - status: PaymentSessionStatus.PENDING, - isInitiated: true, - amount: context.amount, - }) - }) - } - - /** - * Refreshes a payment session with the given provider. - * This means, that we delete the current one and create a new. - * @param paymentSession - the payment session object to - * update - * @param sessionInput - * @return the payment session - */ - async refreshSession( - paymentSession: { - id: string - data: Record - provider_id: string - }, - sessionInput: PaymentSessionInput - ): Promise { - return this.atomicPhase_(async (transactionManager) => { - const session = await this.retrieveSession(paymentSession.id) - - const provider = this.retrieveProvider< - AbstractPaymentService | AbstractPaymentProcessor - >(paymentSession.provider_id) - - if (provider instanceof AbstractPaymentProcessor) { - const error = await provider.deletePayment(session.data) - if (isPaymentProcessorError(error)) { - this.throwFromPaymentProcessorError(error) - } - } else { - await provider - .withTransaction(transactionManager) - .deletePayment(session) - } - - const sessionRepo = transactionManager.withRepository( - this.paymentSessionRepository_ - ) - - await sessionRepo.remove(session) - return await this.createSession(sessionInput) - }) - } - - /** - * Update a payment session with the given provider. - * @param paymentSession - The paymentSession to update - * @param sessionInput - * @return the payment session - */ - async updateSession( - paymentSession: { - id: string - data: Record - provider_id: string - }, - sessionInput: Cart | PaymentSessionInput - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const provider = this.retrieveProvider< - AbstractPaymentService | AbstractPaymentProcessor - >(paymentSession.provider_id) - - const context = this.buildPaymentProcessorContext(sessionInput) - - let paymentResponse - if (provider instanceof AbstractPaymentProcessor) { - paymentResponse = await provider.updatePayment({ - amount: context.amount, - context: context.context, - currency_code: context.currency_code, - customer: context.customer, - email: context.email, - billing_address: context.billing_address, - resource_id: context.resource_id, - paymentSessionData: paymentSession.data, - }) - - if (paymentResponse && "error" in paymentResponse) { - this.throwFromPaymentProcessorError(paymentResponse) - } - } else { - paymentResponse = await provider - .withTransaction(transactionManager) - .updatePayment(paymentSession.data, context) - } - - const sessionData = paymentResponse?.session_data ?? paymentResponse - - // If no update occurs, return the original session - if (!sessionData) { - return await this.retrieveSession(paymentSession.id) - } - - await this.processUpdateRequestsData( - { - customer: { id: context.customer?.id }, - }, - paymentResponse - ) - - return await this.saveSession(paymentSession.provider_id, { - payment_session_id: paymentSession.id, - sessionData, - isInitiated: true, - amount: context.amount, - }) - }) - } - - async deleteSession( - paymentSession: PaymentSession - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const session = await this.retrieveSession(paymentSession.id).catch( - () => void 0 - ) - - if (!session) { - return - } - - const provider = this.retrieveProvider< - AbstractPaymentService | AbstractPaymentProcessor - >(paymentSession.provider_id) - - if (provider instanceof AbstractPaymentProcessor) { - const error = await provider.deletePayment(paymentSession.data) - if (isPaymentProcessorError(error)) { - this.throwFromPaymentProcessorError(error) - } - } else { - await provider - .withTransaction(transactionManager) - .deletePayment(paymentSession) - } - - const sessionRepo = transactionManager.withRepository( - this.paymentSessionRepository_ - ) - - return await sessionRepo.remove(session) - }) - } - - /** - * Finds a provider given an id - * @param providerId - the id of the provider to get - * @return the payment provider - */ - retrieveProvider< - TProvider extends - | AbstractPaymentService - | typeof BasePaymentService - | AbstractPaymentProcessor - >( - providerId: string - ): TProvider extends AbstractPaymentService - ? AbstractPaymentService - : TProvider extends AbstractPaymentProcessor - ? AbstractPaymentProcessor - : typeof BasePaymentService { - try { - let provider - if (providerId === "system") { - provider = this.container_[`systemPaymentProviderService`] - } else { - provider = this.container_[`pp_${providerId}`] - } - - return provider - } catch (err) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Could not find a payment provider with id: ${providerId}` - ) - } - } - - async createPayment(data: CreatePaymentInput): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const { payment_session, currency_code, amount, provider_id } = data - const providerId = provider_id ?? payment_session.provider_id - - const provider = this.retrieveProvider< - AbstractPaymentService | AbstractPaymentProcessor - >(providerId) - - let paymentData: Record = {} - - if (provider instanceof AbstractPaymentProcessor) { - const res = await provider.retrievePayment(payment_session.data) - if ("error" in res) { - this.throwFromPaymentProcessorError(res as PaymentProcessorError) - } else { - // Use else to avoid casting the object and infer the type instead - paymentData = res - } - } else { - paymentData = await provider - .withTransaction(transactionManager) - .getPaymentData(payment_session) - } - - const paymentRepo = transactionManager.withRepository( - this.paymentRepository_ - ) - - const created = paymentRepo.create({ - provider_id: providerId, - amount, - currency_code, - data: paymentData, - cart_id: data.cart_id, - }) - - return await paymentRepo.save(created) - }) - } - - async updatePayment( - paymentId: string, - data: { order_id?: string; swap_id?: string } - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - return await this.paymentService_ - .withTransaction(transactionManager) - .update(paymentId, data) - }) - } - - async authorizePayment( - paymentSession: PaymentSession, - context: Record - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const session = await this.retrieveSession(paymentSession.id).catch( - () => void 0 - ) - - if (!session) { - return - } - - const provider = this.retrieveProvider(paymentSession.provider_id) - - if (provider instanceof AbstractPaymentProcessor) { - const res = await provider.authorizePayment( - paymentSession.data, - context - ) - if ("error" in res) { - this.throwFromPaymentProcessorError(res) - } else { - // Use else to avoid casting the object and infer the type instead - session.data = res.data - session.status = res.status - } - } else { - const { status, data } = await provider - .withTransaction(transactionManager) - .authorizePayment(session, context) - session.data = data - session.status = status - } - - if (session.status === PaymentSessionStatus.AUTHORIZED) { - session.payment_authorized_at = new Date() - } - - const sessionRepo = transactionManager.withRepository( - this.paymentSessionRepository_ - ) - return await sessionRepo.save(session) - }) - } - - async updateSessionData( - paymentSession: PaymentSession, - data: Record - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const session = await this.retrieveSession(paymentSession.id) - - const provider = this.retrieveProvider(paymentSession.provider_id) - - let updatedData - if (provider instanceof AbstractPaymentProcessor) { - const res = await provider.updatePaymentData(paymentSession.id, data) - if ("error" in res) { - this.throwFromPaymentProcessorError(res as PaymentProcessorError) - } else { - updatedData = res - } - } else { - updatedData = await provider - .withTransaction(transactionManager) - .updatePaymentData(paymentSession.data, data) - } - - Object.assign(session.data, updatedData) - session.status = paymentSession.status - - const sessionRepo = transactionManager.withRepository( - this.paymentSessionRepository_ - ) - return await sessionRepo.save(session) - }) - } - - async cancelPayment( - paymentObj: Partial & { id: string } - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const payment = await this.retrievePayment(paymentObj.id) - const provider = this.retrieveProvider(payment.provider_id) - - if (provider instanceof AbstractPaymentProcessor) { - const error = await provider.cancelPayment(payment.data) - if (isPaymentProcessorError(error)) { - this.throwFromPaymentProcessorError(error) - } - } else { - payment.data = await provider - .withTransaction(transactionManager) - .cancelPayment(payment) - } - - const now = new Date() - payment.canceled_at = now.toISOString() - - const paymentRepo = transactionManager.withRepository( - this.paymentRepository_ - ) - return await paymentRepo.save(payment) - }) - } - - async getStatus(payment: Payment): Promise { - const provider = this.retrieveProvider(payment.provider_id) - if (provider instanceof AbstractPaymentProcessor) { - return await provider.getPaymentStatus(payment.data) - } - - return await provider - .withTransaction(this.activeManager_) - .getStatus(payment.data) - } - - async capturePayment( - paymentObj: Partial & { id: string } - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const payment = await this.retrievePayment(paymentObj.id) - const provider = this.retrieveProvider(payment.provider_id) - - if (provider instanceof AbstractPaymentProcessor) { - const res = await provider.capturePayment(payment.data) - if ("error" in res) { - this.throwFromPaymentProcessorError(res as PaymentProcessorError) - } else { - // Use else to avoid casting the object and infer the type instead - payment.data = res - } - } else { - payment.data = await provider - .withTransaction(transactionManager) - .capturePayment(payment) - } - - const now = new Date() - payment.captured_at = now.toISOString() - - const paymentRepo = transactionManager.withRepository( - this.paymentRepository_ - ) - return await paymentRepo.save(payment) - }) - } - - async refundPayment( - payObjs: Payment[], - amount: number, - reason: string, - note?: string - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const payments = await this.listPayments({ - id: payObjs.map((p) => p.id), - }) - - let order_id!: string - const refundable = payments.reduce((acc, next) => { - order_id = next.order_id - if (next.captured_at) { - return (acc += next.amount - next.amount_refunded) - } - - return acc - }, 0) - - if (refundable < amount) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Refund amount is greater that the refundable amount" - ) - } - - let balance = amount - - const used: string[] = [] - - const paymentRepo = transactionManager.withRepository( - this.paymentRepository_ - ) - - let paymentToRefund = payments.find( - (payment) => payment.amount - payment.amount_refunded > 0 - ) - - while (paymentToRefund) { - const currentRefundable = - paymentToRefund.amount - paymentToRefund.amount_refunded - - const refundAmount = Math.min(currentRefundable, balance) - - const provider = this.retrieveProvider(paymentToRefund.provider_id) - - if (provider instanceof AbstractPaymentProcessor) { - const res = await provider.refundPayment( - paymentToRefund.data, - refundAmount - ) - if (isPaymentProcessorError(res)) { - this.throwFromPaymentProcessorError(res as PaymentProcessorError) - } else { - // Use else to avoid casting the object and infer the type instead - paymentToRefund.data = res - } - } else { - paymentToRefund.data = await provider - .withTransaction(transactionManager) - .refundPayment(paymentToRefund, refundAmount) - } - - paymentToRefund.amount_refunded += refundAmount - await paymentRepo.save(paymentToRefund) - - balance -= refundAmount - - used.push(paymentToRefund.id) - - if (balance > 0) { - paymentToRefund = payments.find( - (payment) => - payment.amount - payment.amount_refunded > 0 && - !used.includes(payment.id) - ) - } else { - paymentToRefund = undefined - } - } - - const refundRepo = transactionManager.withRepository( - this.refundRepository_ - ) - - const toCreate = { - order_id, - amount, - reason, - note, - } - - const created = refundRepo.create(toCreate) - return await refundRepo.save(created) - }) - } - - async refundFromPayment( - payment: Payment, - amount: number, - reason: string, - note?: string - ): Promise { - return await this.atomicPhase_(async (manager) => { - const refundable = payment.amount - payment.amount_refunded - - if (refundable < amount) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Refund amount is greater that the refundable amount" - ) - } - - const provider = this.retrieveProvider(payment.provider_id) - - if (provider instanceof AbstractPaymentProcessor) { - const res = await provider.refundPayment(payment.data, amount) - if (isPaymentProcessorError(res)) { - this.throwFromPaymentProcessorError(res as PaymentProcessorError) - } else { - // Use else to avoid casting the object and infer the type instead - payment.data = res - } - } else { - payment.data = await provider - .withTransaction(manager) - .refundPayment(payment, amount) - } - - payment.amount_refunded += amount - - const paymentRepo = manager.withRepository(this.paymentRepository_) - await paymentRepo.save(payment) - - const refundRepo = manager.withRepository(this.refundRepository_) - - const toCreate = { - payment_id: payment.id, - order_id: payment.order_id, - amount, - reason, - note, - } - - const created = refundRepo.create(toCreate) - return await refundRepo.save(created) - }) - } - - async retrieveRefund( - id: string, - config: FindConfig = {} - ): Promise { - const refRepo = this.activeManager_.withRepository(this.refundRepository_) - const query = buildQuery({ id }, config) - const refund = await refRepo.findOne(query) - - if (!refund) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `A refund with ${id} was not found` - ) - } - - return refund - } - - /** - * Build the create session context for both legacy and new API - * @param cartOrData - * @protected - */ - protected buildPaymentProcessorContext( - cartOrData: Cart | PaymentSessionInput - ): Cart & PaymentContext { - const cart = - "object" in cartOrData && cartOrData.object === "cart" - ? cartOrData - : ((cartOrData as PaymentSessionInput).cart as Cart) - - const context = {} as Cart & PaymentContext - - // TODO: only to support legacy API. Once we are ready to break the API, the cartOrData will only support PaymentSessionInput - if ("object" in cartOrData && cartOrData.object === "cart") { - context.cart = { - context: cart.context, - shipping_address: cart.shipping_address, - billing_address: cart.billing_address, - id: cart.id, - email: cart.email, - shipping_methods: cart.shipping_methods, - } - context.amount = cart.total! - context.currency_code = cart.region?.currency_code - context.resource_id = cart.id - Object.assign(context, cart) - } else { - const data = cartOrData as PaymentSessionInput - context.cart = data.cart - context.amount = data.amount - context.currency_code = data.currency_code - context.resource_id = data.resource_id ?? data.cart.id - Object.assign(context, cart) - } - - return context - } - - /** - * Create or update a Payment session data. - * @param providerId - * @param data - * @protected - */ - protected async saveSession( - providerId: string, - data: { - payment_session_id?: string - cartId?: string - amount?: number - sessionData: Record - isSelected?: boolean - isInitiated?: boolean - status?: PaymentSessionStatus - } - ): Promise { - const sessionRepo = this.activeManager_.withRepository( - this.paymentSessionRepository_ - ) - - // Update an existing session - if (data.payment_session_id) { - const session = await this.retrieveSession(data.payment_session_id) - session.data = data.sessionData ?? session.data - session.status = data.status ?? session.status - session.amount = data.amount ?? session.amount - session.is_initiated = data.isInitiated ?? session.is_initiated - session.is_selected = data.isSelected ?? session.is_selected - return await sessionRepo.save(session) - } - - // Create a new session - const toCreate: Partial = { - cart_id: data.cartId || null, - provider_id: providerId, - data: data.sessionData, - is_selected: data.isSelected, - is_initiated: data.isInitiated, - status: data.status, - amount: data.amount, - } - - const created = sessionRepo.create(toCreate) - return await sessionRepo.save(created) - } - - /** - * Process the collected data. Can be used every time we need to process some collected data returned by the provider - * @param data - * @param paymentResponse - * @protected - */ - protected async processUpdateRequestsData( - data: { customer?: { id?: string } } = {}, - paymentResponse: PaymentSessionResponse | Record - ): Promise { - const { update_requests } = paymentResponse as PaymentSessionResponse - - if (!update_requests) { - return - } - - if (update_requests.customer_metadata && data.customer?.id) { - await this.customerService_ - .withTransaction(this.activeManager_) - .update(data.customer.id, { - metadata: update_requests.customer_metadata, - }) - } - } - - private throwFromPaymentProcessorError(errObj: PaymentProcessorError) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `${errObj.error}${errObj.detail ? `:${EOL}${errObj.detail}` : ""}`, - errObj.code - ) - } -} diff --git a/packages/medusa/src/services/payment.ts b/packages/medusa/src/services/payment.ts deleted file mode 100644 index 0272e7fbe3..0000000000 --- a/packages/medusa/src/services/payment.ts +++ /dev/null @@ -1,258 +0,0 @@ -import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { PaymentRepository } from "./../repositories/payment" - -import { TransactionBaseService } from "../interfaces" -import { Payment, Refund } from "../models" -import { FindConfig } from "../types/common" -import { buildQuery } from "../utils" -import EventBusService from "./event-bus" -import { PaymentProviderService } from "./index" - -type InjectedDependencies = { - manager: EntityManager - paymentProviderService: PaymentProviderService - eventBusService: EventBusService - paymentRepository: typeof PaymentRepository -} - -export type PaymentDataInput = { - currency_code: string - provider_id: string - amount: number - data: Record -} - -export default class PaymentService extends TransactionBaseService { - protected readonly eventBusService_: EventBusService - protected readonly paymentProviderService_: PaymentProviderService - protected readonly paymentRepository_: typeof PaymentRepository - static readonly Events = { - CREATED: "payment.created", - UPDATED: "payment.updated", - PAYMENT_CAPTURED: "payment.payment_captured", - PAYMENT_CAPTURE_FAILED: "payment.payment_capture_failed", - REFUND_CREATED: "payment.payment_refund_created", - REFUND_FAILED: "payment.payment_refund_failed", - } - - constructor({ - paymentRepository, - paymentProviderService, - eventBusService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.paymentRepository_ = paymentRepository - this.paymentProviderService_ = paymentProviderService - this.eventBusService_ = eventBusService - } - - /** - * Retrieves a payment by id. - * @param paymentId - the id of the payment - * @param config - the config to retrieve the payment - * @return the payment. - */ - async retrieve( - paymentId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(paymentId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"paymentId" must be defined` - ) - } - - const paymentRepository = this.activeManager_.withRepository( - this.paymentRepository_ - ) - - const query = buildQuery({ id: paymentId }, config) - - const payment = await paymentRepository.find(query) - - if (!payment.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Payment with id ${paymentId} was not found` - ) - } - - return payment[0] - } - - /** - * Created a new payment. - * @param paymentInput - info to create the payment - * @return the payment created. - */ - async create(paymentInput: PaymentDataInput): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const { data, currency_code, amount, provider_id } = paymentInput - - const paymentRepository = manager.withRepository(this.paymentRepository_) - - const created = paymentRepository.create({ - provider_id, - amount, - currency_code, - data, - }) - - const saved = await paymentRepository.save(created) - - await this.eventBusService_ - .withTransaction(manager) - .emit(PaymentService.Events.CREATED, saved) - - return saved - }) - } - - /** - * Updates a payment in order to link it to an order or a swap. - * @param paymentId - the id of the payment - * @param data - order_id or swap_id to link the payment - * @return the payment updated. - */ - async update( - paymentId: string, - data: { order_id?: string; swap_id?: string } - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const payment = await this.retrieve(paymentId) - - const paymentRepository = manager.withRepository(this.paymentRepository_) - - if (data?.order_id) { - payment.order_id = data.order_id - } - - if (data?.swap_id) { - payment.swap_id = data.swap_id - } - - const updated = await paymentRepository.save(payment) - - await this.eventBusService_ - .withTransaction(manager) - .emit(PaymentService.Events.UPDATED, updated) - - return updated - }) - } - - /** - * Captures a payment. - * @param paymentOrId - the id or the class instance of the payment - * @return the payment captured. - */ - async capture(paymentOrId: string | Payment): Promise { - const payment = - typeof paymentOrId === "string" - ? await this.retrieve(paymentOrId) - : paymentOrId - - if (payment?.captured_at) { - return payment - } - - return await this.atomicPhase_(async (manager: EntityManager) => { - let captureError: Error | null = null - const capturedPayment = await this.paymentProviderService_ - .withTransaction(manager) - .capturePayment(payment) - .catch((err) => { - captureError = err - }) - - if (!capturedPayment) { - await this.eventBusService_ - .withTransaction(manager) - .emit(PaymentService.Events.PAYMENT_CAPTURE_FAILED, { - ...payment, - error: captureError, - }) - - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - `Failed to capture Payment ${payment.id}` - ) - } - - await this.eventBusService_ - .withTransaction(manager) - .emit(PaymentService.Events.PAYMENT_CAPTURED, capturedPayment) - - return capturedPayment - }) - } - - /** - * refunds a payment. - * @param paymentOrId - the id or the class instance of the payment - * @param amount - the amount to be refunded from the payment - * @param reason - the refund reason - * @param note - additional note of the refund - * @return the refund created. - */ - async refund( - paymentOrId: string | Payment, - amount: number, - reason: string, - note?: string - ): Promise { - const payment = - typeof paymentOrId === "string" - ? await this.retrieve(paymentOrId) - : paymentOrId - - return await this.atomicPhase_(async (manager: EntityManager) => { - if (!payment.captured_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Payment ${payment.id} is not captured` - ) - } - - const refundable = payment.amount - payment.amount_refunded - if (amount > refundable) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Only ${refundable} can be refunded from Payment ${payment.id}` - ) - } - - let refundError: Error | null = null - const refund = await this.paymentProviderService_ - .withTransaction(manager) - .refundFromPayment(payment, amount, reason, note) - .catch((err) => { - refundError = err - }) - - if (!refund) { - await this.eventBusService_ - .withTransaction(manager) - .emit(PaymentService.Events.REFUND_FAILED, { - ...payment, - error: refundError, - }) - - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - `Failed to refund Payment ${payment.id}` - ) - } - - await this.eventBusService_ - .withTransaction(manager) - .emit(PaymentService.Events.REFUND_CREATED, refund) - - return refund - }) - } -} diff --git a/packages/medusa/src/services/price-list.ts b/packages/medusa/src/services/price-list.ts deleted file mode 100644 index 4e79cfe00c..0000000000 --- a/packages/medusa/src/services/price-list.ts +++ /dev/null @@ -1,565 +0,0 @@ -import { MedusaError, isDefined } from "medusa-core-utils" -import { DeepPartial, EntityManager } from "typeorm" -import { CustomerGroup, PriceList, Product, ProductVariant } from "../models" -import { FindConfig, Selector } from "../types/common" -import { - CreatePriceListInput, - FilterablePriceListProps, - PriceListPriceCreateInput, - PriceListPriceUpdateInput, - UpdatePriceListInput, -} from "../types/price-list" - -import { FlagRouter, promiseAll } from "@medusajs/utils" -import { CustomerGroupService } from "." -import { TransactionBaseService } from "../interfaces" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { MoneyAmountRepository } from "../repositories/money-amount" -import { PriceListRepository } from "../repositories/price-list" -import { ProductVariantRepository } from "../repositories/product-variant" -import { FilterableProductProps } from "../types/product" -import { FilterableProductVariantProps } from "../types/product-variant" -import { buildQuery } from "../utils" -import ProductService from "./product" -import ProductVariantService from "./product-variant" -import RegionService from "./region" - -type PriceListConstructorProps = { - manager: EntityManager - customerGroupService: CustomerGroupService - regionService: RegionService - productService: ProductService - productVariantService: ProductVariantService - priceListRepository: typeof PriceListRepository - moneyAmountRepository: typeof MoneyAmountRepository - productVariantRepository: typeof ProductVariantRepository - featureFlagRouter: FlagRouter -} - -/** - * Provides layer to manipulate product tags. - */ -class PriceListService extends TransactionBaseService { - protected readonly customerGroupService_: CustomerGroupService - protected readonly regionService_: RegionService - protected readonly productService_: ProductService - protected readonly variantService_: ProductVariantService - protected readonly priceListRepo_: typeof PriceListRepository - protected readonly moneyAmountRepo_: typeof MoneyAmountRepository - protected readonly productVariantRepo_: typeof ProductVariantRepository - protected readonly featureFlagRouter_: FlagRouter - - constructor({ - customerGroupService, - regionService, - productService, - productVariantService, - priceListRepository, - moneyAmountRepository, - productVariantRepository, - featureFlagRouter, - }: PriceListConstructorProps) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.customerGroupService_ = customerGroupService - this.productService_ = productService - this.variantService_ = productVariantService - this.regionService_ = regionService - this.priceListRepo_ = priceListRepository - this.moneyAmountRepo_ = moneyAmountRepository - this.productVariantRepo_ = productVariantRepository - this.featureFlagRouter_ = featureFlagRouter - } - - /** - * Retrieves a product tag by id. - * @param {string} priceListId - the id of the product tag to retrieve - * @param {Object} config - the config to retrieve the tag by - * @return {Promise} the collection. - */ - async retrieve( - priceListId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(priceListId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"priceListId" must be defined` - ) - } - - const priceListRepo = this.activeManager_.withRepository( - this.priceListRepo_ - ) - - const query = buildQuery({ id: priceListId }, config) - const priceList = await priceListRepo.findOne(query) - - if (!priceList) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Price list with id: ${priceListId} was not found` - ) - } - - return priceList - } - - async listPriceListsVariantIdsMap( - priceListIds: string | string[] - ): Promise<{ [priceListId: string]: string[] }> { - priceListIds = Array.isArray(priceListIds) ? priceListIds : [priceListIds] - - if (!priceListIds.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"priceListIds" must be defined` - ) - } - - const priceListRepo = this.activeManager_.withRepository( - this.priceListRepo_ - ) - - const priceListsVariantIdsMap = - await priceListRepo.listPriceListsVariantIdsMap(priceListIds) - - if (!Object.keys(priceListsVariantIdsMap)?.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `No PriceLists found with ids: ${priceListIds.join(", ")}` - ) - } - - return priceListsVariantIdsMap - } - - /** - * Creates a Price List - * @param priceListObject - the Price List to create - * @return created Price List - */ - async create( - priceListObject: CreatePriceListInput - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const priceListRepo = manager.withRepository(this.priceListRepo_) - const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) - - const { prices, customer_groups, includes_tax, ...rest } = priceListObject - - const rawPriceList: DeepPartial = { - ...rest, - } - - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) - ) { - if (typeof includes_tax !== "undefined") { - rawPriceList.includes_tax = includes_tax - } - } - - const entity = priceListRepo.create(rawPriceList) - - const priceList = await priceListRepo.save(entity) - - if (prices) { - const prices_ = await this.addCurrencyFromRegion(prices) - await moneyAmountRepo.addPriceListPrices(priceList.id, prices_) - } - - if (customer_groups) { - await this.upsertCustomerGroups_(priceList.id, customer_groups) - } - - return await this.retrieve(priceList.id, { - relations: ["prices", "customer_groups"], - }) - }) - } - - /** - * Updates a Price List - * @param {string} id - the id of the Product List to update - * @param {UpdatePriceListInput} update - the update to apply - * @returns {Promise} updated Price List - */ - async update(id: string, update: UpdatePriceListInput): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const priceListRepo = manager.withRepository(this.priceListRepo_) - const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) - - const priceList = await this.retrieve(id, { select: ["id"] }) - - const { prices, customer_groups, includes_tax, ...rest } = update - - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) - ) { - if (typeof includes_tax !== "undefined") { - priceList.includes_tax = includes_tax - } - } - - if (prices) { - const prices_ = await this.addCurrencyFromRegion(prices) - await moneyAmountRepo.updatePriceListPrices(id, prices_) - } - - if (customer_groups) { - await this.upsertCustomerGroups_(id, customer_groups) - } - - for (const [key, value] of Object.entries(rest)) { - if (typeof value === "undefined") { - continue - } - - priceList[key] = value - } - - await priceListRepo.save(priceList) - - return await this.retrieve(id, { - relations: ["prices", "customer_groups"], - }) - }) - } - - /** - * Adds prices to a price list in bulk, optionally replacing all existing prices - * @param id - id of the price list - * @param prices - prices to add - * @param replace - whether to replace existing prices - * @returns {Promise} updated Price List - */ - async addPrices( - id: string, - prices: PriceListPriceCreateInput[], - replace = false - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) - - const priceList = await this.retrieve(id, { select: ["id"] }) - - const prices_ = await this.addCurrencyFromRegion(prices) - await moneyAmountRepo.addPriceListPrices(priceList.id, prices_, replace) - - return await this.retrieve(priceList.id, { - relations: ["prices"], - }) - }) - } - - /** - * Removes prices from a price list and deletes the removed prices in bulk - * @param id - id of the price list - * @param priceIds - ids of the prices to delete - * @returns {Promise} updated Price List - */ - async deletePrices(id: string, priceIds: string[]): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) - - const priceList = await this.retrieve(id, { select: ["id"] }) - - await moneyAmountRepo.deletePriceListPrices(priceList.id, priceIds) - }) - } - - /** - * Removes all prices from a price list and deletes the removed prices in bulk - * @param id - id of the price list - * @returns {Promise} updated Price List - */ - async clearPrices(id: string): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) - const priceList = await this.retrieve(id, { select: ["id"] }) - await moneyAmountRepo.delete({ price_list_id: priceList.id }) - }) - } - - /** - * Deletes a Price List - * Will never fail due to delete being idempotent. - * @param id - id of the price list - * @returns {Promise} empty promise - */ - async delete(id: string): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const priceListRepo = manager.withRepository(this.priceListRepo_) - - const priceList = await priceListRepo.findOne({ where: { id: id } }) - - if (!priceList) { - return Promise.resolve() - } - - await priceListRepo.remove(priceList) - }) - } - - /** - * Lists Price Lists - * @param {Object} selector - the query object for find - * @param {Object} config - the config to be used for find - * @return {Promise} the result of the find operation - */ - async list( - selector: FilterablePriceListProps = {}, - config: FindConfig = { skip: 0, take: 20 } - ): Promise { - const [priceLists] = await this.listAndCount(selector, config) - return priceLists - } - - /** - * Lists Price Lists and adds count - * @param {Object} selector - the query object for find - * @param {Object} config - the config to be used for find - * @return {Promise} the result of the find operation - */ - async listAndCount( - selector: FilterablePriceListProps = {}, - config: FindConfig = { - skip: 0, - take: 20, - } - ): Promise<[PriceList[], number]> { - const priceListRepo = this.activeManager_.withRepository( - this.priceListRepo_ - ) - const { q, ...priceListSelector } = selector - const query = buildQuery(priceListSelector, config) - - return await priceListRepo.listAndCount(query, q) - } - - protected async upsertCustomerGroups_( - priceListId: string, - customerGroups: { id: string }[] - ): Promise { - const priceListRepo = this.activeManager_.withRepository( - this.priceListRepo_ - ) - const priceList = await this.retrieve(priceListId, { select: ["id"] }) - - const groups: CustomerGroup[] = [] - - for (const cg of customerGroups) { - const customerGroup = await this.customerGroupService_.retrieve(cg.id) - groups.push(customerGroup) - } - - priceList.customer_groups = groups - - await priceListRepo.save(priceList) - } - - async listProducts( - priceListId: string, - selector: FilterableProductProps | Selector = {}, - config: FindConfig = { - relations: [], - skip: 0, - take: 20, - }, - requiresPriceList = false - ): Promise<[Product[], number]> { - return await this.atomicPhase_(async (manager: EntityManager) => { - const productVariantRepo = manager.withRepository( - this.productVariantRepo_ - ) - - const [products, count] = await this.productService_ - .withTransaction(manager) - .listAndCount(selector, config) - - const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) - - const productsWithPrices = await promiseAll( - products.map(async (p) => { - if (p.variants?.length) { - p.variants = await promiseAll( - p.variants.map(async (v) => { - const [prices] = - await moneyAmountRepo.findManyForVariantInPriceList( - v.id, - priceListId, - requiresPriceList - ) - - const variant = productVariantRepo.create({ - ...v, - }) - - variant.prices = prices - return variant - }) - ) - } - - return p - }) - ) - - return [productsWithPrices, count] - }) - } - - async listVariants( - priceListId: string, - selector: FilterableProductVariantProps = {}, - config: FindConfig = { - relations: [], - skip: 0, - take: 20, - }, - requiresPriceList = false - ): Promise<[ProductVariant[], number]> { - return await this.atomicPhase_(async (manager: EntityManager) => { - const [variants, count] = await this.variantService_ - .withTransaction(manager) - .listAndCount(selector, config) - - const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) - - const variantsWithPrices = await promiseAll( - variants.map(async (variant) => { - const [prices] = await moneyAmountRepo.findManyForVariantInPriceList( - variant.id, - priceListId, - requiresPriceList - ) - - variant.prices = prices - return variant - }) - ) - - return [variantsWithPrices, count] - }) - } - - public async deleteProductPrices( - priceListId: string, - productIds: string[] - ): Promise<[string[], number]> { - return await this.atomicPhase_(async () => { - const [products, count] = await this.listProducts( - priceListId, - { - id: productIds, - }, - { - relations: ["variants"], - }, - true - ) - - if (count === 0) { - return [[], count] - } - - const priceIds = products - .map(({ variants }) => - variants - .map((variant) => variant.prices.map((price) => price.id)) - .flat() - ) - .flat() - - if (!priceIds.length) { - return [[], 0] - } - - await this.deletePrices(priceListId, priceIds) - return [priceIds, priceIds.length] - }) - } - - public async deleteVariantPrices( - priceListId: string, - variantIds: string[] - ): Promise<[string[], number]> { - return await this.atomicPhase_(async () => { - const [variants, count] = await this.listVariants( - priceListId, - { - id: variantIds, - }, - {}, - true - ) - - if (count === 0) { - return [[], count] - } - - const priceIds = variants - .map((variant) => variant.prices.map((price) => price.id)) - .flat() - - if (!priceIds.length) { - return [[], 0] - } - - await this.deletePrices(priceListId, priceIds) - return [priceIds, priceIds.length] - }) - } - - /** - * Add `currency_code` to an MA record if `region_id`is passed. - * @param prices - a list of PriceListPrice(Create/Update)Input records - * @return {Promise} updated `prices` list - */ - protected async addCurrencyFromRegion< - T extends PriceListPriceUpdateInput | PriceListPriceCreateInput - >(prices: T[]): Promise { - const prices_: typeof prices = [] - - const regionServiceTx = this.regionService_.withTransaction( - this.activeManager_ - ) - - const regions = await regionServiceTx.list( - { - id: [ - ...new Set( - prices - .map((p) => p.region_id) - .filter((p: string | undefined): p is string => !!p) - ), - ], - }, - {} - ) - - const regionsMap = new Map(regions.map((r) => [r.id, r])) - - for (const price of prices) { - const p = { ...price } - - if (p.region_id) { - const region = regionsMap.get(p.region_id) - - p.currency_code = region!.currency_code - } - - prices_.push(p) - } - - return prices_ - } -} - -export default PriceListService diff --git a/packages/medusa/src/services/pricing.ts b/packages/medusa/src/services/pricing.ts deleted file mode 100644 index 21a7fa479f..0000000000 --- a/packages/medusa/src/services/pricing.ts +++ /dev/null @@ -1,668 +0,0 @@ -import { IPricingModuleService, RemoteQueryFunction } from "@medusajs/types" -import { FlagRouter, promiseAll } from "@medusajs/utils" -import { - CustomerService, - ProductVariantService, - RegionService, - TaxProviderService, -} from "." -import { - IPriceSelectionStrategy, - PriceSelectionContext, -} from "../interfaces/price-selection-strategy" -import { Product, ProductVariant, Region, ShippingOption } from "../models" -import { - PricedProduct, - PricedShippingOption, - PricedVariant, - PricingContext, - ProductVariantPricing, - TaxedPricing, -} from "../types/pricing" - -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { TaxServiceRate } from "../types/tax-service" -import { calculatePriceTaxAmount } from "../utils" - -type InjectedDependencies = { - manager: EntityManager - productVariantService: ProductVariantService - taxProviderService: TaxProviderService - regionService: RegionService - customerService: CustomerService - priceSelectionStrategy: IPriceSelectionStrategy - featureFlagRouter: FlagRouter - remoteQuery: RemoteQueryFunction - pricingModuleService: IPricingModuleService -} - -/** - * Allows retrieval of prices. - */ -class PricingService extends TransactionBaseService { - protected readonly regionService: RegionService - protected readonly taxProviderService: TaxProviderService - protected readonly customerService_: CustomerService - protected readonly priceSelectionStrategy: IPriceSelectionStrategy - protected readonly productVariantService: ProductVariantService - protected readonly featureFlagRouter: FlagRouter - - protected get pricingModuleService(): IPricingModuleService { - return this.__container__.pricingModuleService - } - - protected get remoteQuery(): RemoteQueryFunction { - return this.__container__.remoteQuery - } - - constructor({ - productVariantService, - taxProviderService, - regionService, - priceSelectionStrategy, - featureFlagRouter, - customerService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.regionService = regionService - this.taxProviderService = taxProviderService - this.priceSelectionStrategy = priceSelectionStrategy - this.productVariantService = productVariantService - this.customerService_ = customerService - this.featureFlagRouter = featureFlagRouter - } - - /** - * Collects additional information necessary for completing the price - * selection. - * @param context - the price selection context to use - * @return The pricing context - */ - async collectPricingContext( - context: PriceSelectionContext - ): Promise { - let automaticTaxes = false - let taxRate: number | null = null - let currencyCode = context.currency_code - - let region: Region - if (context.region_id) { - region = await this.regionService - .withTransaction(this.activeManager_) - .retrieve(context.region_id, { - select: ["id", "currency_code", "automatic_taxes", "tax_rate"], - }) - - currencyCode = region.currency_code - automaticTaxes = region.automatic_taxes - taxRate = region.tax_rate - } - - return { - price_selection: { - ...context, - currency_code: currencyCode, - }, - automatic_taxes: automaticTaxes, - tax_rate: taxRate, - } - } - - /** - * Gets the prices for a product variant - * @param variantPricing - the prices retrieved from a variant - * @param productRates - the tax rates that the product has applied - * @return The tax related variant prices. - */ - calculateTaxes( - variantPricing: ProductVariantPricing, - productRates: TaxServiceRate[] - ): TaxedPricing { - const rate = productRates.reduce( - (accRate: number, nextTaxRate: TaxServiceRate) => { - return accRate + (nextTaxRate.rate || 0) / 100 - }, - 0 - ) - - const taxedPricing: TaxedPricing = { - original_tax: null, - calculated_tax: null, - original_price_incl_tax: null, - calculated_price_incl_tax: null, - tax_rates: productRates, - } - - if (variantPricing.calculated_price !== null) { - const includesTax = !!( - this.featureFlagRouter.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && variantPricing.calculated_price_includes_tax - ) - taxedPricing.calculated_tax = Math.round( - calculatePriceTaxAmount({ - price: variantPricing.calculated_price, - taxRate: rate, - includesTax, - }) - ) - - taxedPricing.calculated_price_incl_tax = - variantPricing.calculated_price_includes_tax - ? variantPricing.calculated_price - : variantPricing.calculated_price + taxedPricing.calculated_tax - } - - if (variantPricing.original_price !== null) { - const includesTax = !!( - this.featureFlagRouter.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && variantPricing.original_price_includes_tax - ) - taxedPricing.original_tax = Math.round( - calculatePriceTaxAmount({ - price: variantPricing.original_price, - taxRate: rate, - includesTax, - }) - ) - - taxedPricing.original_price_incl_tax = - variantPricing.original_price_includes_tax - ? variantPricing.original_price - : variantPricing.original_price + taxedPricing.original_tax - } - - return taxedPricing - } - - private async getProductVariantPricing_( - data: { - variantId: string - quantity?: number - }[], - context: PricingContext - ): Promise> { - const variantsPricing = await this.priceSelectionStrategy - .withTransaction(this.activeManager_) - .calculateVariantPrice(data, context.price_selection) - - const pricingResultMap = new Map() - - for (const [variantId, pricing] of variantsPricing.entries()) { - const pricingResult: ProductVariantPricing = { - prices: pricing.prices, - original_price: pricing.originalPrice, - calculated_price: pricing.calculatedPrice, - calculated_price_type: pricing.calculatedPriceType, - original_price_includes_tax: pricing.originalPriceIncludesTax, - calculated_price_includes_tax: pricing.calculatedPriceIncludesTax, - original_price_incl_tax: null, - calculated_price_incl_tax: null, - original_tax: null, - calculated_tax: null, - tax_rates: null, - } - - if (context.automatic_taxes && context.price_selection.region_id) { - const taxRates = context.price_selection.tax_rates || [] - const taxResults = this.calculateTaxes(pricingResult, taxRates) - - pricingResult.original_price_incl_tax = - taxResults.original_price_incl_tax - pricingResult.calculated_price_incl_tax = - taxResults.calculated_price_incl_tax - pricingResult.original_tax = taxResults.original_tax - pricingResult.calculated_tax = taxResults.calculated_tax - pricingResult.tax_rates = taxResults.tax_rates - } - - pricingResultMap.set(variantId, pricingResult) - } - - return pricingResultMap - } - - /** - * Gets the prices for a product variant. - * @param variant - * @param context - the price selection context to use - * @return The product variant prices - */ - async getProductVariantPricing( - variant: Pick, - context: PriceSelectionContext | PricingContext - ): Promise { - let pricingContext: PricingContext - if ("automatic_taxes" in context) { - pricingContext = context - } else { - pricingContext = await this.collectPricingContext(context) - } - - let productRates: Map = new Map() - - if ( - pricingContext.automatic_taxes && - pricingContext.price_selection.region_id - ) { - // Here we assume that the variants belongs to the same product since the context is shared - const productId = variant.product_id - productRates = await this.taxProviderService.getRegionRatesForProduct( - productId, - { - id: pricingContext.price_selection.region_id, - tax_rate: pricingContext.tax_rate, - } - ) - pricingContext.price_selection.tax_rates = productRates.get(productId) - } - - const productVariantPricing = await this.getProductVariantPricing_( - [ - { - variantId: variant.id, - quantity: pricingContext.price_selection.quantity, - }, - ], - pricingContext - ) - - return productVariantPricing.get(variant.id)! - } - - /** - * Gets the prices for a product variant by a variant id. - * @param variantId - the id of the variant to get prices for - * @param context - the price selection context to use - * @return The product variant prices - * @deprecated Use {@link getProductVariantsPricing} instead. - */ - async getProductVariantPricingById( - variantId: string, - context: PriceSelectionContext | PricingContext - ): Promise { - let pricingContext: PricingContext - if ("automatic_taxes" in context) { - pricingContext = context - } else { - pricingContext = await this.collectPricingContext(context) - } - - let productRates: TaxServiceRate[] = [] - if ( - pricingContext.automatic_taxes && - pricingContext.price_selection.region_id - ) { - const { product_id } = await this.productVariantService - .withTransaction(this.activeManager_) - .retrieve(variantId, { select: ["id", "product_id"] }) - - const regionRatesForProduct = await this.taxProviderService - .withTransaction(this.activeManager_) - .getRegionRatesForProduct([product_id], { - id: pricingContext.price_selection.region_id, - tax_rate: pricingContext.tax_rate, - }) - - productRates = regionRatesForProduct.get(product_id)! - } - - pricingContext.price_selection.tax_rates = productRates - const productVariantPricing = await this.getProductVariantPricing_( - [{ variantId }], - pricingContext - ) - - return productVariantPricing.get(variantId)! - } - - /** - * Gets the prices for a collection of variants. - * @param data - * @param context - the price selection context to use - * @return The product variant prices - */ - async getProductVariantsPricing( - data: { variantId: string; quantity?: number }[], - context: PriceSelectionContext | PricingContext - ): Promise<{ [variant_id: string]: ProductVariantPricing }> { - let pricingContext: PricingContext - if ("automatic_taxes" in context) { - pricingContext = context - } else { - pricingContext = await this.collectPricingContext(context) - } - - const dataMap = new Map(data.map((d) => [d.variantId, d])) - - const variants = await this.productVariantService - .withTransaction(this.activeManager_) - .list( - { id: data.map((d) => d.variantId) }, - { select: ["id", "product_id"] } - ) - - let productsRatesMap: Map = new Map() - - if (pricingContext.price_selection.region_id) { - // Here we assume that the variants belongs to the same product since the context is shared - const productId = variants[0]?.product_id - productsRatesMap = await this.taxProviderService - .withTransaction(this.activeManager_) - .getRegionRatesForProduct(productId, { - id: pricingContext.price_selection.region_id, - tax_rate: pricingContext.tax_rate, - }) - - pricingContext.price_selection.tax_rates = - productsRatesMap.get(productId)! - } - - const variantsPricingMap = await this.getProductVariantPricing_( - variants.map((v) => ({ - variantId: v.id, - quantity: dataMap.get(v.id)!.quantity, - })), - pricingContext - ) - - const pricingResult: { [variant_id: string]: ProductVariantPricing } = {} - for (const { variantId } of data) { - pricingResult[variantId] = variantsPricingMap.get(variantId)! - } - - return pricingResult - } - - private async getProductPricing_( - data: { productId: string; variants: ProductVariant[] }[], - context: PricingContext - ): Promise>> { - let taxRatesMap: Map - - if (context.automatic_taxes && context.price_selection.region_id) { - taxRatesMap = await this.taxProviderService - .withTransaction(this.activeManager_) - .getRegionRatesForProduct( - data.map((d) => d.productId), - { - id: context.price_selection.region_id, - tax_rate: context.tax_rate, - } - ) - } - - const productsPricingMap = new Map< - string, - Record - >() - - await promiseAll( - data.map(async ({ productId, variants }) => { - const pricingData = variants.map((variant) => { - return { variantId: variant.id } - }) - - const context_ = { ...context } - if (context_.automatic_taxes && context_.price_selection.region_id) { - context_.price_selection.tax_rates = taxRatesMap.get(productId)! - } - - const variantsPricingMap = await this.getProductVariantPricing_( - pricingData, - context_ - ) - - const productVariantsPricing = productsPricingMap.get(productId) || {} - variantsPricingMap.forEach((variantPricing, variantId) => { - productVariantsPricing[variantId] = variantPricing - }) - productsPricingMap.set(productId, productVariantsPricing) - }) - ) - - return productsPricingMap - } - - /** - * Gets all the variant prices for a product. All the product's variants will - * be fetched. - * @param product - the product to get pricing for. - * @param context - the price selection context to use - * @return A map of variant ids to their corresponding prices - */ - async getProductPricing( - product: Pick, - context: PriceSelectionContext - ): Promise> { - const pricingContext = await this.collectPricingContext(context) - const productPricing = await this.getProductPricing_( - [{ productId: product.id, variants: product.variants }], - pricingContext - ) - return productPricing.get(product.id)! - } - - /** - * Gets all the variant prices for a product by the product id - * @param productId - the id of the product to get prices for - * @param context - the price selection context to use - * @return A map of variant ids to their corresponding prices - */ - async getProductPricingById( - productId: string, - context: PriceSelectionContext - ): Promise> { - const pricingContext = await this.collectPricingContext(context) - const variants = await this.productVariantService.list( - { product_id: productId }, - { select: ["id"] } - ) - const productPricing = await this.getProductPricing_( - [{ productId, variants }], - pricingContext - ) - return productPricing.get(productId)! - } - - /** - * Set additional prices on a list of product variants. - * @param variants - * @param context - the price selection context to use - * @return A list of products with variants decorated with prices - */ - async setVariantPrices( - variants: ProductVariant[], - context: PriceSelectionContext = {} - ): Promise { - const pricingContext = await this.collectPricingContext(context) - - const variantsPricingMap = await this.getProductVariantsPricing( - variants.map((v) => ({ - variantId: v.id, - quantity: context.quantity, - })), - pricingContext - ) - - return variants.map((variant) => { - const variantPricing = variantsPricingMap[variant.id] - Object.assign(variant, variantPricing) - return variant as unknown as PricedVariant - }) - } - - /** - * Set additional prices on a list of products. - * @param products - list of products on which to set additional prices - * @param context - the price selection context to use - * @return A list of products with variants decorated with prices - */ - async setProductPrices( - products: Product[], - context: PriceSelectionContext = {} - ): Promise<(Product | PricedProduct)[]> { - const pricingContext = await this.collectPricingContext(context) - - const pricingData = products - .filter((p) => p.variants.length) - .map((product) => ({ - productId: product.id, - variants: product.variants, - })) - - const productsVariantsPricingMap = await this.getProductPricing_( - pricingData, - pricingContext - ) - - return products.map((product) => { - if (!product?.variants?.length) { - return product - } - - product.variants.map((productVariant): PricedVariant => { - const variantPricing = productsVariantsPricingMap.get(product.id)! - const pricing = variantPricing[productVariant.id] - - Object.assign(productVariant, pricing) - return productVariant as unknown as PricedVariant - }) - - return product - }) - } - - async setAdminVariantPricing( - variants: ProductVariant[], - context: PriceSelectionContext = {} - ): Promise { - return await this.setVariantPrices(variants, context) - } - - async setAdminProductPricing( - products: Product[] - ): Promise<(Product | PricedProduct)[]> { - return await this.setProductPrices(products) - } - - /** - * Gets the prices for a shipping option. - * @param shippingOption - the shipping option to get prices for - * @param context - the price selection context to use - * @return The shipping option prices - */ - async getShippingOptionPricing( - shippingOption: ShippingOption, - context: PriceSelectionContext | PricingContext - ): Promise { - let pricingContext: PricingContext - if ("automatic_taxes" in context) { - pricingContext = context - } else { - pricingContext = - (context as PricingContext) ?? - (await this.collectPricingContext(context)) - } - - let shippingOptionRates: TaxServiceRate[] = [] - if ( - pricingContext.automatic_taxes && - pricingContext.price_selection.region_id - ) { - shippingOptionRates = await this.taxProviderService - .withTransaction(this.activeManager_) - .getRegionRatesForShipping(shippingOption.id, { - id: pricingContext.price_selection.region_id, - tax_rate: pricingContext.tax_rate, - }) - } - - const price = shippingOption.amount || 0 - const rate = shippingOptionRates.reduce( - (accRate: number, nextTaxRate: TaxServiceRate) => { - return accRate + (nextTaxRate.rate || 0) / 100 - }, - 0 - ) - - const includesTax = - this.featureFlagRouter.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && shippingOption.includes_tax - - const taxAmount = Math.round( - calculatePriceTaxAmount({ - taxRate: rate, - price, - includesTax, - }) - ) - const totalInclTax = includesTax ? price : price + taxAmount - - return { - ...shippingOption, - price_incl_tax: totalInclTax, - tax_rates: shippingOptionRates, - tax_amount: taxAmount, - } - } - - /** - * Set additional prices on a list of shipping options. - * @param shippingOptions - list of shipping options on which to set additional prices - * @param context - the price selection context to use - * @return A list of shipping options with prices - */ - async setShippingOptionPrices( - shippingOptions: ShippingOption[], - context: Omit = {} - ): Promise { - const regions = new Set() - - for (const shippingOption of shippingOptions) { - regions.add(shippingOption.region_id) - } - - const contexts = await promiseAll( - [...regions].map(async (regionId) => { - return { - context: await this.collectPricingContext({ - ...context, - region_id: regionId, - }), - region_id: regionId, - } - }) - ) - - const shippingOptionPricingPromises: Promise[] = [] - - shippingOptions.map(async (shippingOption) => { - const pricingContext = contexts.find( - (c) => c.region_id === shippingOption.region_id - ) - - if (!pricingContext) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Could not find pricing context for shipping option" - ) - } - - shippingOptionPricingPromises.push( - this.getShippingOptionPricing(shippingOption, pricingContext.context) - ) - }) - - return await promiseAll(shippingOptionPricingPromises) - } -} - -export default PricingService diff --git a/packages/medusa/src/services/product-category.ts b/packages/medusa/src/services/product-category.ts deleted file mode 100644 index b317f29e2c..0000000000 --- a/packages/medusa/src/services/product-category.ts +++ /dev/null @@ -1,546 +0,0 @@ -import { selectorConstraintsToString } from "@medusajs/utils" -import { isDefined, MedusaError } from "medusa-core-utils" -import { Between, EntityManager, MoreThanOrEqual, Not } from "typeorm" -import { EventBusService } from "." -import { TransactionBaseService } from "../interfaces" -import { ProductCategory } from "../models" -import { ProductCategoryRepository } from "../repositories/product-category" -import { - FindConfig, - QuerySelector, - Selector, - TreeQuerySelector, -} from "../types/common" -import { - CreateProductCategoryInput, - ReorderConditions, - tempReorderRank, - UpdateProductCategoryInput, -} from "../types/product-category" -import { buildQuery, nullableValue, setMetadata } from "../utils" - -type InjectedDependencies = { - manager: EntityManager - eventBusService: EventBusService - productCategoryRepository: typeof ProductCategoryRepository -} - -/** - * Provides layer to manipulate product categories. - */ -class ProductCategoryService extends TransactionBaseService { - protected readonly productCategoryRepo_: typeof ProductCategoryRepository - protected readonly eventBusService_: EventBusService - - static Events = { - CREATED: "product-category.created", - UPDATED: "product-category.updated", - DELETED: "product-category.deleted", - } - - constructor({ - productCategoryRepository, - eventBusService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.eventBusService_ = eventBusService - this.productCategoryRepo_ = productCategoryRepository - } - - /** - * Lists product category based on the provided parameters and includes the count of - * product category that match the query. - * @param selector - Filter options for product category. - * @param config - Configuration for query. - * @param treeSelector - Filter options for product category tree relations - * @return an array containing the product category as - * the first element and the total count of product category that matches the query - * as the second element. - */ - async listAndCount( - selector: TreeQuerySelector, - config: FindConfig = { - skip: 0, - take: 100, - }, - treeSelector: QuerySelector = {} - ): Promise<[ProductCategory[], number]> { - const includeDescendantsTree = !!selector.include_descendants_tree - delete selector.include_descendants_tree - - const productCategoryRepo = this.activeManager_.withRepository( - this.productCategoryRepo_ - ) - - const selector_ = { ...selector } - let q: string | undefined - - if ("q" in selector_) { - q = selector_.q - delete selector_.q - } - - const query = buildQuery(selector_, config) - - return await productCategoryRepo.getFreeTextSearchResultsAndCount( - query, - q, - treeSelector, - includeDescendantsTree - ) - } - - /** - * A generic retrieve for fining product categories by different attributes. - * - * @param config - the config of the product category to retrieve. - * @param selector - * @param treeSelector - * @return the product category. - */ - protected async retrieve_( - config: FindConfig = {}, - selector: Selector = {}, - treeSelector: QuerySelector = {} - ) { - const productCategoryRepo = this.activeManager_.withRepository( - this.productCategoryRepo_ - ) - - const query = buildQuery(selector, config) - const productCategory = await productCategoryRepo.findOneWithDescendants( - query, - treeSelector - ) - - if (!productCategory) { - const selectorConstraints = selectorConstraintsToString(selector) - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `ProductCategory with ${selectorConstraints} was not found` - ) - } - - return productCategory - } - - /** - * Retrieves a product category by id. - * @param productCategoryId - the id of the product category to retrieve. - * @param config - the config of the product category to retrieve. - * @param selector - * @param treeSelector - * @return the product category. - */ - async retrieve( - productCategoryId: string, - config: FindConfig = {}, - selector: Selector = {}, - treeSelector: QuerySelector = {} - ): Promise { - if (!isDefined(productCategoryId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"productCategoryId" must be defined` - ) - } - - const selectors = Object.assign({ id: productCategoryId }, selector) - return this.retrieve_(config, selectors, treeSelector) - } - - /** - * Retrieves a product category by handle. - * - * @param handle - the handle of the category - * @param config - the config of the product category to retrieve. - * @param selector - * @param treeSelector - * @return the product category. - */ - async retrieveByHandle( - handle: string, - config: FindConfig = {}, - selector: Selector = {}, - treeSelector: QuerySelector = {} - ) { - if (!isDefined(handle)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"handle" must be defined` - ) - } - - const selectors = Object.assign({ handle }, selector) - return this.retrieve_(config, selectors, treeSelector) - } - - /** - * Creates a product category - * @param productCategoryInput - parameters to create a product category - * @return created product category - */ - async create( - productCategoryInput: CreateProductCategoryInput - ): Promise { - return await this.atomicPhase_(async (manager) => { - const pcRepo = manager.withRepository(this.productCategoryRepo_) - const siblingCount = await pcRepo.countBy({ - parent_category_id: nullableValue( - productCategoryInput.parent_category_id - ), - }) - - productCategoryInput.rank = siblingCount - - await this.transformParentIdToEntity(productCategoryInput) - - let productCategory = pcRepo.create(productCategoryInput) - productCategory = await pcRepo.save(productCategory) - - await this.eventBusService_ - .withTransaction(manager) - .emit(ProductCategoryService.Events.CREATED, { - id: productCategory.id, - }) - - return productCategory - }) - } - - /** - * Updates a product category - * @param productCategoryId - id of product category to update - * @param productCategoryInput - parameters to update in product category - * @return updated product category - */ - async update( - productCategoryId: string, - productCategoryInput: UpdateProductCategoryInput - ): Promise { - return await this.atomicPhase_(async (manager) => { - let productCategory = await this.retrieve(productCategoryId) - - const productCategoryRepo = manager.withRepository( - this.productCategoryRepo_ - ) - - const { metadata, ...rest } = productCategoryInput - - if (metadata) { - productCategory.metadata = setMetadata(productCategory, metadata) - } - - const conditions = this.fetchReorderConditions( - productCategory, - productCategoryInput - ) - - if (conditions.shouldChangeRank || conditions.shouldChangeParent) { - productCategoryInput.rank = tempReorderRank - } - - await this.transformParentIdToEntity(productCategoryInput) - - for (const key in productCategoryInput) { - if (isDefined(productCategoryInput[key])) { - productCategory[key] = productCategoryInput[key] - } - } - - productCategory = await productCategoryRepo.save(productCategory) - - await this.performReordering(productCategoryRepo, conditions) - await this.eventBusService_ - .withTransaction(manager) - .emit(ProductCategoryService.Events.UPDATED, { - id: productCategory.id, - }) - - return productCategory - }) - } - - /** - * Deletes a product category - * - * @param productCategoryId is the id of the product category to delete - * @return a promise - */ - async delete(productCategoryId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const productCategoryRepository: typeof ProductCategoryRepository = - manager.withRepository(this.productCategoryRepo_) - - const productCategory = await this.retrieve(productCategoryId, { - relations: ["category_children"], - }).catch((err) => void 0) - - if (!productCategory) { - return - } - - const conditions = this.fetchReorderConditions( - productCategory, - { - parent_category_id: productCategory.parent_category_id, - rank: productCategory.rank, - }, - true - ) - - if (productCategory.category_children.length > 0) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Deleting ProductCategory (${productCategoryId}) with category children is not allowed` - ) - } - - await productCategoryRepository.delete(productCategory.id) - await this.performReordering(productCategoryRepository, conditions) - - await this.eventBusService_ - .withTransaction(manager) - .emit(ProductCategoryService.Events.DELETED, { - id: productCategory.id, - }) - }) - } - - /** - * Add a batch of product to a product category - * @param productCategoryId - The id of the product category on which to add the products - * @param productIds - The products ids to attach to the product category - * @return the product category on which the products have been added - */ - async addProducts( - productCategoryId: string, - productIds: string[] - ): Promise { - return await this.atomicPhase_(async (manager) => { - const productCategoryRepository = manager.withRepository( - this.productCategoryRepo_ - ) - - await productCategoryRepository.addProducts(productCategoryId, productIds) - }) - } - - /** - * Remove a batch of product from a product category - * @param productCategoryId - The id of the product category on which to remove the products - * @param productIds - The products ids to remove from the product category - * @return the product category on which the products have been removed - */ - async removeProducts( - productCategoryId: string, - productIds: string[] - ): Promise { - return await this.atomicPhase_(async (manager) => { - const productCategoryRepository = manager.withRepository( - this.productCategoryRepo_ - ) - - await productCategoryRepository.removeProducts( - productCategoryId, - productIds - ) - }) - } - - protected fetchReorderConditions( - productCategory: ProductCategory, - input: UpdateProductCategoryInput, - shouldDeleteElement = false - ): ReorderConditions { - const originalParentId = productCategory.parent_category_id - const targetParentId = input.parent_category_id - const originalRank = productCategory.rank - const targetRank = input.rank - const shouldChangeParent = - targetParentId !== undefined && targetParentId !== originalParentId - const shouldChangeRank = - shouldChangeParent || - (isDefined(targetRank) && originalRank !== targetRank) - - return { - targetCategoryId: productCategory.id, - originalParentId, - targetParentId, - originalRank, - targetRank, - shouldChangeParent, - shouldChangeRank, - shouldIncrementRank: false, - shouldDeleteElement, - } - } - - protected async performReordering( - repository: typeof ProductCategoryRepository, - conditions: ReorderConditions - ): Promise { - const { shouldChangeParent, shouldChangeRank, shouldDeleteElement } = - conditions - - if (!(shouldChangeParent || shouldChangeRank || shouldDeleteElement)) { - return - } - - // If we change parent, we need to shift the siblings to eliminate the - // rank occupied by the targetCategory in the original parent. - shouldChangeParent && - (await this.shiftSiblings(repository, { - ...conditions, - targetRank: conditions.originalRank, - targetParentId: conditions.originalParentId, - })) - - // If we change parent, we need to shift the siblings of the new parent - // to create a rank that the targetCategory will occupy. - shouldChangeParent && - shouldChangeRank && - (await this.shiftSiblings(repository, { - ...conditions, - shouldIncrementRank: true, - })) - - // If we only change rank, we need to shift the siblings - // to create a rank that the targetCategory will occupy. - ;((!shouldChangeParent && shouldChangeRank) || shouldDeleteElement) && - (await this.shiftSiblings(repository, { - ...conditions, - targetParentId: conditions.originalParentId, - })) - } - - protected async shiftSiblings( - repository: typeof ProductCategoryRepository, - conditions: ReorderConditions - ): Promise { - let { shouldIncrementRank, targetRank } = conditions - const { - shouldChangeParent, - originalRank, - targetParentId, - targetCategoryId, - shouldDeleteElement, - } = conditions - - // The current sibling count will replace targetRank if - // targetRank is greater than the count of siblings. - const siblingCount = await repository.countBy({ - parent_category_id: nullableValue(targetParentId), - id: Not(targetCategoryId), - }) - - // The category record that will be placed at the requested rank - // We've temporarily placed it at a temporary rank that is - // beyond a reasonable value (tempReorderRank) - const targetCategory = await repository.findOne({ - where: { - id: targetCategoryId, - parent_category_id: nullableValue(targetParentId), - rank: tempReorderRank, - }, - }) - - // If the targetRank is not present, or if targetRank is beyond the - // rank of the last category, we set the rank as the last rank - if (targetRank === undefined || targetRank > siblingCount) { - targetRank = siblingCount - } - - let rankCondition - - // If parent doesn't change, we only need to get the ranks - // in between the original rank and the target rank. - if (shouldChangeParent || shouldDeleteElement) { - rankCondition = MoreThanOrEqual(targetRank) - } else if (originalRank > targetRank) { - shouldIncrementRank = true - rankCondition = Between(targetRank, originalRank) - } else { - shouldIncrementRank = false - rankCondition = Between(originalRank, targetRank) - } - - // Scope out the list of siblings that we need to shift up or down - const siblingsToShift = await repository.find({ - where: { - parent_category_id: nullableValue(targetParentId), - rank: rankCondition, - id: Not(targetCategoryId), - }, - order: { - // depending on whether we shift up or down, we order accordingly - rank: shouldIncrementRank ? "DESC" : "ASC", - }, - }) - - // Depending on the conditions, we get a subset of the siblings - // and independently shift them up or down a rank - for (let index = 0; index < siblingsToShift.length; index++) { - const sibling = siblingsToShift[index] - - // Depending on the condition, we could also have the targetCategory - // in the siblings list, we skip shifting the target until all other siblings - // have been shifted. - if (sibling.id === targetCategoryId) { - continue - } - - sibling.rank = shouldIncrementRank ? ++sibling.rank : --sibling.rank - - await repository.save(sibling) - } - - // The targetCategory will not be present in the query when we are shifting - // siblings of the old parent of the targetCategory. - if (!targetCategory) { - return - } - - // Place the targetCategory in the requested rank - targetCategory.rank = targetRank - await repository.save(targetCategory) - } - - /** - * Accepts an input object and transforms product_category_id - * into product_category entity. - * @param productCategoryInput - params used to create/update - * @return transformed productCategoryInput - */ - protected async transformParentIdToEntity( - productCategoryInput: - | CreateProductCategoryInput - | UpdateProductCategoryInput - ): Promise { - // Typeorm only updates mpath when the category entity of the parent - // is passed into create/save. For this reason, every time we create a - // category, we must fetch the entity and push to create - const parentCategoryId = productCategoryInput.parent_category_id - - if (parentCategoryId === undefined) { - return productCategoryInput - } - - // It is really important that the parentCategory is either null or a record. - // If the null is not explicitly passed to make it a root element, the mpath gets - // incorrectly set - const parentCategory = parentCategoryId - ? await this.retrieve(parentCategoryId) - : null - - productCategoryInput.parent_category = parentCategory - delete productCategoryInput.parent_category_id - - return productCategoryInput - } -} - -export default ProductCategoryService diff --git a/packages/medusa/src/services/product-collection.ts b/packages/medusa/src/services/product-collection.ts deleted file mode 100644 index 4ca80995f0..0000000000 --- a/packages/medusa/src/services/product-collection.ts +++ /dev/null @@ -1,345 +0,0 @@ -import { isDefined, MedusaError } from "medusa-core-utils" -import { - EntityManager, - FindManyOptions, - FindOptionsWhere, - ILike, -} from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { ProductCollection } from "../models" -import { ProductRepository } from "../repositories/product" -import { ProductCollectionRepository } from "../repositories/product-collection" -import { ExtendedFindConfig, FindConfig, Selector } from "../types/common" -import { - CreateProductCollection, - UpdateProductCollection, -} from "../types/product-collection" -import { buildQuery, isString, setMetadata } from "../utils" -import EventBusService from "./event-bus" - -type InjectedDependencies = { - manager: EntityManager - eventBusService: EventBusService - productRepository: typeof ProductRepository - productCollectionRepository: typeof ProductCollectionRepository -} - -type ListAndCountSelector = Selector & { - q?: string - discount_condition_id?: string -} - -/** - * Provides layer to manipulate product collections. - */ -class ProductCollectionService extends TransactionBaseService { - protected readonly eventBus_: EventBusService - // eslint-disable-next-line max-len - protected readonly productCollectionRepository_: typeof ProductCollectionRepository - protected readonly productRepository_: typeof ProductRepository - - static readonly Events = { - CREATED: "product-collection.created", - UPDATED: "product-collection.updated", - DELETED: "product-collection.deleted", - PRODUCTS_ADDED: "product-collection.products_added", - PRODUCTS_REMOVED: "product-collection.products_removed", - } - - constructor({ - productCollectionRepository, - productRepository, - eventBusService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.productCollectionRepository_ = productCollectionRepository - this.productRepository_ = productRepository - this.eventBus_ = eventBusService - } - - /** - * Retrieves a product collection by id. - * @param collectionId - the id of the collection to retrieve. - * @param config - the config of the collection to retrieve. - * @return the collection. - */ - async retrieve( - collectionId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(collectionId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"collectionId" must be defined` - ) - } - - const collectionRepo = this.activeManager_.withRepository( - this.productCollectionRepository_ - ) - - const query = buildQuery({ id: collectionId }, config) - const collection = await collectionRepo.findOne(query) - - if (!collection) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Product collection with id: ${collectionId} was not found` - ) - } - - return collection - } - - /** - * Retrieves a product collection by id. - * @param collectionHandle - the handle of the collection to retrieve. - * @param config - query config for request - * @return the collection. - */ - async retrieveByHandle( - collectionHandle: string, - config: FindConfig = {} - ): Promise { - const collectionRepo = this.activeManager_.withRepository( - this.productCollectionRepository_ - ) - - const query = buildQuery({ handle: collectionHandle }, config) - const collection = await collectionRepo.findOne(query) - - if (!collection) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Product collection with handle: ${collectionHandle} was not found` - ) - } - - return collection - } - - /** - * Creates a product collection - * @param collection - the collection to create - * @return created collection - */ - async create( - collection: CreateProductCollection - ): Promise { - return await this.atomicPhase_(async (manager) => { - const collectionRepo = manager.withRepository( - this.productCollectionRepository_ - ) - let productCollection = collectionRepo.create(collection) - productCollection = await collectionRepo.save(productCollection); - - await this.eventBus_ - .withTransaction(manager) - .emit(ProductCollectionService.Events.CREATED, { - id: productCollection.id, - }) - - return productCollection - }) - } - - /** - * Updates a product collection - * @param collectionId - id of collection to update - * @param update - update object - * @return update collection - */ - async update( - collectionId: string, - update: UpdateProductCollection - ): Promise { - return await this.atomicPhase_(async (manager) => { - const collectionRepo = manager.withRepository( - this.productCollectionRepository_ - ) - - let productCollection = await this.retrieve(collectionId) - - const { metadata, ...rest } = update - - if (metadata) { - productCollection.metadata = setMetadata(productCollection, metadata) - } - - for (const [key, value] of Object.entries(rest)) { - productCollection[key] = value - } - - productCollection = await collectionRepo.save(productCollection) - - await this.eventBus_ - .withTransaction(manager) - .emit(ProductCollectionService.Events.UPDATED, { - id: productCollection.id, - }) - - return productCollection - }) - } - - /** - * Deletes a product collection idempotently - * @param collectionId - id of collection to delete - * @return empty promise - */ - async delete(collectionId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const productCollectionRepo = manager.withRepository( - this.productCollectionRepository_ - ) - - const productCollection = await this.retrieve(collectionId) - - if (!productCollection) { - return Promise.resolve() - } - - await productCollectionRepo.softRemove(productCollection) - - await this.eventBus_ - .withTransaction(manager) - .emit(ProductCollectionService.Events.DELETED, { - id: productCollection.id, - }) - - return Promise.resolve() - }) - } - - async addProducts( - collectionId: string, - productIds: string[] - ): Promise { - return await this.atomicPhase_(async (manager) => { - const productRepo = manager.withRepository(this.productRepository_) - - const { id } = await this.retrieve(collectionId, { select: ["id"] }) - - await productRepo.bulkAddToCollection(productIds, id) - - const productCollection = await this.retrieve(id, { - relations: ["products"], - }) - - await this.eventBus_ - .withTransaction(manager) - .emit(ProductCollectionService.Events.PRODUCTS_ADDED, { - productCollection: productCollection, - productIds: productIds, - }) - - return productCollection - }) - } - - async removeProducts( - collectionId: string, - productIds: string[] - ): Promise { - return await this.atomicPhase_(async (manager) => { - const productRepo = manager.withRepository(this.productRepository_) - - const { id } = await this.retrieve(collectionId, { select: ["id"] }) - - await productRepo.bulkRemoveFromCollection(productIds, id) - - const productCollection = await this.retrieve(id, { - relations: ["products"], - }) - - await this.eventBus_ - .withTransaction(manager) - .emit(ProductCollectionService.Events.PRODUCTS_REMOVED, { - productCollection: productCollection, - productIds: productIds, - }) - - return Promise.resolve() - }) - } - - /** - * Lists product collections - * @param selector - the query object for find - * @param config - the config to be used for find - * @return the result of the find operation - */ - async list( - selector: Selector & { - q?: string - discount_condition_id?: string - } = {}, - config = { skip: 0, take: 20 } - ): Promise { - const [collections] = await this.listAndCount(selector, config) - return collections - } - - /** - * Lists product collections and add count. - * @param selector - the query object for find - * @param config - the config to be used for find - * @return the result of the find operation - */ - async listAndCount( - selector: ListAndCountSelector = {}, - config: FindConfig = { skip: 0, take: 20 } - ): Promise<[ProductCollection[], number]> { - const productCollectionRepo = this.activeManager_.withRepository( - this.productCollectionRepository_ - ) - - let q - if (isString(selector.q)) { - q = selector.q - delete selector.q - } - - const query = buildQuery( - selector, - config - ) as FindManyOptions & { - where: { discount_condition_id?: string } - } & ExtendedFindConfig - - if (q) { - const where = query.where as FindOptionsWhere - - delete where.title - delete where.handle - delete where.created_at - delete where.updated_at - - query.where = [ - { - ...where, - title: ILike(`%${q}%`), - }, - { - ...where, - handle: ILike(`%${q}%`), - }, - ] - } - - if (query.where.discount_condition_id) { - const discountConditionId = query.where.discount_condition_id - delete query.where.discount_condition_id - return await productCollectionRepo.findAndCountByDiscountConditionId( - discountConditionId, - query - ) - } - - return await productCollectionRepo.findAndCount(query) - } -} - -export default ProductCollectionService diff --git a/packages/medusa/src/services/product-tag.ts b/packages/medusa/src/services/product-tag.ts deleted file mode 100644 index 80e35b5dfb..0000000000 --- a/packages/medusa/src/services/product-tag.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { EntityManager, FindOptionsWhere, ILike } from "typeorm" -import { ProductTag } from "../models" -import { ProductTagRepository } from "../repositories/product-tag" -import { FindConfig, Selector } from "../types/common" -import { TransactionBaseService } from "../interfaces" -import { buildQuery, isString } from "../utils" - -type ProductTagConstructorProps = { - manager: EntityManager - productTagRepository: typeof ProductTagRepository -} - -class ProductTagService extends TransactionBaseService { - protected readonly tagRepo_: typeof ProductTagRepository - - constructor({ productTagRepository }: ProductTagConstructorProps) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.tagRepo_ = productTagRepository - } - - /** - * Retrieves a product tag by id. - * @param tagId - the id of the product tag to retrieve - * @param config - the config to retrieve the tag by - * @return the collection. - */ - async retrieve( - tagId: string, - config: FindConfig = {} - ): Promise { - const tagRepo = this.activeManager_.withRepository(this.tagRepo_) - - const query = buildQuery({ id: tagId }, config) - const tag = await tagRepo.findOne(query) - - if (!tag) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Product tag with id: ${tagId} was not found` - ) - } - - return tag - } - - /** - * Creates a product tag - * @param tag - the product tag to create - * @return created product tag - */ - async create(tag: Partial): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const tagRepo = manager.withRepository(this.tagRepo_) - - const productTag = tagRepo.create(tag) - return await tagRepo.save(productTag) - }) - } - - /** - * Lists product tags - * @param selector - the query object for find - * @param config - the config to be used for find - * @return the result of the find operation - */ - async list( - selector: Selector & { - q?: string - discount_condition_id?: string - } = {}, - config: FindConfig = { skip: 0, take: 20 } - ): Promise { - const [tags] = await this.listAndCount(selector, config) - return tags - } - - /** - * Lists product tags and adds count. - * @param selector - the query object for find - * @param config - the config to be used for find - * @return the result of the find operation - */ - async listAndCount( - selector: Selector & { - q?: string - discount_condition_id?: string - } = {}, - config: FindConfig = { skip: 0, take: 20 } - ): Promise<[ProductTag[], number]> { - const tagRepo = this.activeManager_.withRepository(this.tagRepo_) - - let q: string | undefined - if (isString(selector.q)) { - q = selector.q - delete selector.q - } - - let discount_condition_id - if (selector.discount_condition_id) { - discount_condition_id = selector.discount_condition_id - delete selector.discount_condition_id - } - - const query = buildQuery(selector, config) - query.where = query.where as FindOptionsWhere - - if (q) { - query.where.value = ILike(`%${q}%`) - } - - if (discount_condition_id) { - const discountConditionId = discount_condition_id as string - return await tagRepo.findAndCountByDiscountConditionId( - discountConditionId, - query - ) - } - - return await tagRepo.findAndCount(query) - } -} - -export default ProductTagService diff --git a/packages/medusa/src/services/product-tax-rate.ts b/packages/medusa/src/services/product-tax-rate.ts deleted file mode 100644 index f63c341ed2..0000000000 --- a/packages/medusa/src/services/product-tax-rate.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ProductTaxRate } from "../models" -import { ProductTaxRateRepository } from "../repositories/product-tax-rate" -import { FindConfig } from "../types/common" -import { FilterableProductTaxRateProps } from "../types/product-tax-rate" -import { TransactionBaseService } from "../interfaces" -import { buildQuery } from "../utils" - -class ProductTaxRateService extends TransactionBaseService { - protected readonly productTaxRateRepository_: typeof ProductTaxRateRepository - - constructor({ productTaxRateRepository }) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.productTaxRateRepository_ = productTaxRateRepository - } - - /** - * @param selector - the query object for find - * @param config - query config object for variant retrieval - * @return the result of the find operation - */ - async list( - selector: FilterableProductTaxRateProps, - config: FindConfig = { relations: [], skip: 0, take: 20 } - ): Promise { - const pTaxRateRepo = this.activeManager_.withRepository( - this.productTaxRateRepository_ - ) - - const query = buildQuery(selector, config) - - return await pTaxRateRepo.find(query) - } -} - -export default ProductTaxRateService diff --git a/packages/medusa/src/services/product-type.ts b/packages/medusa/src/services/product-type.ts deleted file mode 100644 index 3a1a63cd42..0000000000 --- a/packages/medusa/src/services/product-type.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { FindOptionsWhere, ILike } from "typeorm" -import { ProductType } from "../models" -import { ProductTypeRepository } from "../repositories/product-type" -import { ExtendedFindConfig, FindConfig, Selector } from "../types/common" -import { TransactionBaseService } from "../interfaces" -import { buildQuery, isString } from "../utils" - -class ProductTypeService extends TransactionBaseService { - protected readonly typeRepository_: typeof ProductTypeRepository - - constructor({ productTypeRepository }) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.typeRepository_ = productTypeRepository - } - - /** - * Gets a product type by id. - * Throws in case of DB Error and if product was not found. - * @param id - id of the product to get. - * @param config - object that defines what should be included in the - * query response - * @return the result of the find one operation. - */ - async retrieve( - id: string, - config: FindConfig = {} - ): Promise { - const typeRepo = this.activeManager_.withRepository(this.typeRepository_) - - const query = buildQuery({ id }, config) - const type = await typeRepo.findOne(query) - - if (!type) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Product type with id: ${id} was not found` - ) - } - - return type - } - - /** - * Lists product types - * @param selector - the query object for find - * @param config - the config to be used for find - * @return the result of the find operation - */ - async list( - selector: Selector & { - q?: string - discount_condition_id?: string - } = {}, - config: FindConfig = { skip: 0, take: 20 } - ): Promise { - const [productTypes] = await this.listAndCount(selector, config) - return productTypes - } - - /** - * Lists product types and adds count. - * @param selector - the query object for find - * @param config - the config to be used for find - * @return the result of the find operation - */ - async listAndCount( - selector: Selector & { - q?: string - discount_condition_id?: string - } = {}, - config: FindConfig = { skip: 0, take: 20 } - ): Promise<[ProductType[], number]> { - const typeRepo = this.activeManager_.withRepository(this.typeRepository_) - - let q - if (isString(selector.q)) { - q = selector.q - delete selector.q - } - - const query = buildQuery( - selector, - config - ) as ExtendedFindConfig & { - where: FindOptionsWhere & { discount_condition_id?: string } - } - - if (q) { - query.where.value = ILike(`%${q}%`) - } - - if (query.where.discount_condition_id) { - const discountConditionId = query.where.discount_condition_id as string - delete query.where.discount_condition_id - return await typeRepo.findAndCountByDiscountConditionId( - discountConditionId, - query - ) - } - - return await typeRepo.findAndCount(query) - } -} - -export default ProductTypeService diff --git a/packages/medusa/src/services/product-variant-inventory.ts b/packages/medusa/src/services/product-variant-inventory.ts deleted file mode 100644 index bdae64145b..0000000000 --- a/packages/medusa/src/services/product-variant-inventory.ts +++ /dev/null @@ -1,1028 +0,0 @@ -import { - IEventBusService, - IInventoryService, - IStockLocationService, - InventoryItemDTO, - InventoryLevelDTO, - RemoteQueryFunction, - ReservationItemDTO, - ReserveQuantityContext, -} from "@medusajs/types" -import { - FlagRouter, - MedusaError, - MedusaV2Flag, - isDefined, - promiseAll, - remoteQueryObjectFromString, -} from "@medusajs/utils" -import { EntityManager, In } from "typeorm" -import { LineItem, Product, ProductVariant } from "../models" -import { PricedProduct, PricedVariant } from "../types/pricing" - -import { TransactionBaseService } from "../interfaces" -import { ProductVariantInventoryItem } from "../models/product-variant-inventory-item" -import { getSetDifference } from "../utils/diff-set" -import ProductVariantService from "./product-variant" -import SalesChannelInventoryService from "./sales-channel-inventory" -import SalesChannelLocationService from "./sales-channel-location" - -type InjectedDependencies = { - manager: EntityManager - salesChannelLocationService: SalesChannelLocationService - salesChannelInventoryService: SalesChannelInventoryService - productVariantService: ProductVariantService - eventBusService: IEventBusService - featureFlagRouter: FlagRouter - remoteQuery: RemoteQueryFunction -} - -type AvailabilityContext = { - variantInventoryMap?: Map - inventoryLocationMap?: Map -} - -class ProductVariantInventoryService extends TransactionBaseService { - protected manager_: EntityManager - protected transactionManager_: EntityManager | undefined - - protected readonly salesChannelLocationService_: SalesChannelLocationService - protected readonly salesChannelInventoryService_: SalesChannelInventoryService - protected readonly productVariantService_: ProductVariantService - protected readonly eventBusService_: IEventBusService - protected readonly featureFlagRouter_: FlagRouter - protected readonly remoteQuery_: RemoteQueryFunction - - protected get inventoryService_(): IInventoryService { - return this.__container__.inventoryService - } - - protected get stockLocationService_(): IStockLocationService { - return this.__container__.stockLocationService - } - - constructor({ - salesChannelLocationService, - salesChannelInventoryService, - productVariantService, - eventBusService, - featureFlagRouter, - remoteQuery, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.salesChannelLocationService_ = salesChannelLocationService - this.salesChannelInventoryService_ = salesChannelInventoryService - this.productVariantService_ = productVariantService - this.eventBusService_ = eventBusService - this.featureFlagRouter_ = featureFlagRouter - this.remoteQuery_ = remoteQuery - } - - /** - * confirms if requested inventory is available - * @param variantId id of the variant to confirm inventory for - * @param quantity quantity of inventory to confirm is available - * @param context optionally include a sales channel if applicable - * @returns boolean indicating if inventory is available - */ - async confirmInventory( - variantId: string, - quantity: number, - context: { salesChannelId?: string | null } = {} - ): Promise { - if (!variantId) { - return true - } - - const productVariant = await this.productVariantService_ - .withTransaction(this.activeManager_) - .retrieve(variantId, { - select: [ - "id", - "allow_backorder", - "manage_inventory", - "inventory_quantity", - ], - }) - - // If the variant allows backorders or if inventory isn't managed we - // don't need to check inventory - if (productVariant.allow_backorder || !productVariant.manage_inventory) { - return true - } - - if (!this.inventoryService_) { - return productVariant.inventory_quantity >= quantity - } - - const variantInventory = await this.listByVariant(variantId) - - // If there are no inventory items attached to the variant we default - // to true - if (variantInventory.length === 0) { - return true - } - - let locationIds: string[] = [] - if (context.salesChannelId) { - locationIds = await this.salesChannelLocationService_.listLocationIds( - context.salesChannelId - ) - } else { - const stockLocations = await this.stockLocationService_.list( - {}, - { select: ["id"] } - ) - locationIds = stockLocations.map((l) => l.id) - } - - if (locationIds.length === 0) { - return false - } - - const hasInventory = await promiseAll( - variantInventory.map(async (inventoryPart) => { - const itemQuantity = inventoryPart.required_quantity * quantity - return await this.inventoryService_.confirmInventory( - inventoryPart.inventory_item_id, - locationIds, - itemQuantity - ) - }) - ) - - return hasInventory.every(Boolean) - } - - /** - * Retrieves a product variant inventory item by its inventory item ID and variant ID. - * - * @param inventoryItemId - The ID of the inventory item to retrieve. - * @param variantId - The ID of the variant to retrieve. - * @returns A promise that resolves with the product variant inventory item. - */ - async retrieve( - inventoryItemId: string, - variantId: string - ): Promise { - const variantInventoryRepo = this.activeManager_.getRepository( - ProductVariantInventoryItem - ) - - const variantInventory = await variantInventoryRepo.findOne({ - where: { inventory_item_id: inventoryItemId, variant_id: variantId }, - }) - - if (!variantInventory) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Inventory item with id ${inventoryItemId} not found` - ) - } - - return variantInventory - } - - /** - * list registered inventory items - * @param itemIds list inventory item ids - * @returns list of inventory items - */ - async listByItem(itemIds: string[]): Promise { - const variantInventoryRepo = this.activeManager_.getRepository( - ProductVariantInventoryItem - ) - - const variantInventory = await variantInventoryRepo.find({ - where: { inventory_item_id: In(itemIds) }, - }) - - return variantInventory - } - - /** - * List inventory items for a specific variant - * @param variantId variant id - * @returns variant inventory items for the variant id - */ - public async listByVariant( - variantId: string | string[] - ): Promise { - const variantInventoryRepo = this.activeManager_.getRepository( - ProductVariantInventoryItem - ) - - const ids = Array.isArray(variantId) ? variantId : [variantId] - - const variantInventory = await variantInventoryRepo.find({ - where: { variant_id: In(ids) }, - }) - - return variantInventory - } - - /** - * lists variant by inventory item id - * @param itemId item id - * @returns a list of product variants that are associated with the item id - */ - async listVariantsByItem(itemId: string): Promise { - if (!this.inventoryService_) { - return [] - } - - const variantInventory = await this.listByItem([itemId]) - const items = await this.productVariantService_.list({ - id: variantInventory.map((i) => i.variant_id), - }) - - return items - } - - /** - * lists inventory items for a given variant - * @param variantId variant id - * @returns lidt of inventory items for the variant - */ - async listInventoryItemsByVariant( - variantId: string - ): Promise { - if (!this.inventoryService_) { - return [] - } - - const variantInventory = await this.listByVariant(variantId) - const [items] = await this.inventoryService_.listInventoryItems({ - id: variantInventory.map((i) => i.inventory_item_id), - }) - - return items - } - - /** - * Attach a variant to an inventory item - * @returns the variant inventory item - */ - async attachInventoryItem( - attachments: { - /** - * variant id - */ - variantId: string - /** - * inventory item id - */ - inventoryItemId: string - /** - * quantity of variant to attach - */ - requiredQuantity?: number - }[] - ): Promise - async attachInventoryItem( - variantId: string, - inventoryItemId: string, - requiredQuantity?: number - ): Promise - async attachInventoryItem( - variantIdOrAttachments: - | string - | { - variantId: string - inventoryItemId: string - requiredQuantity?: number - }[], - inventoryItemId?: string, - requiredQuantity?: number - ): Promise { - const data = Array.isArray(variantIdOrAttachments) - ? variantIdOrAttachments - : [ - { - variantId: variantIdOrAttachments, - inventoryItemId: inventoryItemId!, - requiredQuantity, - }, - ] - - const invalidDataEntries = data.filter( - (d) => typeof d.requiredQuantity === "number" && d.requiredQuantity < 1 - ) - - if (invalidDataEntries.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `"requiredQuantity" must be greater than 0, the following entries are invalid: ${invalidDataEntries - .map((d) => JSON.stringify(d)) - .join(", ")}` - ) - } - - // Verify that variant exists - let variants - if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) { - variants = await this.remoteQuery_( - remoteQueryObjectFromString({ - entryPoint: "variants", - variables: { - id: data.map((d) => d.variantId), - }, - fields: ["id"], - }) - ) - } else { - variants = await this.productVariantService_ - .withTransaction(this.activeManager_) - .list( - { - id: data.map((d) => d.variantId), - }, - { - select: ["id"], - } - ) - } - - const foundVariantIds = new Set(variants.map((v) => v.id)) - const requestedVariantIds = new Set(data.map((v) => v.variantId)) - if (foundVariantIds.size !== requestedVariantIds.size) { - const difference = getSetDifference(requestedVariantIds, foundVariantIds) - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Variants not found for the following ids: ${[...difference].join( - ", " - )}` - ) - } - - // Verify that item exists - const [inventoryItems] = await this.inventoryService_.listInventoryItems( - { - id: data.map((d) => d.inventoryItemId), - }, - { - select: ["id"], - }, - { - transactionManager: this.activeManager_, - } - ) - - const foundInventoryItemIds = new Set(inventoryItems.map((v) => v.id)) - const requestedInventoryItemIds = new Set( - data.map((v) => v.inventoryItemId) - ) - - if (foundInventoryItemIds.size !== requestedInventoryItemIds.size) { - const difference = getSetDifference( - requestedInventoryItemIds, - foundInventoryItemIds - ) - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Inventory items not found for the following ids: ${[ - ...difference, - ].join(", ")}` - ) - } - - const variantInventoryRepo = this.activeManager_.getRepository( - ProductVariantInventoryItem - ) - - const existingAttachments = await variantInventoryRepo.find({ - where: data.map((d) => ({ - variant_id: d.variantId, - inventory_item_id: d.inventoryItemId, - })), - }) - - const existingMap: Map> = existingAttachments.reduce( - (acc, curr) => { - const existingSet = acc.get(curr.variant_id) || new Set() - existingSet.add(curr.inventory_item_id) - acc.set(curr.variant_id, existingSet) - return acc - }, - new Map() - ) - - const toCreate = ( - await promiseAll( - data.map(async (d) => { - if (existingMap.get(d.variantId)?.has(d.inventoryItemId)) { - return null - } - - return variantInventoryRepo.create({ - variant_id: d.variantId, - inventory_item_id: d.inventoryItemId, - required_quantity: d.requiredQuantity ?? 1, - }) - }) - ) - ).filter( - ( - tc: ProductVariantInventoryItem | null - ): tc is ProductVariantInventoryItem => !!tc - ) - - const createdVariantInventoryItems = await variantInventoryRepo.save( - toCreate - ) - - return createdVariantInventoryItems - } - - /** - * Remove a variant from an inventory item - * @param variantId variant id or undefined if all the variants will be affected - * @param inventoryItemId inventory item id - */ - async detachInventoryItem( - inventoryItemId: string, - variantId?: string - ): Promise { - const variantInventoryRepo = this.activeManager_.getRepository( - ProductVariantInventoryItem - ) - - const where: any = { - inventory_item_id: inventoryItemId, - } - if (variantId) { - where.variant_id = variantId - } - - const varInvItems = await variantInventoryRepo.find({ - where, - }) - - if (varInvItems.length) { - await variantInventoryRepo.remove(varInvItems) - } - } - - /** - * Reserves a quantity of a variant - * @param variantId variant id - * @param quantity quantity to reserve - * @param context optional parameters - */ - async reserveQuantity( - variantId: string, - quantity: number, - context: ReserveQuantityContext = {} - ): Promise { - if (!this.inventoryService_) { - return this.atomicPhase_(async (manager) => { - const variantServiceTx = - this.productVariantService_.withTransaction(manager) - const variant = await variantServiceTx.retrieve(variantId, { - select: ["id", "inventory_quantity"], - }) - await variantServiceTx.update(variant.id, { - inventory_quantity: variant.inventory_quantity - quantity, - }) - return - }) - } - - const toReserve = { - line_item_id: context.lineItemId, - } - - const variantInventory = await this.listByVariant(variantId) - - if (variantInventory.length === 0) { - return - } - - let locationId = context.locationId - const moduleContext = { - transactionManager: this.activeManager_, - } - - if (!isDefined(locationId) && context.salesChannelId) { - const locationIds = await this.salesChannelLocationService_ - .withTransaction(this.activeManager_) - .listLocationIds(context.salesChannelId) - - if (!locationIds.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Must provide location_id or sales_channel_id to a Sales Channel that has associated Stock Locations" - ) - } - - const [locations, count] = - await this.inventoryService_.listInventoryLevels( - { - location_id: locationIds, - inventory_item_id: variantInventory[0].inventory_item_id, - }, - undefined, - moduleContext - ) - - if (count === 0) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Must provide location_id or sales_channel_id to a Sales Channel that has associated locations with inventory levels" - ) - } - - locationId = locations[0].location_id - } - - const reservationItems = - await this.inventoryService_.createReservationItems( - variantInventory.map((inventoryPart) => { - const itemQuantity = inventoryPart.required_quantity * quantity - - return { - ...toReserve, - location_id: locationId as string, - inventory_item_id: inventoryPart.inventory_item_id, - quantity: itemQuantity, - } - }), - moduleContext - ) - - return reservationItems.flat() - } - - /** - * Adjusts the quantity of reservations for a line item by a given amount. - * @param {string} lineItemId - The ID of the line item - * @param {string} variantId - The ID of the variant - * @param {string} locationId - The ID of the location to prefer adjusting quantities at - * @param {number} quantity - The amount to adjust the quantity by - */ - async adjustReservationsQuantityByLineItem( - lineItemId: string, - variantId: string, - locationId: string, - quantity: number - ): Promise { - if (!this.inventoryService_) { - return this.atomicPhase_(async (manager) => { - const variantServiceTx = - this.productVariantService_.withTransaction(manager) - const variant = await variantServiceTx.retrieve(variantId, { - select: ["id", "inventory_quantity", "manage_inventory"], - }) - - if (!variant.manage_inventory) { - return - } - - await variantServiceTx.update(variantId, { - inventory_quantity: variant.inventory_quantity - quantity, - }) - }) - } - - if (quantity > 0) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "You can only reduce reservation quantities using adjustReservationsQuantityByLineItem. If you wish to reserve more use update or create." - ) - } - - const context = { - transactionManager: this.activeManager_, - } - const [reservations, reservationCount] = - await this.inventoryService_.listReservationItems( - { - line_item_id: lineItemId, - }, - { - order: { created_at: "DESC" }, - }, - context - ) - - reservations.sort((a, _) => { - if (a.location_id === locationId) { - return -1 - } - return 0 - }) - - if (reservationCount) { - const inventoryItems = await this.listByVariant(variantId) - const productVariantInventory = inventoryItems[0] - - const deltaUpdate = Math.abs( - quantity * productVariantInventory.required_quantity - ) - - const exactReservation = reservations.find( - (r) => r.quantity === deltaUpdate && r.location_id === locationId - ) - if (exactReservation) { - await this.inventoryService_.deleteReservationItem( - exactReservation.id, - context - ) - return - } - - let remainingQuantity = deltaUpdate - - const reservationsToDelete: ReservationItemDTO[] = [] - let reservationToUpdate: ReservationItemDTO | null = null - for (const reservation of reservations) { - if (reservation.quantity <= remainingQuantity) { - remainingQuantity -= reservation.quantity - reservationsToDelete.push(reservation) - } else { - reservationToUpdate = reservation - break - } - } - - if (reservationsToDelete.length) { - await this.inventoryService_.deleteReservationItem( - reservationsToDelete.map((r) => r.id), - context - ) - } - - if (reservationToUpdate) { - await this.inventoryService_.updateReservationItem( - reservationToUpdate.id, - { - quantity: reservationToUpdate.quantity - remainingQuantity, - }, - context - ) - } - } - } - - /** - * Validate stock at a location for fulfillment items - * @param items Fulfillment Line items to validate quantities for - * @param locationId Location to validate stock at - * @returns nothing if successful, throws error if not - */ - async validateInventoryAtLocation( - items: Omit[], - locationId: string - ) { - if (!this.inventoryService_) { - return - } - - const itemsToValidate = items.filter((item) => !!item.variant_id) - - for (const item of itemsToValidate) { - const pvInventoryItems = await this.listByVariant(item.variant_id!) - - if (!pvInventoryItems.length) { - continue - } - - const context = { - transactionManager: this.activeManager_, - } - - const [inventoryLevels, inventoryLevelCount] = - await this.inventoryService_.listInventoryLevels( - { - inventory_item_id: pvInventoryItems.map((i) => i.inventory_item_id), - location_id: locationId, - }, - undefined, - context - ) - - if (!inventoryLevelCount) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Inventory item for ${item.title} not found at location` - ) - } - - const pviMap: Map = new Map( - pvInventoryItems.map((pvi) => [pvi.inventory_item_id, pvi]) - ) - - for (const inventoryLevel of inventoryLevels) { - const pvInventoryItem = pviMap.get(inventoryLevel.inventory_item_id) - - if ( - !pvInventoryItem || - pvInventoryItem.required_quantity * item.quantity > - inventoryLevel.stocked_quantity - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Insufficient stock for item: ${item.title}` - ) - } - } - } - } - - /** - * delete a reservation of variant quantity - * @param lineItemId line item id - * @param variantId variant id - * @param quantity quantity to release - */ - async deleteReservationsByLineItem( - lineItemId: string | string[], - variantId: string, - quantity: number - ): Promise { - if (!this.inventoryService_) { - return this.atomicPhase_(async (manager) => { - const productVariantServiceTx = - this.productVariantService_.withTransaction(manager) - const variant = await productVariantServiceTx.retrieve(variantId, { - select: ["id", "inventory_quantity", "manage_inventory"], - }) - - if (!variant.manage_inventory) { - return - } - - await productVariantServiceTx.update(variantId, { - inventory_quantity: variant.inventory_quantity + quantity, - }) - }) - } - - const itemIds = Array.isArray(lineItemId) ? lineItemId : [lineItemId] - await this.inventoryService_.deleteReservationItemsByLineItem(itemIds, { - transactionManager: this.activeManager_, - }) - } - - /** - * Adjusts inventory of a variant on a location - * @param variantId variant id - * @param locationId location id - * @param quantity quantity to adjust - */ - async adjustInventory( - variantId: string, - locationId: string, - quantity: number - ): Promise { - if (!this.inventoryService_) { - return this.atomicPhase_(async (manager) => { - const productVariantServiceTx = - this.productVariantService_.withTransaction(manager) - const variant = await productVariantServiceTx.retrieve(variantId, { - select: ["id", "inventory_quantity", "manage_inventory"], - }) - - if (!variant.manage_inventory) { - return - } - - await productVariantServiceTx.update(variantId, { - inventory_quantity: variant.inventory_quantity + quantity, - }) - }) - } - - const variantInventory = await this.listByVariant(variantId) - - if (variantInventory.length === 0) { - return - } - - await promiseAll( - variantInventory.map(async (inventoryPart) => { - const itemQuantity = inventoryPart.required_quantity * quantity - return await this.inventoryService_.adjustInventory( - inventoryPart.inventory_item_id, - locationId, - itemQuantity, - { - transactionManager: this.activeManager_, - } - ) - }) - ) - } - - async setVariantAvailability( - variants: ProductVariant[] | PricedVariant[], - salesChannelId: string | string[] | undefined, - availabilityContext: AvailabilityContext = {} - ): Promise { - if (!this.inventoryService_) { - return variants - } - - const { variantInventoryMap, inventoryLocationMap } = - await this.getAvailabilityContext( - variants.map((v) => v.id), - salesChannelId, - availabilityContext - ) - - return variants.map((variant) => { - if (!variant.id) { - return variant - } - - variant.purchasable = variant.allow_backorder - - if (!variant.manage_inventory) { - variant.purchasable = true - return variant - } - - const variantInventory = variantInventoryMap.get(variant.id) || [] - - if (!variantInventory.length) { - delete variant.inventory_quantity - variant.purchasable = true - return variant - } - - if (!salesChannelId) { - delete variant.inventory_quantity - variant.purchasable = false - return variant - } - - const locations = - inventoryLocationMap.get(variantInventory[0].inventory_item_id) ?? [] - - variant.inventory_quantity = locations.reduce( - (acc, next) => acc + (next.stocked_quantity - next.reserved_quantity), - 0 - ) - - variant.purchasable = - variant.inventory_quantity > 0 || variant.allow_backorder - - return variant - }) - } - - private async getAvailabilityContext( - variants: string[], - salesChannelId: string | string[] | undefined, - existingContext: AvailabilityContext = {} - ): Promise> { - let variantInventoryMap = existingContext.variantInventoryMap - let inventoryLocationMap = existingContext.inventoryLocationMap - - if (!variantInventoryMap) { - variantInventoryMap = new Map() - const variantInventories = await this.listByVariant(variants) - - variantInventories.forEach((inventory) => { - const variantId = inventory.variant_id - const currentInventories = variantInventoryMap!.get(variantId) || [] - currentInventories.push(inventory) - variantInventoryMap!.set(variantId, currentInventories) - }) - } - - const locationIds: string[] = [] - - if (salesChannelId && !inventoryLocationMap) { - const locations = await this.salesChannelLocationService_ - .withTransaction(this.activeManager_) - .listLocationIds(salesChannelId) - locationIds.push(...locations) - } - - if (!inventoryLocationMap) { - inventoryLocationMap = new Map() - } - - if (locationIds.length) { - const [locationLevels] = await this.inventoryService_.listInventoryLevels( - { - location_id: locationIds, - inventory_item_id: [ - ...new Set( - Array.from(variantInventoryMap.values()) - .flat() - .map((i) => i.inventory_item_id) - ), - ], - }, - {}, - { - transactionManager: this.activeManager_, - } - ) - - locationLevels.reduce((acc, curr) => { - if (!acc.has(curr.inventory_item_id)) { - acc.set(curr.inventory_item_id, []) - } - acc.get(curr.inventory_item_id)!.push(curr) - - return acc - }, inventoryLocationMap) - } - - return { - variantInventoryMap, - inventoryLocationMap, - } - } - - async setProductAvailability( - products: (Product | PricedProduct)[], - salesChannelId: string | string[] | undefined - ): Promise<(Product | PricedProduct)[]> { - if (!this.inventoryService_) { - return products - } - - const variantIds: string[] = products - .flatMap((p) => p.variants.map((v: { id?: string }) => v.id) ?? []) - .filter((v): v is string => !!v) - - const availabilityContext = await this.getAvailabilityContext( - variantIds, - salesChannelId - ) - - return await promiseAll( - products.map(async (product) => { - if (!product.variants || product.variants.length === 0) { - return product - } - - product.variants = await this.setVariantAvailability( - product.variants, - salesChannelId, - availabilityContext - ) - - return product - }) - ) - } - - /** - * Get the quantity of a variant from a list of variantInventoryItems - * The inventory quantity of the variant should be equal to the inventory - * item with the smallest stock, adjusted for quantity required to fulfill - * the given variant. - * - * @param variantInventoryItems List of inventoryItems for a given variant, These must all be for the same variant - * @param channelId Sales channel id to fetch availability for - * @returns The available quantity of the variant from the inventoryItems - */ - async getVariantQuantityFromVariantInventoryItems( - variantInventoryItems: ProductVariantInventoryItem[], - channelId: string - ): Promise { - const variantItemsAreMixed = variantInventoryItems.some( - (inventoryItem) => - inventoryItem.variant_id !== variantInventoryItems[0].variant_id - ) - - if (variantInventoryItems.length && variantItemsAreMixed) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "All variant inventory items must belong to the same variant" - ) - } - - const salesChannelInventoryServiceTx = - this.salesChannelInventoryService_.withTransaction(this.activeManager_) - - return Math.min( - ...(await promiseAll( - variantInventoryItems.map(async (variantInventory) => { - // get the total available quantity for the given sales channel - // divided by the required quantity to account for how many of the - // variant we can fulfill at the current time. Take the minimum we - // can fulfill and set that as quantity - return ( - // eslint-disable-next-line max-len - (await salesChannelInventoryServiceTx.retrieveAvailableItemQuantity( - channelId, - variantInventory.inventory_item_id - )) / variantInventory.required_quantity - ) - }) - )) - ) - } -} - -export default ProductVariantInventoryService diff --git a/packages/medusa/src/services/product-variant.ts b/packages/medusa/src/services/product-variant.ts deleted file mode 100644 index f8084b6d97..0000000000 --- a/packages/medusa/src/services/product-variant.ts +++ /dev/null @@ -1,1152 +0,0 @@ -import { - Brackets, - EntityManager, - FindManyOptions, - FindOneOptions, - FindOptionsSelect, - FindOptionsWhere, - ILike, - In, - SelectQueryBuilder, -} from "typeorm" -import { - CreateProductVariantInput, - FilterableProductVariantProps, - GetRegionPriceContext, - ProductVariantPrice, - UpdateProductVariantData, - UpdateProductVariantInput, - UpdateVariantCurrencyPriceData, - UpdateVariantPricesData, - UpdateVariantRegionPriceData, -} from "../types/product-variant" -import { FindConfig, WithRequiredProperty } from "../types/common" -import { - FindWithRelationsOptions, - ProductVariantRepository, -} from "../repositories/product-variant" -import { - IPriceSelectionStrategy, - PriceSelectionContext, - TransactionBaseService, -} from "../interfaces" -import { isDefined, MedusaError } from "medusa-core-utils" -import { - MoneyAmount, - Product, - ProductOptionValue, - ProductVariant, -} from "../models" -import { - buildQuery, - hasChanges, - isObject, - isString, - setMetadata, -} from "../utils" - -import { CartRepository } from "../repositories/cart" -import EventBusService from "./event-bus" -import { MoneyAmountRepository } from "../repositories/money-amount" -import { ProductOptionValueRepository } from "../repositories/product-option-value" -import { ProductRepository } from "../repositories/product" -import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" -import RegionService from "./region" -import { buildRelations, promiseAll } from "@medusajs/utils" - -class ProductVariantService extends TransactionBaseService { - static Events = { - UPDATED: "product-variant.updated", - CREATED: "product-variant.created", - DELETED: "product-variant.deleted", - } - - protected readonly productVariantRepository_: typeof ProductVariantRepository - protected readonly productRepository_: typeof ProductRepository - protected readonly eventBus_: EventBusService - protected readonly regionService_: RegionService - protected readonly priceSelectionStrategy_: IPriceSelectionStrategy - protected readonly moneyAmountRepository_: typeof MoneyAmountRepository - // eslint-disable-next-line max-len - protected readonly productOptionValueRepository_: typeof ProductOptionValueRepository - protected readonly cartRepository_: typeof CartRepository - - constructor({ - productVariantRepository, - productRepository, - eventBusService, - regionService, - moneyAmountRepository, - productOptionValueRepository, - cartRepository, - priceSelectionStrategy, - }) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.productVariantRepository_ = productVariantRepository - this.productRepository_ = productRepository - this.eventBus_ = eventBusService - this.regionService_ = regionService - this.moneyAmountRepository_ = moneyAmountRepository - this.productOptionValueRepository_ = productOptionValueRepository - this.cartRepository_ = cartRepository - this.priceSelectionStrategy_ = priceSelectionStrategy - } - - /** - * Gets a product variant by id. - * @param variantId - the id of the product to get. - * @param config - query config object for variant retrieval. - * @return the product document. - */ - async retrieve( - variantId: string, - config: FindConfig & PriceSelectionContext = { - include_discount_prices: false, - } - ): Promise { - const variantRepo = this.activeManager_.withRepository( - this.productVariantRepository_ - ) - const query = buildQuery({ id: variantId }, config) as FindOneOptions - const variant = await variantRepo.findOne(query) - - if (!variant) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Variant with id: ${variantId} was not found` - ) - } - - return variant - } - - /** - * Gets a product variant by id. - * @param sku - The unique stock keeping unit used to identify the product variant. - * @param config - query config object for variant retrieval. - * @return the product document. - */ - async retrieveBySKU( - sku: string, - config: FindConfig & PriceSelectionContext = { - include_discount_prices: false, - } - ): Promise { - const variantRepo = this.activeManager_.withRepository( - this.productVariantRepository_ - ) - - const priceIndex = config.relations?.indexOf("prices") ?? -1 - if (priceIndex >= 0 && config.relations) { - config.relations = [...config.relations] - config.relations.splice(priceIndex, 1) - } - - const query = buildQuery({ sku }, config) as FindOneOptions - const variant = await variantRepo.findOne(query) - - if (!variant) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Variant with sku: ${sku} was not found` - ) - } - - return variant - } - - /** - * Creates an unpublished product variant. Will validate against parent product - * to ensure that the variant can in fact be created. - * @param productOrProductId - the product the variant will be added to - * @param variants - * @return resolves to the creation result. - */ - async create< - TVariants extends CreateProductVariantInput | CreateProductVariantInput[], - TOutput = TVariants extends CreateProductVariantInput[] - ? CreateProductVariantInput[] - : CreateProductVariantInput - >( - productOrProductId: string | Product, - variants: CreateProductVariantInput | CreateProductVariantInput[] - ): Promise { - const isVariantsArray = Array.isArray(variants) - const variants_ = isVariantsArray ? variants : [variants] - - return await this.atomicPhase_(async (manager: EntityManager) => { - const productRepo = manager.withRepository(this.productRepository_) - const variantRepo = manager.withRepository(this.productVariantRepository_) - - let product = productOrProductId as Product - - if (isString(product)) { - product = (await productRepo.findOne({ - where: { id: productOrProductId as string }, - relations: buildRelations([ - "variants", - "variants.options", - "options", - ]), - })) as Product - } - - if (!product?.id) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Product id missing` - ) - } - - this.validateVariantsToCreate_(product, variants_) - - let computedRank = product.variants.length - const variantPricesToUpdate: { - id: string - prices: ProductVariantPrice[] - }[] = [] - - const results = await promiseAll( - variants_.map(async (variant) => { - const { prices, ...rest } = variant - - if (!rest.variant_rank) { - rest.variant_rank = computedRank - } - ++computedRank - - const toCreate = { - ...rest, - product_id: product.id, - } - - const productVariant = variantRepo.create(toCreate) - - const result = await variantRepo.save(productVariant) - - if (prices?.length) { - variantPricesToUpdate.push({ id: result.id, prices }) - } - - return result - }) - ) - - if (variantPricesToUpdate.length) { - await this.updateVariantPrices( - variantPricesToUpdate.map((v) => ({ - variantId: v.id, - prices: v.prices, - })) - ) - } - - const eventsToEmit = results.map((result) => ({ - eventName: ProductVariantService.Events.CREATED, - data: { - id: result.id, - product_id: result.product_id, - }, - })) - - await this.eventBus_.withTransaction(manager).emit(eventsToEmit) - - return (isVariantsArray ? results : results[0]) as unknown as TOutput - }) - } - - /** - * Updates a collection of variant. - * @param variantData - a collection of variant and the data to update. - * @return resolves to the update result. - */ - async update( - variantData: { - variant: ProductVariant - updateData: UpdateProductVariantInput - }[] - ): Promise - - /** - * Updates a variant. - * Price updates should use dedicated methods. - * The function will throw, if price updates are attempted. - * @param variantOrVariantId - variant or id of a variant. - * @param update - an object with the update values. - * @return resolves to the update result. - */ - async update( - variantOrVariantId: string | Partial, - update: UpdateProductVariantInput - ): Promise - - async update( - variantOrVariantId: string | Partial, - update: UpdateProductVariantInput - ): Promise - - async update< - TInput extends - | string - | Partial - | UpdateProductVariantData[], - TResult = TInput extends UpdateProductVariantData[] - ? ProductVariant[] - : ProductVariant - >( - variantOrVariantIdOrData: TInput, - updateData?: UpdateProductVariantInput - ): Promise { - let data = Array.isArray(variantOrVariantIdOrData) - ? variantOrVariantIdOrData - : ([] as UpdateProductVariantData[]) - - return await this.atomicPhase_(async (manager: EntityManager) => { - const variantRepo = manager.withRepository(this.productVariantRepository_) - - if (updateData) { - let variant: Partial | null = - variantOrVariantIdOrData as Partial - - if (isString(variantOrVariantIdOrData)) { - variant = await this.retrieve(variantOrVariantIdOrData, { - select: variantRepo.metadata.columns.map( - (c) => c.propertyName - ) as (keyof ProductVariant)[], - }) - } - - if (!variant?.id) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Variant id missing` - ) - } - - data = [{ variant: variant as ProductVariant, updateData: updateData }] - } - - const result = await this.updateBatch(data) - - return (Array.isArray(variantOrVariantIdOrData) - ? result - : result[0]) as unknown as TResult - }) - } - - protected async updateBatch( - variantData: UpdateProductVariantData[] - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const variantRepo = manager.withRepository(this.productVariantRepository_) - - const variantPriceUpdateData = variantData - .filter((data) => isDefined(data.updateData.prices)) - .map((data) => ({ - variantId: data.variant.id, - prices: data.updateData.prices!, - })) - - if (variantPriceUpdateData.length) { - await this.updateVariantPrices(variantPriceUpdateData) - } - - const results: [ProductVariant, UpdateProductVariantInput, boolean][] = - await promiseAll( - variantData.map(async ({ variant, updateData }) => { - const { prices, options, ...rest } = updateData - - const shouldUpdate = hasChanges(variant, rest) - const shouldEmitUpdateEvent = - shouldUpdate || !!options?.length || !!prices?.length - - for (const option of options ?? []) { - await this.updateOptionValue( - variant.id!, - option.option_id, - option.value - ) - } - - const toUpdate: QueryDeepPartialEntity = {} - - if (isObject(rest.metadata)) { - toUpdate["metadata"] = setMetadata( - variant as ProductVariant, - rest.metadata - ) as QueryDeepPartialEntity> - delete rest.metadata - } - - if (Object.keys(rest).length) { - for (const [key, value] of Object.entries(rest)) { - if (variant[key] !== value) { - toUpdate[key] = value - } - } - } - - let result = variant - - // No need to update if nothing on the variant has changed - if (shouldUpdate) { - const { id } = variant - const rawResult = await variantRepo.update( - { id }, - { id, ...toUpdate } - ) - - result = variantRepo.create({ - ...variant, - ...rawResult.generatedMaps[0], - }) - } - - return [result, updateData, shouldEmitUpdateEvent] - }) - ) - - const events = results - .filter(([, , shouldEmitUpdateEvent]) => shouldEmitUpdateEvent) - .map(([result, updatedData]) => { - return { - eventName: ProductVariantService.Events.UPDATED, - data: { - id: result.id, - product_id: result.product_id, - fields: Object.keys(updatedData), - }, - } - }) - - if (events.length) { - await this.eventBus_.withTransaction(manager).emit(events) - } - - return results.map(([variant]) => variant) - }) - } - - /** - * Updates variant/prices collection. - * Deletes any prices that are not in the update object, and is not associated with a price list. - * @param data - * @returns empty promise - */ - async updateVariantPrices(data: UpdateVariantPricesData[]): Promise - - /** - * Updates a variant's prices. - * Deletes any prices that are not in the update object, and is not associated with a price list. - * @param variantId - the id of variant - * @param prices - the update prices - * @returns empty promise - */ - async updateVariantPrices( - variantId: string, - prices: ProductVariantPrice[] - ): Promise - - async updateVariantPrices( - variantIdOrData: string | UpdateVariantPricesData[], - prices?: ProductVariantPrice[] - ): Promise { - let data = !isString(variantIdOrData) - ? variantIdOrData - : ([] as UpdateVariantPricesData[]) - - if (prices && isString(variantIdOrData)) { - data = [{ variantId: variantIdOrData, prices }] - } - - return await this.updateVariantPricesBatch(data) - } - - protected async updateVariantPricesBatch( - data: UpdateVariantPricesData[] - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.withRepository( - this.moneyAmountRepository_ - ) - - // Delete obsolete prices - await moneyAmountRepo.deleteVariantPricesNotIn(data) - - const regionIdsSet: Set = new Set( - data - .map((data_) => - data_.prices - .filter((price) => price.region_id) - .map((price) => price.region_id!) - ) - .flat() - ) - - const regions = await this.regionService_.withTransaction(manager).list( - { - id: [...regionIdsSet], - }, - { - select: ["id", "currency_code"], - } - ) - - const regionsMap = new Map(regions.map((r) => [r.id, r])) - - const dataRegionPrices: UpdateVariantRegionPriceData[] = [] - const dataCurrencyPrices: UpdateVariantCurrencyPriceData[] = [] - - data.forEach(({ prices, variantId }) => { - prices.forEach((price) => { - if (price.region_id) { - const region = regionsMap.get(price.region_id)! - dataRegionPrices.push({ - variantId, - price: { - currency_code: region.currency_code, - region_id: price.region_id, - amount: price.amount, - }, - }) - } else { - dataCurrencyPrices.push({ - variantId, - price: { - ...price, - currency_code: price.currency_code!, - }, - }) - } - }) - }) - - const promises: Promise[] = [] - - if (dataRegionPrices.length) { - promises.push(this.upsertRegionPrices(dataRegionPrices)) - } - - if (dataCurrencyPrices.length) { - promises.push(this.upsertCurrencyPrices(dataCurrencyPrices)) - } - - await promiseAll(promises) - }) - } - - async upsertRegionPrices( - data: UpdateVariantRegionPriceData[] - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.withRepository( - this.moneyAmountRepository_ - ) - const productVariantRepo = this.activeManager_.withRepository( - this.productVariantRepository_ - ) - - const where = data.map((data_) => ({ - variant_id: data_.variantId, - region_id: data_.price.region_id, - })) - - const moneyAmounts = await moneyAmountRepo.findRegionMoneyAmounts(where) - - const moneyAmountsMapToVariantId = new Map() - moneyAmounts.map((d) => { - const moneyAmounts = moneyAmountsMapToVariantId.get(d.variant_id) ?? [] - moneyAmounts.push(d) - moneyAmountsMapToVariantId.set(d.variant_id, moneyAmounts) - }) - - const dataToCreate: QueryDeepPartialEntity[] = [] - const dataToUpdate: QueryDeepPartialEntity[] = [] - - data.forEach(({ price, variantId }) => { - const variantMoneyAmounts = - moneyAmountsMapToVariantId.get(variantId) ?? [] - - const moneyAmount: MoneyAmount = variantMoneyAmounts.find( - (ma) => ma.region_id === price.region_id - ) - - if (moneyAmount) { - // No need to update if the amount is the same - if (moneyAmount.amount !== price.amount) { - dataToUpdate.push({ - id: moneyAmount.id, - amount: price.amount, - }) - } - } else { - const ma = moneyAmountRepo.create({ - ...price, - }) as QueryDeepPartialEntity - ma.variant = { id: variantId } - dataToCreate.push(ma) - } - }) - - const promises: Promise[] = [] - - if (dataToCreate.length) { - promises.push(moneyAmountRepo.insertBulk(dataToCreate)) - } - - if (dataToUpdate.length) { - dataToUpdate.forEach((data) => { - const { id, ...rest } = data - promises.push(moneyAmountRepo.update({ id: data.id as string }, rest)) - }) - } - - if (dataToCreate.length || dataToUpdate.length) { - promises.push( - this.priceSelectionStrategy_ - .withTransaction(manager) - .onVariantsPricesUpdate(data.map((d) => d.variantId)) - ) - } - - await promiseAll(promises) - }) - } - - async upsertCurrencyPrices( - data: { - variantId: string - price: WithRequiredProperty - }[] - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.withRepository( - this.moneyAmountRepository_ - ) - const productVariantRepo = this.activeManager_.withRepository( - this.productVariantRepository_ - ) - - const where = data.map((data_) => ({ - variant_id: data_.variantId, - currency_code: data_.price.currency_code, - })) - - const moneyAmounts = await moneyAmountRepo.findCurrencyMoneyAmounts(where) - - const moneyAmountsMapToVariantId = new Map() - moneyAmounts.map((d) => { - const moneyAmounts = moneyAmountsMapToVariantId.get(d.variant_id) ?? [] - moneyAmounts.push(d) - moneyAmountsMapToVariantId.set(d.variant_id, moneyAmounts) - }) - - const dataToCreate: QueryDeepPartialEntity[] = [] - const dataToUpdate: QueryDeepPartialEntity[] = [] - - data.forEach(({ price, variantId }) => { - const variantMoneyAmounts = - moneyAmountsMapToVariantId.get(variantId) ?? [] - - const moneyAmount: MoneyAmount = variantMoneyAmounts.find( - (ma) => ma.currency_code === price.currency_code - ) - - if (moneyAmount) { - // No need to update if the amount is the same - if (moneyAmount.amount !== price.amount) { - dataToUpdate.push({ - id: moneyAmount.id, - amount: price.amount, - }) - } - } else { - const ma = moneyAmountRepo.create({ - ...price, - currency_code: price.currency_code.toLowerCase(), - }) as QueryDeepPartialEntity - ma.variant = { id: variantId } - dataToCreate.push(ma) - } - }) - - const promises: Promise[] = [] - - if (dataToCreate.length) { - promises.push(moneyAmountRepo.insertBulk(dataToCreate)) - } - - if (dataToUpdate.length) { - dataToUpdate.forEach((data) => { - const { id, ...rest } = data - promises.push(moneyAmountRepo.update({ id: data.id as string }, rest)) - }) - } - - if (dataToCreate.length || dataToUpdate.length) { - promises.push( - this.priceSelectionStrategy_ - .withTransaction(manager) - .onVariantsPricesUpdate(data.map((d) => d.variantId)) - ) - } - - await promiseAll(promises) - }) - } - - /** - * Gets the price specific to a region. If no region specific money amount - * exists the function will try to use a currency price. If no default - * currency price exists the function will throw an error. - * @param variantId - the id of the variant to get price from - * @param context - context for getting region price - * @return the price specific to the region - */ - async getRegionPrice( - variantId: string, - context: GetRegionPriceContext - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const region = await this.regionService_ - .withTransaction(manager) - .retrieve(context.regionId) - - const prices = await this.priceSelectionStrategy_ - .withTransaction(manager) - .calculateVariantPrice([{ variantId, quantity: context.quantity }], { - region_id: context.regionId, - currency_code: region.currency_code, - customer_id: context.customer_id, - include_discount_prices: !!context.include_discount_prices, - }) - - return prices.get(variantId)!.calculatedPrice - }) - } - - /** - * @deprecated use addOrUpdateRegionPrices instead - * Sets the default price of a specific region - * @param variantId - the id of the variant to update - * @param price - the price for the variant. - * @return the result of the update operation - */ - async setRegionPrice( - variantId: string, - price: ProductVariantPrice - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.withRepository( - this.moneyAmountRepository_ - ) - - let [moneyAmount] = await moneyAmountRepo.getPricesForVariantInRegion( - variantId, - price.region_id - ) - - const created = !moneyAmount - - if (!moneyAmount) { - moneyAmount = moneyAmountRepo.create({ - ...price, - variant: { id: variantId }, - }) - } else { - moneyAmount.amount = price.amount - } - - const createdAmount = await moneyAmountRepo.save(moneyAmount) - - if (created) { - await moneyAmountRepo.createProductVariantMoneyAmounts([ - { - variant_id: variantId, - money_amount_id: createdAmount.id, - }, - ]) - } - - return createdAmount - }) - } - - /** - * @deprecated use addOrUpdateCurrencyPrices instead - * Sets the default price for the given currency. - * @param variantId - the id of the variant to set prices for - * @param price - the price for the variant - * @return the result of the update operation - */ - async setCurrencyPrice( - variantId: string, - price: ProductVariantPrice - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.withRepository( - this.moneyAmountRepository_ - ) - - return await moneyAmountRepo.upsertVariantCurrencyPrice(variantId, price) - }) - } - - /** - * Updates variant's option value. - * Option value must be of type string or number. - * @param variantId - the variant to decorate. - * @param optionId - the option from product. - * @param optionValue - option value to add. - * @return the result of the update operation. - */ - async updateOptionValue( - variantId: string, - optionId: string, - optionValue: string - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const productOptionValueRepo = manager.withRepository( - this.productOptionValueRepository_ - ) - - const productOptionValue = await productOptionValueRepo.findOne({ - where: { variant_id: variantId, option_id: optionId }, - }) - - if (!productOptionValue) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Product option value not found` - ) - } - - productOptionValue.value = optionValue - - return await productOptionValueRepo.save(productOptionValue) - }) - } - - /** - * Adds option value to a variant. - * Fails when product with variant does not exist or - * if that product does not have an option with the given - * option id. Fails if given variant is not found. - * Option value must be of type string or number. - * @param variantId - the variant to decorate. - * @param optionId - the option from product. - * @param optionValue - option value to add. - * @return the result of the update operation. - */ - async addOptionValue( - variantId: string, - optionId: string, - optionValue: string - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const productOptionValueRepo = manager.withRepository( - this.productOptionValueRepository_ - ) - - const productOptionValue = productOptionValueRepo.create({ - variant_id: variantId, - option_id: optionId, - value: optionValue, - }) - - return await productOptionValueRepo.save(productOptionValue) - }) - } - - /** - * Deletes option value from given variant. - * Will never fail due to delete being idempotent. - * @param variantId - the variant to decorate. - * @param optionId - the option from product. - * @return empty promise - */ - async deleteOptionValue(variantId: string, optionId: string): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const productOptionValueRepo = manager.withRepository( - this.productOptionValueRepository_ - ) - - const productOptionValue = await productOptionValueRepo.findOne({ - where: { - variant_id: variantId, - option_id: optionId, - }, - }) - - if (!productOptionValue) { - return Promise.resolve() - } - - await productOptionValueRepo.softRemove(productOptionValue) - - return Promise.resolve() - }) - } - - /** - * @param selector - the query object for find - * @param config - query config object for variant retrieval - * @return the result of the find operation - */ - async listAndCount( - selector: FilterableProductVariantProps, - config: FindConfig & PriceSelectionContext = { - relations: [], - skip: 0, - take: 20, - include_discount_prices: false, - } - ): Promise<[ProductVariant[], number]> { - const variantRepo = this.activeManager_.withRepository( - this.productVariantRepository_ - ) - - let q - if (isDefined(selector.q)) { - q = selector.q - delete selector.q - } - - const query = buildQuery, ProductVariant>( - selector as FindOptionsSelect, - config - ) - query.relationLoadStrategy = "query" - - if (q) { - query.relations = query.relations ?? {} - query.relations["product"] = query.relations["product"] ?? true - - query.where = query.where as FindOptionsWhere - delete query.where?.title - - query.where = query.where ?? {} - query.where = [ - { - ...query.where, - title: ILike(`%${q}%`), - }, - { - ...query.where, - sku: ILike(`%${q}%`), - }, - { - ...query.where, - product: { - ...((query.where.product ?? - {}) as FindOptionsWhere), - title: ILike(`%${q}%`), - }, - }, - ] - } - - return await variantRepo.findAndCount(query) - } - - /** - * @param selector - the query object for find - * @param config - query config object for variant retrieval - * @return the result of the find operation - */ - async list( - selector: FilterableProductVariantProps, - config: FindConfig & PriceSelectionContext = { - relations: [], - skip: 0, - take: 20, - } - ): Promise { - const productVariantRepo = this.activeManager_.withRepository( - this.productVariantRepository_ - ) - - const priceIndex = config.relations?.indexOf("prices") ?? -1 - if (priceIndex >= 0 && config.relations) { - config.relations = [...config.relations] - config.relations.splice(priceIndex, 1) - } - - let q: string | undefined - if ("q" in selector) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) as FindManyOptions - - if (q) { - const where = query.where as FindOptionsWhere - - delete where?.sku - delete where?.title - - query.relations = query.relations || {} - query.relations["product"] = true - - query.where = (qb: SelectQueryBuilder): void => { - qb.where(where).andWhere([ - { sku: ILike(`%${q}%`) }, - { title: ILike(`%${q}%`) }, - { product: { title: ILike(`%${q}%`) } }, - ]) - } - } - - return await productVariantRepo.find(query) - } - - /** - * Deletes variant or variants. - * Will never fail due to delete being idempotent. - * @param variantIds - the id of the variant to delete. Must be - * castable as an ObjectId - * @return empty promise - */ - async delete(variantIds: string | string[]): Promise { - const variantIds_ = isString(variantIds) ? [variantIds] : variantIds - - return await this.atomicPhase_(async (manager: EntityManager) => { - const variantRepo = manager.withRepository(this.productVariantRepository_) - - const variants = await variantRepo.find({ - where: { id: In(variantIds_) }, - relations: ["prices", "options", "inventory_items"], - }) - - if (!variants.length) { - return Promise.resolve() - } - - await variantRepo.softRemove(variants) - - const events = variants.map((variant) => { - return { - eventName: ProductVariantService.Events.DELETED, - data: { - id: variant.id, - product_id: variant.product_id, - metadata: variant.metadata, - }, - } - }) - - await this.eventBus_.withTransaction(manager).emit(events) - }) - } - - /** - * Check if the variant is assigned to at least one of the provided sales channels. - * - * @param id - product variant id - * @param salesChannelIds - an array of sales channel ids - */ - async isVariantInSalesChannels( - id: string, - salesChannelIds: string[] - ): Promise { - const variant = await this.retrieve(id, { - relations: ["product", "product.sales_channels"], - }) - - // TODO: reimplement this to use db level check - const productsSalesChannels = variant.product.sales_channels.map( - (channel) => channel.id - ) - - return productsSalesChannels.some((id) => salesChannelIds.includes(id)) - } - - /** - * Lists variants based on the provided parameters and includes the count of - * variants that match the query. - * @param variantRepo - the variant repository - * @param query - object that defines the scope for what should be returned - * @param q - free text query - * @return an array containing the products as the first element and the total - * count of products that matches the query as the second element. - */ - getFreeTextQueryBuilder_( - variantRepo: typeof ProductVariantRepository, - query: FindWithRelationsOptions, - q?: string - ): SelectQueryBuilder { - const where = query.where - - if (typeof where === "object") { - if ("title" in where) { - delete where.title - } - } - - let qb = variantRepo - .createQueryBuilder("pv") - .take(query.take) - .skip(Math.max(query.skip ?? 0, 0)) - .leftJoinAndSelect("pv.product", "product") - .select(["pv.id"]) - .where(where!) - .andWhere( - new Brackets((qb) => { - qb.where(`product.title ILIKE :q`, { q: `%${q}%` }) - .orWhere(`pv.title ILIKE :q`, { q: `%${q}%` }) - .orWhere(`pv.sku ILIKE :q`, { q: `%${q}%` }) - }) - ) - - if (query.withDeleted) { - qb = qb.withDeleted() - } - - return qb - } - - protected validateVariantsToCreate_( - product: Product, - variants: CreateProductVariantInput[] - ): void { - for (const variant of variants) { - if (product.options.length !== variant.options.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Product options length does not match variant options length. Product has ${product.options.length} and variant has ${variant.options.length}.` - ) - } - - product.options.forEach((option) => { - if (!variant.options.find((vo) => option.id === vo.option_id)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Variant options do not contain value for ${option.title}` - ) - } - }) - - const variantExists = product.variants.find((v) => { - return v.options.every((option) => { - const variantOption = variant.options.find( - (o) => option.option_id === o.option_id - ) - - return option.value === variantOption?.value - }) - }) - - if (variantExists) { - throw new MedusaError( - MedusaError.Types.DUPLICATE_ERROR, - `Variant with title ${variantExists.title} with provided options already exists` - ) - } - } - } -} - -export default ProductVariantService diff --git a/packages/medusa/src/services/product.ts b/packages/medusa/src/services/product.ts deleted file mode 100644 index dfd67e145c..0000000000 --- a/packages/medusa/src/services/product.ts +++ /dev/null @@ -1,1171 +0,0 @@ -import { RemoteQueryFunction } from "@medusajs/types" -import { - buildRelations, - buildSelects, - FlagRouter, - MedusaV2Flag, - objectToStringPath, - promiseAll, - selectorConstraintsToString, -} from "@medusajs/utils" -import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager, In } from "typeorm" - -import { ProductVariantService, SearchService } from "." -import { TransactionBaseService } from "../interfaces" -import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels" -import { - Product, - ProductCategory, - ProductOption, - ProductTag, - ProductType, - ProductVariant, - SalesChannel, - ShippingProfile, -} from "../models" -import { ImageRepository } from "../repositories/image" -import { - FindWithoutRelationsOptions, - ProductRepository, -} from "../repositories/product" -import { ProductCategoryRepository } from "../repositories/product-category" -import { ProductOptionRepository } from "../repositories/product-option" -import { ProductTagRepository } from "../repositories/product-tag" -import { ProductTypeRepository } from "../repositories/product-type" -import { ProductVariantRepository } from "../repositories/product-variant" -import { Selector } from "../types/common" -import { - CreateProductInput, - FilterableProductProps, - FindProductConfig, - ProductOptionInput, - ProductSelector, - UpdateProductInput, -} from "../types/product" -import { CreateProductVariantInput } from "../types/product-variant" -import { buildQuery, isString, setMetadata } from "../utils" -import EventBusService from "./event-bus" -import SalesChannelService from "./sales-channel" - -type InjectedDependencies = { - manager: EntityManager - productOptionRepository: typeof ProductOptionRepository - productRepository: typeof ProductRepository - productVariantRepository: typeof ProductVariantRepository - productTypeRepository: typeof ProductTypeRepository - productTagRepository: typeof ProductTagRepository - imageRepository: typeof ImageRepository - productCategoryRepository: typeof ProductCategoryRepository - productVariantService: ProductVariantService - searchService: SearchService - salesChannelService: SalesChannelService - eventBusService: EventBusService - featureFlagRouter: FlagRouter - remoteQuery: RemoteQueryFunction -} - -class ProductService extends TransactionBaseService { - protected readonly productOptionRepository_: typeof ProductOptionRepository - protected readonly productRepository_: typeof ProductRepository - protected readonly productVariantRepository_: typeof ProductVariantRepository - protected readonly productTypeRepository_: typeof ProductTypeRepository - protected readonly productTagRepository_: typeof ProductTagRepository - protected readonly imageRepository_: typeof ImageRepository - // eslint-disable-next-line max-len - protected readonly productCategoryRepository_: typeof ProductCategoryRepository - protected readonly productVariantService_: ProductVariantService - protected readonly searchService_: SearchService - protected readonly salesChannelService_: SalesChannelService - protected readonly eventBus_: EventBusService - protected readonly featureFlagRouter_: FlagRouter - protected remoteQuery_: RemoteQueryFunction - - static readonly IndexName = `products` - static readonly Events = { - UPDATED: "product.updated", - CREATED: "product.created", - DELETED: "product.deleted", - } - - constructor({ - productOptionRepository, - productRepository, - productVariantRepository, - eventBusService, - productVariantService, - productTypeRepository, - productTagRepository, - productCategoryRepository, - imageRepository, - searchService, - remoteQuery, - salesChannelService, - featureFlagRouter, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.productOptionRepository_ = productOptionRepository - this.productRepository_ = productRepository - this.productVariantRepository_ = productVariantRepository - this.eventBus_ = eventBusService - this.productVariantService_ = productVariantService - this.productCategoryRepository_ = productCategoryRepository - this.productTypeRepository_ = productTypeRepository - this.productTagRepository_ = productTagRepository - this.imageRepository_ = imageRepository - this.searchService_ = searchService - this.salesChannelService_ = salesChannelService - this.featureFlagRouter_ = featureFlagRouter - this.remoteQuery_ = remoteQuery - } - - /** - * Lists products based on the provided parameters. - * @param selector - an object that defines rules to filter products - * by - * @param config - object that defines the scope for what should be - * returned - * @return the result of the find operation - */ - async list( - selector: ProductSelector, - config: FindProductConfig = { - relations: [], - skip: 0, - take: 20, - include_discount_prices: false, - } - ): Promise { - const [products] = await this.listAndCount(selector, config) - return products - } - - /** - * Lists products based on the provided parameters and includes the count of - * products that match the query. - * @param selector - an object that defines rules to filter products - * by - * @param config - object that defines the scope for what should be - * returned - * @return an array containing the products as - * the first element and the total count of products that matches the query - * as the second element. - */ - async listAndCount( - selector: ProductSelector, - config: FindProductConfig = { - relations: [], - skip: 0, - take: 20, - include_discount_prices: false, - } - ): Promise<[Product[], number]> { - /* const productRepo = this.activeManager_.withRepository( - this.productRepository_ - ) - - const { q, ...productSelector } = selector - const query = buildQuery(productSelector, config) as ExtendedFindConfig< - Product & ProductFilterOptions - > - - return await productRepo.findAndCount(query, q)*/ - - /** - * TODO: The below code is a temporary fix for the issue with the typeorm idle transaction in query strategy mode - */ - - const manager = this.activeManager_ - const productRepo = manager.withRepository(this.productRepository_) - - const hasSalesChannelsRelation = - config.relations?.includes("sales_channels") - - if ( - this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key) && - hasSalesChannelsRelation - ) { - config.relations = config.relations?.filter((r) => r !== "sales_channels") - } - - const { q, query, relations } = this.prepareListQuery_(selector, config) - - let count: number - let products: Product[] - - if (q) { - ;[products, count] = await productRepo.getFreeTextSearchResultsAndCount( - q, - query, - relations - ) - } else { - ;[products, count] = await productRepo.findWithRelationsAndCount( - relations, - query - ) - } - - if ( - this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key) && - hasSalesChannelsRelation - ) { - await this.decorateProductsWithSalesChannels(products) - } - - return [products, count] - } - - /** - * Return the total number of documents in database - * @param {object} selector - the selector to choose products by - * @return {Promise} the result of the count operation - */ - async count(selector: Selector = {}): Promise { - const productRepo = this.activeManager_.withRepository( - this.productRepository_ - ) - const query = buildQuery(selector) - return await productRepo.count(query) - } - - /** - * Gets a product by id. - * Throws in case of DB Error and if product was not found. - * @param productId - id of the product to get. - * @param config - object that defines what should be included in the - * query response - * @return the result of the find one operation. - */ - async retrieve( - productId: string, - config: FindProductConfig = { - include_discount_prices: false, - } - ): Promise { - if (!isDefined(productId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"productId" must be defined` - ) - } - - return await this.retrieve_({ id: productId }, config) - } - - /** - * Gets a product by handle. - * Throws in case of DB Error and if product was not found. - * @param productHandle - handle of the product to get. - * @param config - details about what to get from the product - * @return the result of the find one operation. - */ - async retrieveByHandle( - productHandle: string, - config: FindProductConfig = {} - ): Promise { - if (!isDefined(productHandle)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"productHandle" must be defined` - ) - } - - return await this.retrieve_({ handle: productHandle }, config) - } - - /** - * Gets a product by external id. - * Throws in case of DB Error and if product was not found. - * @param externalId - handle of the product to get. - * @param config - details about what to get from the product - * @return the result of the find one operation. - */ - async retrieveByExternalId( - externalId: string, - config: FindProductConfig = {} - ): Promise { - if (!isDefined(externalId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"externalId" must be defined` - ) - } - - return await this.retrieve_({ external_id: externalId }, config) - } - - /** - * Gets a product by selector. - * Throws in case of DB Error and if product was not found. - * @param selector - selector object - * @param config - object that defines what should be included in the - * query response - * @return the result of the find one operation. - */ - async retrieve_( - selector: Selector, - config: FindProductConfig = { - include_discount_prices: false, // TODO: this seams to be unused from the repository - } - ): Promise { - /* const productRepo = this.activeManager_.withRepository( - this.productRepository_ - ) - const query = buildQuery(selector, config as FindConfig) - const product = await productRepo.findOne(query) - - if (!product) { - const selectorConstraints = Object.entries(selector) - .map(([key, value]) => `${key}: ${value}`) - .join(", ") - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Product with ${selectorConstraints} was not found` - ) - } - - return product*/ - - /** - * TODO: The below code is a temporary fix for the issue with the typeorm idle transaction in query strategy mode - */ - const manager = this.activeManager_ - const productRepo = manager.withRepository(this.productRepository_) - - const hasSalesChannelsRelation = - config.relations?.includes("sales_channels") - - if ( - this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key) && - hasSalesChannelsRelation - ) { - config.relations = config.relations?.filter((r) => r !== "sales_channels") - } - - const { relations, ...query } = buildQuery(selector, config) - - const product = await productRepo.findOneWithRelations( - objectToStringPath(relations), - query as FindWithoutRelationsOptions - ) - - if (!product) { - const selectorConstraints = selectorConstraintsToString(selector) - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Product with ${selectorConstraints} was not found` - ) - } - - if ( - this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key) && - hasSalesChannelsRelation - ) { - await this.decorateProductsWithSalesChannels([product]) - } - - return product - } - - /** - * Gets all variants belonging to a product. - * @param productId - the id of the product to get variants from. - * @param config - The config to select and configure relations etc... - * @return an array of variants - */ - async retrieveVariants( - productId: string, - config: FindProductConfig = { - skip: 0, - take: 50, - } - ): Promise { - const givenRelations = config.relations ?? [] - const requiredRelations = ["variants"] - const relationsSet = new Set([...givenRelations, ...requiredRelations]) - - const product = await this.retrieve(productId, { - ...config, - relations: [...relationsSet], - }) - return product.variants - } - - async filterProductsBySalesChannel( - productIds: string[], - salesChannelId: string, - config: FindProductConfig = { - skip: 0, - take: 50, - } - ): Promise { - const givenRelations = config.relations ?? [] - const requiredRelations = ["sales_channels"] - const relationsSet = new Set([...givenRelations, ...requiredRelations]) - - const products = await this.list( - { - id: productIds, - }, - { - ...config, - relations: [...relationsSet], - } - ) - const productSalesChannelsMap = new Map( - products.map((product) => [product.id, product.sales_channels]) - ) - return products.filter((product) => { - return productSalesChannelsMap - .get(product.id) - ?.some((sc) => sc.id === salesChannelId) - }) - } - - async listTypes(): Promise { - const productTypeRepository = this.activeManager_.withRepository( - this.productTypeRepository_ - ) - - return await productTypeRepository.find({}) - } - - async listTagsByUsage(take = 10): Promise { - const productTagRepo = this.activeManager_.withRepository( - this.productTagRepository_ - ) - - return await productTagRepo.listTagsByUsage(take) - } - - /** - * Check if the product is assigned to at least one of the provided sales channels. - * - * @param id - product id - * @param salesChannelIds - an array of sales channel ids - */ - async isProductInSalesChannels( - id: string, - salesChannelIds: string[] - ): Promise { - const product = await this.retrieve_( - { id }, - { relations: ["sales_channels"] } - ) - - // TODO: reimplement this to use db level check - const productsSalesChannels = product.sales_channels.map( - (channel) => channel.id - ) - - return productsSalesChannels.some((id) => salesChannelIds.includes(id)) - } - - /** - * Creates a product. - * @param productObject - the product to create - * @return resolves to the creation result. - */ - async create(productObject: CreateProductInput): Promise { - return await this.atomicPhase_(async (manager) => { - const productRepo = manager.withRepository(this.productRepository_) - const productTagRepo = manager.withRepository(this.productTagRepository_) - const productTypeRepo = manager.withRepository( - this.productTypeRepository_ - ) - const imageRepo = manager.withRepository(this.imageRepository_) - const optionRepo = manager.withRepository(this.productOptionRepository_) - - const { - options, - tags, - type, - images, - variants, - sales_channels: salesChannels, - categories: categories, - ...rest - } = productObject - - if (!rest.thumbnail && images?.length) { - rest.thumbnail = images[0] - } - - // if product is a giftcard, we should disallow discounts - if (rest.is_giftcard) { - rest.discountable = false - } - - let product = productRepo.create(rest) - - if (rest.profile_id) { - product.profiles = [{ id: rest.profile_id! }] as ShippingProfile[] - } - - if (images?.length) { - product.images = await imageRepo.upsertImages(images) - } - - if (tags?.length) { - product.tags = await productTagRepo.upsertTags(tags) - } - - if (typeof type !== `undefined`) { - product.type_id = (await productTypeRepo.upsertType(type))?.id || null - } - - if ( - this.featureFlagRouter_.isFeatureEnabled(SalesChannelFeatureFlag.key) && - !this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key) - ) { - if (isDefined(salesChannels)) { - product.sales_channels = [] - if (salesChannels?.length) { - const salesChannelIds = salesChannels?.map((sc) => sc.id) - product.sales_channels = salesChannelIds?.map( - (id) => ({ id } as SalesChannel) - ) - } - } - } - - if (isDefined(categories)) { - product.categories = [] - - if (categories?.length) { - const categoryIds = categories.map((c) => c.id) - const categoryRecords = categoryIds.map( - (id) => ({ id } as ProductCategory) - ) - - product.categories = categoryRecords - } - } - - product = await productRepo.save(product) - - if ( - isDefined(salesChannels) && - this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key) - ) { - if (salesChannels?.length) { - await Promise.all( - salesChannels?.map( - async (sc) => - await this.salesChannelService_.addProducts(sc.id, [product.id]) - ) - ) - } - } - - product.options = await promiseAll( - (options ?? []).map(async (option) => { - const res = optionRepo.create({ - ...option, - product_id: product.id, - }) - await optionRepo.save(res) - return res - }) - ) - - if (variants) { - const toCreate = variants.map((variant) => { - return { - ...variant, - options: - variant.options?.map((option, index) => { - return { - option_id: product.options[index].id, - ...option, - } - }) ?? [], - } - }) - product.variants = await this.productVariantService_ - .withTransaction(manager) - .create( - product.id, - toCreate as unknown as CreateProductVariantInput[] - ) - } - - const result = await this.withTransaction(manager).retrieve(product.id, { - relations: ["options"], - }) - - await this.eventBus_ - .withTransaction(manager) - .emit(ProductService.Events.CREATED, { - id: result.id, - }) - return result - }) - } - - /** - * Updates a product. Product variant updates should use dedicated methods, - * e.g. `addVariant`, etc. The function will throw errors if metadata or - * product variant updates are attempted. - * @param {string} productId - the id of the product. Must be a string that - * can be casted to an ObjectId - * @param {object} update - an object with the update values. - * @return {Promise} resolves to the update result. - */ - async update( - productId: string, - update: UpdateProductInput - ): Promise { - return await this.atomicPhase_(async (manager) => { - const productRepo = manager.withRepository(this.productRepository_) - const productTagRepo = manager.withRepository(this.productTagRepository_) - const productTypeRepo = manager.withRepository( - this.productTypeRepository_ - ) - const imageRepo = manager.withRepository(this.imageRepository_) - - const relations = ["tags", "images"] - - if ( - this.featureFlagRouter_.isFeatureEnabled(SalesChannelFeatureFlag.key) - ) { - if (isDefined(update.sales_channels)) { - relations.push("sales_channels") - } - } else { - if (isDefined(update.sales_channels)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "the property sales_channels should no appears as part of the payload" - ) - } - } - - const product = await this.withTransaction(manager).retrieve(productId, { - relations, - }) - - const { - metadata, - images, - tags, - type, - sales_channels: salesChannels, - categories: categories, - ...rest - } = update - - if (rest.profile_id) { - product.profiles = [{ id: rest.profile_id! }] as ShippingProfile[] - } - - if (!product.thumbnail && !update.thumbnail && images?.length) { - product.thumbnail = images[0] - } - - const promises: Promise[] = [] - - if (images) { - promises.push( - imageRepo - .upsertImages(images) - .then((image) => (product.images = image)) - ) - } - - if (metadata) { - product.metadata = setMetadata(product, metadata) - } - - if (isDefined(type)) { - promises.push( - productTypeRepo - .upsertType(type) - .then((type) => (product.type_id = type?.id ?? null)) - ) - } - - if (tags) { - promises.push( - productTagRepo.upsertTags(tags).then((tags) => (product.tags = tags)) - ) - } - - if (isDefined(categories)) { - product.categories = [] - - if (categories?.length) { - const categoryIds = categories.map((c) => c.id) - product.categories = categoryIds.map( - (id) => ({ id } as ProductCategory) - ) - } - } - - if ( - this.featureFlagRouter_.isFeatureEnabled(SalesChannelFeatureFlag.key) && - !this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key) - ) { - if (isDefined(salesChannels)) { - product.sales_channels = [] - if (salesChannels?.length) { - const salesChannelIds = salesChannels?.map((sc) => sc.id) - product.sales_channels = salesChannelIds?.map( - (id) => ({ id } as SalesChannel) - ) - } - } - } - - for (const [key, value] of Object.entries(rest)) { - if (isDefined(value)) { - product[key] = value - } - } - - await promiseAll(promises) - - const result = await productRepo.save(product) - - if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) { - if (salesChannels?.length) { - await promiseAll( - salesChannels?.map( - async (sc) => - await this.salesChannelService_.addProducts(sc.id, [product.id]) - ) - ) - } - } - - await this.eventBus_ - .withTransaction(manager) - .emit(ProductService.Events.UPDATED, { - id: result.id, - fields: Object.keys(update), - }) - - return result - }) - } - - /** - * Deletes a product from a given product id. The product's associated - * variants will also be deleted. - * @param productId - the id of the product to delete. Must be - * castable as an ObjectId - * @return empty promise - */ - async delete(productId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const productRepo = manager.withRepository(this.productRepository_) - - // Should not fail, if product does not exist, since delete is idempotent - const product = await productRepo.findOne({ - where: { id: productId }, - relations: { - variants: { - prices: true, - options: true, - }, - }, - }) - - if (!product) { - return - } - - await productRepo.softRemove(product) - - await this.eventBus_ - .withTransaction(manager) - .emit(ProductService.Events.DELETED, { - id: productId, - }) - - return Promise.resolve() - }) - } - - /** - * Adds an option to a product. Options can, for example, be "Size", "Color", - * etc. Will update all the products variants with a dummy value for the newly - * created option. The same option cannot be added more than once. - * @param productId - the product to apply the new option to - * @param optionTitle - the display title of the option, e.g. "Size" - * @return the result of the model update operation - */ - async addOption(productId: string, optionTitle: string): Promise { - return await this.atomicPhase_(async (manager) => { - const productOptionRepo = manager.withRepository( - this.productOptionRepository_ - ) - - const product = await this.withTransaction(manager).retrieve(productId, { - relations: ["options", "variants"], - }) - - if (product.options.find((o) => o.title === optionTitle)) { - throw new MedusaError( - MedusaError.Types.DUPLICATE_ERROR, - `An option with the title: ${optionTitle} already exists` - ) - } - - const option = productOptionRepo.create({ - title: optionTitle, - product_id: productId, - }) - - await productOptionRepo.save(option) - - const productVariantServiceTx = - this.productVariantService_.withTransaction(manager) - for (const variant of product.variants) { - await productVariantServiceTx.addOptionValue( - variant.id, - option.id, - "Default Value" - ) - } - - const result = await this.withTransaction(manager).retrieve(productId) - - await this.eventBus_ - .withTransaction(manager) - .emit(ProductService.Events.UPDATED, result) - return result - }) - } - - async reorderVariants( - productId: string, - variantOrder: string[] - ): Promise { - return await this.atomicPhase_(async (manager) => { - const productRepo = manager.withRepository(this.productRepository_) - - const product = await this.withTransaction(manager).retrieve(productId, { - relations: ["variants"], - }) - - if (product.variants.length !== variantOrder.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Product variants and new variant order differ in length.` - ) - } - - product.variants = variantOrder.map((vId) => { - const variant = product.variants.find((v) => v.id === vId) - if (!variant) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Product has no variant with id: ${vId}` - ) - } - - return variant - }) - - const result = productRepo.save(product) - await this.eventBus_ - .withTransaction(manager) - .emit(ProductService.Events.UPDATED, result) - return result - }) - } - - /** - * Updates a product's option. Throws if the call tries to update an option - * not associated with the product. Throws if the updated title already exists. - * @param productId - the product whose option we are updating - * @param optionId - the id of the option we are updating - * @param data - the data to update the option with - * @return the updated product - */ - async updateOption( - productId: string, - optionId: string, - data: ProductOptionInput - ): Promise { - return await this.atomicPhase_(async (manager) => { - const productOptionRepo = manager.withRepository( - this.productOptionRepository_ - ) - - const product = await this.withTransaction(manager).retrieve(productId, { - relations: ["options"], - }) - - const { title, values } = data - - const optionExists = product.options.some( - (o) => - o.title.toUpperCase() === title.toUpperCase() && o.id !== optionId - ) - if (optionExists) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `An option with title ${title} already exists` - ) - } - - const productOption = await productOptionRepo.findOne({ - where: { id: optionId }, - }) - - if (!productOption) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Option with id: ${optionId} does not exist` - ) - } - - productOption.title = title - if (values) { - productOption.values = values - } - - await productOptionRepo.save(productOption) - - await this.eventBus_ - .withTransaction(manager) - .emit(ProductService.Events.UPDATED, product) - return product - }) - } - - /** - * Retrieve product's option by title. - * - * @param title - title of the option - * @param productId - id of a product - * @return product option - */ - async retrieveOptionByTitle( - title: string, - productId: string - ): Promise { - const productOptionRepo = this.activeManager_.withRepository( - this.productOptionRepository_ - ) - - return productOptionRepo.findOne({ - where: { title, product_id: productId }, - }) - } - - /** - * Delete an option from a product. - * @param productId - the product to delete an option from - * @param optionId - the option to delete - * @return the updated product - */ - async deleteOption( - productId: string, - optionId: string - ): Promise { - return await this.atomicPhase_(async (manager) => { - const productOptionRepo = manager.withRepository( - this.productOptionRepository_ - ) - - const product = await this.withTransaction(manager).retrieve(productId, { - relations: ["variants", "variants.options"], - }) - - const productOption = await productOptionRepo.findOne({ - where: { id: optionId, product_id: productId }, - relations: ["values"], - }) - - if (!productOption) { - return Promise.resolve() - } - - // In case the product does not contain variants, we can safely delete the option - // If it does contain variants, we need to make sure no variant exist for the - // product option to delete - if (product?.variants?.length) { - // For the option we want to delete, make sure that all variants have the - // same option values. The reason for doing is, that we want to avoid - // duplicate variants. For example, if we have a product with size and - // color options, that has four variants: (black, 1), (black, 2), - // (blue, 1), (blue, 2) and we delete the size option from the product, - // we would end up with four variants: (black), (black), (blue), (blue). - // We now have two duplicate variants. To ensure that this does not - // happen, we will force the user to select which variants to keep. - const firstVariant = product.variants[0] - - const valueToMatch = firstVariant.options.find( - (o) => o.option_id === optionId - )?.value - - const equalsFirst = await promiseAll( - product.variants.map(async (v) => { - const option = v.options.find((o) => o.option_id === optionId) - return option?.value === valueToMatch - }) - ) - - if (!equalsFirst.every((v) => v)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `To delete an option, first delete all variants, such that when an option is deleted, no duplicate variants will exist.` - ) - } - } - - // If we reach this point, we can safely delete the product option - await productOptionRepo.softRemove(productOption) - - await this.eventBus_ - .withTransaction(manager) - .emit(ProductService.Events.UPDATED, product) - return product - }) - } - - /** - * Assign a product to a profile, if a profile id null is provided then detach the product from the profile - * @param productIds ID or IDs of the products to update - * @param profileId Shipping profile ID to update the shipping options with - * @returns updated products - */ - async updateShippingProfile( - productIds: string | string[], - profileId: string | null - ): Promise { - return await this.atomicPhase_(async (manager) => { - const productRepo = manager.withRepository(this.productRepository_) - - const ids = isString(productIds) ? [productIds] : productIds - - let products = ( - await this.list( - { id: In(ids) }, - { relations: ["profiles"], select: ["id"] } - ) - ).map((product) => { - product.profiles = !profileId - ? [] - : ([{ id: profileId }] as ShippingProfile[]) - return product - }) - - products = await productRepo.save(products) - - await this.eventBus_ - .withTransaction(manager) - .emit(ProductService.Events.UPDATED, products) - - return products - }) - } - - /** - * Temporary method to be used in place we need custom query strategy to prevent typeorm bug - * @param selector - * @param config - * @protected - */ - protected prepareListQuery_( - selector: FilterableProductProps | Selector, - config: FindProductConfig - ): { - q: string - relations: (keyof Product)[] - query: FindWithoutRelationsOptions - } { - let q - if ("q" in selector) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - query.order = config.order - - if (config.relations && config.relations.length > 0) { - query.relations = buildRelations(config.relations) - } - - if (config.select && config.select.length > 0) { - query.select = buildSelects(config.select) - } - - const rels = objectToStringPath(query.relations) - delete query.relations - - return { - query: query as FindWithoutRelationsOptions, - relations: rels as (keyof Product)[], - q, - } - } - - /** - * Temporary method to join sales channels of a product using RemoteQuery while - * MedusaV2 FF is on. - * - * @param products - * @private - */ - private async decorateProductsWithSalesChannels(products: Product[]) { - const productIdSalesChannelMapMap = - await this.getSalesChannelModuleChannels(products.map((p) => p.id)) - - products.forEach( - (product) => - (product.sales_channels = productIdSalesChannelMapMap[product.id] ?? []) - ) - - return products - } - - /** - * Temporary method to fetch sales channels of a product using RemoteQuery while - * MedusaV2 FF is on. - * - * @param productIds - * @private - */ - private async getSalesChannelModuleChannels( - productIds: string[] - ): Promise> { - const query = { - product: { - __args: { filters: { id: productIds } }, - fields: ["id"], - sales_channels: { - fields: [ - "id", - "name", - "description", - "is_disabled", - "created_at", - "updated_at", - "deleted_at", - ], - }, - }, - } - - const ret = {} - const data = (await this.remoteQuery_(query)) as { - id: string - sales_channels: SalesChannel[] - }[] - data.forEach((record) => (ret[record.id] = record.sales_channels)) - - return ret - } -} - -export default ProductService diff --git a/packages/medusa/src/services/publishable-api-key.ts b/packages/medusa/src/services/publishable-api-key.ts deleted file mode 100644 index f7f55d6b93..0000000000 --- a/packages/medusa/src/services/publishable-api-key.ts +++ /dev/null @@ -1,346 +0,0 @@ -import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager, FindOptionsWhere, ILike } from "typeorm" - -import { selectorConstraintsToString } from "@medusajs/utils" -import { TransactionBaseService } from "../interfaces" -import { PublishableApiKey, SalesChannel } from "../models" -import { PublishableApiKeyRepository } from "../repositories/publishable-api-key" -import { PublishableApiKeySalesChannelRepository } from "../repositories/publishable-api-key-sales-channel" -import { FindConfig, Selector } from "../types/common" -import { - CreatePublishableApiKeyInput, - UpdatePublishableApiKeyInput, -} from "../types/publishable-api-key" -import { buildQuery, isString } from "../utils" -import EventBusService from "./event-bus" - -type InjectedDependencies = { - manager: EntityManager - - eventBusService: EventBusService - publishableApiKeyRepository: typeof PublishableApiKeyRepository - // eslint-disable-next-line max-len - publishableApiKeySalesChannelRepository: typeof PublishableApiKeySalesChannelRepository -} - -/** - * A service for PublishableApiKey business logic. - */ -class PublishableApiKeyService extends TransactionBaseService { - static Events = { - CREATED: "publishable_api_key.created", - REVOKED: "publishable_api_key.revoked", - } - - protected readonly eventBusService_: EventBusService - // eslint-disable-next-line max-len - protected readonly publishableApiKeyRepository_: typeof PublishableApiKeyRepository - // eslint-disable-next-line max-len - protected readonly publishableApiKeySalesChannelRepository_: typeof PublishableApiKeySalesChannelRepository - - constructor({ - eventBusService, - publishableApiKeyRepository, - publishableApiKeySalesChannelRepository, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.eventBusService_ = eventBusService - this.publishableApiKeyRepository_ = publishableApiKeyRepository - this.publishableApiKeySalesChannelRepository_ = - publishableApiKeySalesChannelRepository - } - - /** - * Create a PublishableApiKey record. - * - * @param data - partial data for creating the entity - * @param context - key creation context object - */ - async create( - data: CreatePublishableApiKeyInput, - context: { - loggedInUserId: string - } - ): Promise { - return await this.atomicPhase_(async (manager) => { - const publishableApiKeyRepo = manager.withRepository( - this.publishableApiKeyRepository_ - ) - - const publishableApiKey = publishableApiKeyRepo.create({ - ...data, - created_by: context.loggedInUserId, - }) - - await this.eventBusService_ - .withTransaction(manager) - .emit(PublishableApiKeyService.Events.CREATED, { - id: publishableApiKey.id, - }) - - return await publishableApiKeyRepo.save(publishableApiKey) - }) - } - - /** - * Retrieves a PublishableApiKey by id - * - * @param publishableApiKeyId - id of the key - * @param config - a find config object - */ - async retrieve( - publishableApiKeyId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(publishableApiKeyId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"publishableApiKeyId" must be defined` - ) - } - - return await this.retrieve_({ id: publishableApiKeyId }, config) - } - - /** - * Generic retrieve for selecting PublishableApiKEys by different attributes. - * - * @param selector - a PublishableApiKey selector object - * @param config - a find config object - */ - protected async retrieve_( - selector: Selector, - config: FindConfig = {} - ): Promise { - const repo = this.activeManager_.withRepository( - this.publishableApiKeyRepository_ - ) - - const query = buildQuery(selector, config) - query.relationLoadStrategy = "query" - - const publishableApiKey = await repo.findOne(query) - - if (!publishableApiKey) { - const selectorConstraints = selectorConstraintsToString(selector) - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Publishable key with ${selectorConstraints} was not found` - ) - } - - return publishableApiKey - } - - /** - * Lists publishable API keys based on the provided parameters. - * - * @return an array containing publishable API keys and a total count of records that matches the query - */ - async listAndCount( - selector: Selector & { q?: string }, - config: FindConfig = { - skip: 0, - take: 20, - } - ): Promise<[PublishableApiKey[], number]> { - const pubKeyRepo = this.activeManager_.withRepository( - this.publishableApiKeyRepository_ - ) - - let q - if (isString(selector.q)) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - query.where = query.where as FindOptionsWhere - - if (q) { - query.where.title = ILike(`%${q}%`) - } - - return await pubKeyRepo.findAndCount(query) - } - - async update( - publishableApiKeyId: string, - data: UpdatePublishableApiKeyInput - ): Promise { - { - return await this.atomicPhase_(async (manager) => { - const publishableApiKeyRepository = manager.withRepository( - this.publishableApiKeyRepository_ - ) - - const pubKey = await this.retrieve(publishableApiKeyId) - - for (const key of Object.keys(data)) { - if (isDefined(data[key])) { - pubKey[key] = data[key] - } - } - - return await publishableApiKeyRepository.save(pubKey) - }) - } - } - - /** - * Delete Publishable API key. - * - * @param publishableApiKeyId - id of the key being deleted - */ - async delete(publishableApiKeyId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const repo = manager.withRepository(this.publishableApiKeyRepository_) - - const publishableApiKey = await this.retrieve(publishableApiKeyId).catch() - - if (publishableApiKey) { - await repo.remove(publishableApiKey) - } - }) - } - - /** - * Revoke a PublishableApiKey - * - * @param publishableApiKeyId - id of the key - * @param context - key revocation context object - */ - async revoke( - publishableApiKeyId: string, - context: { - loggedInUserId: string - } - ): Promise { - return await this.atomicPhase_(async (manager) => { - const repo = manager.withRepository(this.publishableApiKeyRepository_) - - const pubKey = await this.retrieve(publishableApiKeyId) - - if (pubKey.revoked_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `PublishableApiKey has already been revoked.` - ) - } - - pubKey.revoked_at = new Date() - pubKey.revoked_by = context.loggedInUserId - - await repo.save(pubKey) - - await this.eventBusService_ - .withTransaction(manager) - .emit(PublishableApiKeyService.Events.REVOKED, { - id: pubKey.id, - }) - }) - } - - /** - * Check whether the key is active (i.e. haven't been revoked or deleted yet) - * - * @param publishableApiKeyId - id of the key - */ - async isValid(publishableApiKeyId: string): Promise { - const pubKey = await this.retrieve(publishableApiKeyId) - return pubKey.revoked_by === null - } - - /** - * Associate provided sales channels with the publishable api key. - * - * @param publishableApiKeyId - * @param salesChannelIds - */ - async addSalesChannels( - publishableApiKeyId: string, - salesChannelIds: string[] - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const pubKeySalesChannelRepo = transactionManager.withRepository( - this.publishableApiKeySalesChannelRepository_ - ) - - await pubKeySalesChannelRepo.addSalesChannels( - publishableApiKeyId, - salesChannelIds - ) - }) - } - - /** - * Remove provided sales channels from the publishable api key scope. - * - * @param publishableApiKeyId - * @param salesChannelIds - */ - async removeSalesChannels( - publishableApiKeyId: string, - salesChannelIds: string[] - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const pubKeySalesChannelRepo = transactionManager.withRepository( - this.publishableApiKeySalesChannelRepository_ - ) - - await pubKeySalesChannelRepo.removeSalesChannels( - publishableApiKeyId, - salesChannelIds - ) - }) - } - - /** - * List SalesChannels associated with the PublishableKey - * - * @param publishableApiKeyId - id of the key SalesChannels are listed for - * @param config - querying params - */ - async listSalesChannels( - publishableApiKeyId: string, - config?: { q?: string } - ): Promise { - const pubKeySalesChannelRepo = this.activeManager_.withRepository( - this.publishableApiKeySalesChannelRepository_ - ) - - return await pubKeySalesChannelRepo.findSalesChannels( - publishableApiKeyId, - config - ) - } - - /** - * Get a map of resources ids that are withing the key's scope. - * - * @param publishableApiKeyId - */ - async getResourceScopes( - publishableApiKeyId: string - ): Promise<{ sales_channel_ids: string[] }> { - const pubKeySalesChannelRepo = this.activeManager_.withRepository( - this.publishableApiKeySalesChannelRepository_ - ) - - const salesChannels = await pubKeySalesChannelRepo.find({ - select: ["sales_channel_id"], - where: { publishable_key_id: publishableApiKeyId }, - }) - - return { - sales_channel_ids: salesChannels.map( - ({ sales_channel_id }) => sales_channel_id - ), - } - } -} - -export default PublishableApiKeyService diff --git a/packages/medusa/src/services/region.ts b/packages/medusa/src/services/region.ts deleted file mode 100644 index a32b848162..0000000000 --- a/packages/medusa/src/services/region.ts +++ /dev/null @@ -1,845 +0,0 @@ -import { isDefined, MedusaError } from "medusa-core-utils" -import { DeepPartial, EntityManager, FindOptionsWhere, ILike } from "typeorm" -import { Country, Currency, Region } from "../models" -import { FindConfig, Selector } from "../types/common" -import { CreateRegionInput, UpdateRegionInput } from "../types/region" -import { buildQuery, setMetadata } from "../utils" - -import { FlagRouter, promiseAll } from "@medusajs/utils" -import { TransactionBaseService } from "../interfaces" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { CountryRepository } from "../repositories/country" -import { CurrencyRepository } from "../repositories/currency" -import { FulfillmentProviderRepository } from "../repositories/fulfillment-provider" -import { PaymentProviderRepository } from "../repositories/payment-provider" -import { RegionRepository } from "../repositories/region" -import { TaxProviderRepository } from "../repositories/tax-provider" -import { countries } from "../utils/countries" -import EventBusService from "./event-bus" -import FulfillmentProviderService from "./fulfillment-provider" -import { PaymentProviderService } from "./index" -import StoreService from "./store" - -type InjectedDependencies = { - manager: EntityManager - storeService: StoreService - eventBusService: EventBusService - paymentProviderService: PaymentProviderService - fulfillmentProviderService: FulfillmentProviderService - featureFlagRouter: FlagRouter - - regionRepository: typeof RegionRepository - countryRepository: typeof CountryRepository - currencyRepository: typeof CurrencyRepository - taxProviderRepository: typeof TaxProviderRepository - paymentProviderRepository: typeof PaymentProviderRepository - fulfillmentProviderRepository: typeof FulfillmentProviderRepository -} - -/** - * Provides layer to manipulate regions. - */ -class RegionService extends TransactionBaseService { - static Events = { - UPDATED: "region.updated", - CREATED: "region.created", - DELETED: "region.deleted", - } - - protected featureFlagRouter_: FlagRouter - - protected readonly eventBus_: EventBusService - protected readonly storeService_: StoreService - protected readonly paymentProviderService_: PaymentProviderService - protected readonly fulfillmentProviderService_: FulfillmentProviderService - protected readonly regionRepository_: typeof RegionRepository - protected readonly countryRepository_: typeof CountryRepository - protected readonly currencyRepository_: typeof CurrencyRepository - // eslint-disable-next-line max-len - protected readonly paymentProviderRepository_: typeof PaymentProviderRepository - // eslint-disable-next-line max-len - protected readonly fulfillmentProviderRepository_: typeof FulfillmentProviderRepository - protected readonly taxProviderRepository_: typeof TaxProviderRepository - - constructor({ - regionRepository, - countryRepository, - storeService, - eventBusService, - currencyRepository, - paymentProviderRepository, - fulfillmentProviderRepository, - taxProviderRepository, - paymentProviderService, - fulfillmentProviderService, - featureFlagRouter, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.regionRepository_ = regionRepository - this.countryRepository_ = countryRepository - this.storeService_ = storeService - this.eventBus_ = eventBusService - this.currencyRepository_ = currencyRepository - this.paymentProviderRepository_ = paymentProviderRepository - this.fulfillmentProviderRepository_ = fulfillmentProviderRepository - this.paymentProviderService_ = paymentProviderService - this.taxProviderRepository_ = taxProviderRepository - this.fulfillmentProviderService_ = fulfillmentProviderService - - this.featureFlagRouter_ = featureFlagRouter - } - - /** - * Creates a region. - * - * @param data - the unvalidated region - * @return the newly created region - */ - async create(data: CreateRegionInput): Promise { - return await this.atomicPhase_(async (manager) => { - const regionRepository = manager.withRepository(this.regionRepository_) - const currencyRepository = manager.withRepository( - this.currencyRepository_ - ) - - const regionObject = { ...data } as DeepPartial - const { metadata, currency_code, includes_tax, ...toValidate } = data - - const validated = await this.validateFields(toValidate) - - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) - ) { - if (typeof includes_tax !== "undefined") { - regionObject.includes_tax = includes_tax - } - } - - if (currency_code) { - // will throw if currency is not added to store currencies - await this.validateCurrency(currency_code) - const currency = await currencyRepository.findOne({ - where: { code: currency_code.toLowerCase() }, - }) - - if (!currency) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Could not find currency with code ${currency_code}` - ) - } - - regionObject.currency = currency - regionObject.currency_code = currency_code.toLowerCase() - } - - if (metadata) { - regionObject.metadata = setMetadata( - { metadata: regionObject.metadata ?? null }, - metadata - ) - } - - for (const [key, value] of Object.entries(validated)) { - regionObject[key] = value - } - - const created = regionRepository.create(regionObject) as Region - const result = await regionRepository.save(created) - - await this.eventBus_ - .withTransaction(manager) - .emit(RegionService.Events.CREATED, { - id: result.id, - }) - - return result - }) - } - - /** - * Updates a region - * - * @param regionId - the region to update - * @param update - the data to update the region with - * @return the result of the update operation - */ - async update(regionId: string, update: UpdateRegionInput): Promise { - return await this.atomicPhase_(async (manager) => { - const regionRepository = manager.withRepository(this.regionRepository_) - const currencyRepository = manager.withRepository( - this.currencyRepository_ - ) - - const region = await this.retrieve(regionId) - - const { metadata, currency_code, includes_tax, ...toValidate } = update - - const validated = await this.validateFields(toValidate, region.id) - - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) - ) { - if (typeof includes_tax !== "undefined") { - region.includes_tax = includes_tax - } - } - - if (currency_code) { - // will throw if currency is not added to store currencies - await this.validateCurrency(currency_code) - const currency = await currencyRepository.findOne({ - where: { code: currency_code.toLowerCase() }, - }) - - if (!currency) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Could not find currency with code ${currency_code}` - ) - } - - region.currency_code = currency_code.toLowerCase() - } - - if (metadata) { - region.metadata = setMetadata(region, metadata) - } - - for (const [key, value] of Object.entries(validated)) { - region[key] = value - } - - const result = await regionRepository.save(region) - - await this.eventBus_ - .withTransaction(manager) - .emit(RegionService.Events.UPDATED, { - id: result.id, - fields: Object.keys(update), - }) - - return result - }) - } - - /** - * Validates fields for creation and updates. If the region already exists - * the id can be passed to check that country updates are allowed. - * - * @param regionData - the region data to validate - * @param id - optional id of the region to check against - * @return the validated region data - */ - protected async validateFields< - T extends CreateRegionInput | UpdateRegionInput - >( - regionData: Omit, - id?: T extends UpdateRegionInput ? string : undefined - ): Promise> { - const ppRepository = this.activeManager_.withRepository( - this.paymentProviderRepository_ - ) - const fpRepository = this.activeManager_.withRepository( - this.fulfillmentProviderRepository_ - ) - const tpRepository = this.activeManager_.withRepository( - this.taxProviderRepository_ - ) - - const region = { ...regionData } as DeepPartial - - if (region.tax_rate) { - this.validateTaxRate(region.tax_rate) - } - - if (regionData.countries) { - region.countries = await promiseAll( - regionData.countries!.map(async (countryCode) => - this.validateCountry(countryCode, id!) - ) - ).catch((err) => { - throw err - }) - } - - if ((regionData as UpdateRegionInput).tax_provider_id) { - const tp = await tpRepository.findOne({ - where: { id: (regionData as UpdateRegionInput).tax_provider_id! }, - }) - if (!tp) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Tax provider not found" - ) - } - } - - if (regionData.payment_providers) { - region.payment_providers = await promiseAll( - regionData.payment_providers.map(async (pId) => { - const pp = await ppRepository.findOne({ where: { id: pId } }) - if (!pp) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Payment provider not found" - ) - } - - return pp - }) - ) - } - - if (regionData.fulfillment_providers) { - region.fulfillment_providers = await promiseAll( - regionData.fulfillment_providers.map(async (fId) => { - const fp = await fpRepository.findOne({ where: { id: fId } }) - if (!fp) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Fulfillment provider not found" - ) - } - - return fp - }) - ) - } - - return region - } - - /** - * Validates a tax rate. Will throw if the tax rate is not between 0 and 1. - * - * @param taxRate - a number representing the tax rate of the region - * @throws if the tax rate isn't number between 0-100 - * @return void - */ - protected validateTaxRate(taxRate: number): void | never { - if (taxRate > 100 || taxRate < 0) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "The tax_rate must be between 0 and 1" - ) - } - } - - /** - * Validates a currency code. Will throw if the currency code doesn't exist. - * - * @param currencyCode - an ISO currency code - * @throws if the provided currency code is invalid - * @return void - */ - protected async validateCurrency( - currencyCode: Currency["code"] - ): Promise { - const store = await this.storeService_ - .withTransaction(this.transactionManager_) - .retrieve({ relations: ["currencies"] }) - - const storeCurrencies = store.currencies.map((curr) => curr.code) - - if (!storeCurrencies.includes(currencyCode.toLowerCase())) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Invalid currency code" - ) - } - } - - /** - * Validates a country code. Will normalize the code before checking for - * existence. - * - * @param code - a 2 digit alphanumeric ISO country code - * @param regionId - the id of the current region to check against - * @return the validated Country - */ - protected async validateCountry( - code: Country["iso_2"], - regionId: string - ): Promise { - const countryRepository = this.activeManager_.withRepository( - this.countryRepository_ - ) - - const countryCode = code.toUpperCase() - const isCountryExists = countries.some( - (country) => country.alpha2 === countryCode - ) - if (!isCountryExists) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Invalid country code" - ) - } - - const country = await countryRepository.findOne({ - where: { - iso_2: code.toLowerCase(), - }, - }) - - if (!country) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Country with code ${code} not found` - ) - } - - if (country.region_id && country.region_id !== regionId) { - throw new MedusaError( - MedusaError.Types.DUPLICATE_ERROR, - `${country.display_name} already exists in region ${country.region_id}` - ) - } - - return country - } - - /** - * Retrieve a region by country code. - * - * @param code - a 2 digit alphanumeric ISO country code - * @param config - region find config - * @return a Region with country code - */ - async retrieveByCountryCode( - code: Country["iso_2"], - config: FindConfig = {} - ): Promise { - const countryRepository = this.activeManager_.withRepository( - this.countryRepository_ - ) - - const query = buildQuery({ iso_2: code.toLowerCase() }, {}) - const country = await countryRepository.findOne(query) - - if (!country) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Country with code ${code} not found` - ) - } - - if (!country.region_id) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Country does not belong to a region` - ) - } - - return await this.retrieve(country.region_id, config) - } - - /** - * Retrieves a region by name. - * - * @param name - the name of the region to retrieve - * @return region with the matching name - */ - async retrieveByName(name: string): Promise { - const [region] = await this.list({ name }, { take: 1 }) - - if (!region) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Region "${name}" was not found` - ) - } - - return region - } - - /** - * Retrieves a region by its id. - * - * @param regionId - the id of the region to retrieve - * @param config - configuration settings - * @return the region - */ - async retrieve( - regionId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(regionId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"regionId" must be defined` - ) - } - - const regionRepository = this.activeManager_.withRepository( - this.regionRepository_ - ) - - const query = buildQuery({ id: regionId }, config) - const region = await regionRepository.findOne(query) - - if (!region) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Region with ${regionId} was not found` - ) - } - - return region - } - - /** - * Lists all regions based on a query - * - * @param {object} selector - query object for find - * @param {object} config - configuration settings - * @return {Promise} result of the find operation - */ - async list( - selector: Selector = {}, - config: FindConfig = { - relations: [], - skip: 0, - take: 10, - } - ): Promise { - const [regions] = await this.listAndCount(selector, config) - return regions - } - - /** - * Lists all regions based on a query and returns them along with count - * - * @param {object} selector - query object for find - * @param {object} config - configuration settings - * @return {Promise} result of the find operation - */ - async listAndCount( - selector: Selector & { q?: string } = {}, - config: FindConfig = { - relations: [], - skip: 0, - take: 10, - } - ): Promise<[Region[], number]> { - const regionRepo = this.activeManager_.withRepository( - this.regionRepository_ - ) - - let q: string | undefined - - if (selector.q) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - - if (q) { - const where = query.where as FindOptionsWhere - - delete where.name - - query.where = [ - { - ...where, - name: ILike(`%${q}%`), - }, - ] - } - - return await regionRepo.findAndCount(query) - } - - /** - * Deletes a region. - * - * @param regionId - the region to delete - * @return the result of the delete operation - */ - async delete(regionId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.withRepository(this.regionRepository_) - const countryRepo = manager.withRepository(this.countryRepository_) - - const region = await this.retrieve(regionId, { relations: ["countries"] }) - - if (!region) { - return Promise.resolve() - } - - await regionRepo.softRemove(region) - await countryRepo.update({ region_id: region.id }, { region_id: null }) - - await this.eventBus_ - .withTransaction(manager) - .emit(RegionService.Events.DELETED, { - id: regionId, - }) - - return Promise.resolve() - }) - } - - /** - * Adds a country to the region. - * - * @param regionId - the region to add a country to - * @param code - a 2 digit alphanumeric ISO country code. - * @return the updated Region - */ - async addCountry(regionId: string, code: Country["iso_2"]): Promise { - return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.withRepository(this.regionRepository_) - - const country = await this.validateCountry(code, regionId) - - const region = await this.retrieve(regionId, { relations: ["countries"] }) - - // Check if region already has country - if ( - region.countries && - region.countries.map((c) => c.iso_2).includes(country.iso_2) - ) { - return region - } - - region.countries = [...(region.countries || []), country] - - const updated = await regionRepo.save(region) - - await this.eventBus_ - .withTransaction(manager) - .emit(RegionService.Events.UPDATED, { - id: updated.id, - fields: ["countries"], - }) - - return updated - }) - } - - /** - * Removes a country from a Region. - * - * @param regionId - the region to remove from - * @param code - a 2 digit alphanumeric ISO country code to remove - * @return the updated Region - */ - async removeCountry( - regionId: string, - code: Country["iso_2"] - ): Promise { - return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.withRepository(this.regionRepository_) - - const region = await this.retrieve(regionId, { relations: ["countries"] }) - - // Check if region contains country. If not, we simpy resolve - if ( - region.countries && - !region.countries.map((c) => c.iso_2).includes(code) - ) { - return region - } - - region.countries = region.countries.filter( - (country) => country.iso_2 !== code - ) - - const updated = await regionRepo.save(region) - await this.eventBus_ - .withTransaction(manager) - .emit(RegionService.Events.UPDATED, { - id: updated.id, - fields: ["countries"], - }) - - return updated - }) - } - - /** - * Adds a payment provider that is available in the region. Fails if the - * provider doesn't exist. - * - * @param regionId - the region to add the provider to - * @param providerId - the provider to add to the region - * @return the updated Region - */ - async addPaymentProvider( - regionId: string, - providerId: string - ): Promise { - return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.withRepository(this.regionRepository_) - const ppRepo = manager.withRepository(this.paymentProviderRepository_) - - const region = await this.retrieve(regionId, { - relations: ["payment_providers"], - }) - - // Check if region already has payment provider - if (region.payment_providers.find(({ id }) => id === providerId)) { - return region - } - - const pp = await ppRepo.findOne({ where: { id: providerId } }) - - if (!pp) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Payment provider ${providerId} was not found` - ) - } - - region.payment_providers = [...region.payment_providers, pp] - - const updated = await regionRepo.save(region) - - await this.eventBus_ - .withTransaction(manager) - .emit(RegionService.Events.UPDATED, { - id: updated.id, - fields: ["payment_providers"], - }) - - return updated - }) - } - - /** - * Adds a fulfillment provider that is available in the region. Fails if the - * provider doesn't exist. - * - * @param regionId - the region to add the provider to - * @param providerId - the provider to add to the region - * @return the updated Region - */ - async addFulfillmentProvider( - regionId: string, - providerId: string - ): Promise { - return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.withRepository(this.regionRepository_) - const fpRepo = manager.withRepository(this.fulfillmentProviderRepository_) - - const region = await this.retrieve(regionId, { - relations: ["fulfillment_providers"], - }) - - // Check if region already has payment provider - if (region.fulfillment_providers.find(({ id }) => id === providerId)) { - return Promise.resolve(region) - } - - const fp = await fpRepo.findOne({ where: { id: providerId } }) - - if (!fp) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Fulfillment provider ${providerId} was not found` - ) - } - - region.fulfillment_providers = [...region.fulfillment_providers, fp] - - const updated = await regionRepo.save(region) - await this.eventBus_ - .withTransaction(manager) - .emit(RegionService.Events.UPDATED, { - id: updated.id, - fields: ["fulfillment_providers"], - }) - - return updated - }) - } - - /** - * Removes a payment provider from a region. Is idempotent. - * - * @param regionId - the region to remove the provider from - * @param providerId - the provider to remove from the region - * @return the updated Region - */ - async removePaymentProvider( - regionId: string, - providerId: string - ): Promise { - return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.withRepository(this.regionRepository_) - - const region = await this.retrieve(regionId, { - relations: ["payment_providers"], - }) - - // Check if region already has payment provider - if (!region.payment_providers.find(({ id }) => id === providerId)) { - return Promise.resolve(region) - } - - region.payment_providers = region.payment_providers.filter( - ({ id }) => id !== providerId - ) - - const updated = await regionRepo.save(region) - await this.eventBus_ - .withTransaction(manager) - .emit(RegionService.Events.UPDATED, { - id: updated.id, - fields: ["payment_providers"], - }) - - return updated - }) - } - - /** - * Removes a fulfillment provider from a region. Is idempotent. - * - * @param regionId - the region to remove the provider from - * @param providerId - the provider to remove from the region - * @return the updated Region - */ - async removeFulfillmentProvider( - regionId: string, - providerId: string - ): Promise { - return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.withRepository(this.regionRepository_) - - const region = await this.retrieve(regionId, { - relations: ["fulfillment_providers"], - }) - - // Check if region already has payment provider - if (!region.fulfillment_providers.find(({ id }) => id === providerId)) { - return Promise.resolve(region) - } - - region.fulfillment_providers = region.fulfillment_providers.filter( - ({ id }) => id !== providerId - ) - - const updated = await regionRepo.save(region) - await this.eventBus_ - .withTransaction(manager) - .emit(RegionService.Events.UPDATED, { - id: updated.id, - fields: ["fulfillment_providers"], - }) - - return updated - }) - } -} - -export default RegionService diff --git a/packages/medusa/src/services/return-reason.ts b/packages/medusa/src/services/return-reason.ts deleted file mode 100644 index a5f11e2a23..0000000000 --- a/packages/medusa/src/services/return-reason.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { ReturnReason } from "../models" -import { ReturnReasonRepository } from "../repositories/return-reason" -import { FindConfig, Selector } from "../types/common" -import { CreateReturnReason, UpdateReturnReason } from "../types/return-reason" -import { buildQuery } from "../utils" - -type InjectedDependencies = { - manager: EntityManager - returnReasonRepository: typeof ReturnReasonRepository -} - -class ReturnReasonService extends TransactionBaseService { - protected readonly retReasonRepo_: typeof ReturnReasonRepository - - constructor({ returnReasonRepository }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.retReasonRepo_ = returnReasonRepository - } - - async create(data: CreateReturnReason): Promise { - return await this.atomicPhase_(async (manager) => { - const rrRepo = manager.withRepository(this.retReasonRepo_) - - if (data.parent_return_reason_id && data.parent_return_reason_id !== "") { - const parentReason = await this.retrieve(data.parent_return_reason_id) - - if (parentReason.parent_return_reason_id) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Doubly nested return reasons is not supported" - ) - } - } - - const created = rrRepo.create(data) - - return await rrRepo.save(created) - }) - } - - async update(id: string, data: UpdateReturnReason): Promise { - return await this.atomicPhase_(async (manager) => { - const rrRepo = manager.withRepository(this.retReasonRepo_) - const reason = await this.retrieve(id) - - for (const key of Object.keys(data).filter( - (k) => typeof data[k] !== `undefined` - )) { - reason[key] = data[key] - } - - await rrRepo.save(reason) - - return reason - }) - } - - /** - * @param {Object} selector - the query object for find - * @param {Object} config - config object - * @return {Promise} the result of the find operation - */ - async list( - selector: Selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise { - const rrRepo = this.activeManager_.withRepository(this.retReasonRepo_) - const query = buildQuery(selector, config) - return rrRepo.find(query) - } - - /** - * Gets an order by id. - * @param {string} returnReasonId - id of order to retrieve - * @param {Object} config - config object - * @return {Promise} the order document - */ - async retrieve( - returnReasonId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(returnReasonId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"returnReasonId" must be defined` - ) - } - - const rrRepo = this.activeManager_.withRepository(this.retReasonRepo_) - - const query = buildQuery({ id: returnReasonId }, config) - const item = await rrRepo.findOne(query) - - if (!item) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Return Reason with id: ${returnReasonId} was not found.` - ) - } - - return item - } - - async delete(returnReasonId: string): Promise { - return this.atomicPhase_(async (manager) => { - const rrRepo = manager.withRepository(this.retReasonRepo_) - - // We include the relation 'return_reason_children' to enable cascading deletes of return reasons if a parent is removed - const reason = await this.retrieve(returnReasonId, { - relations: ["return_reason_children"], - }) - - if (!reason) { - return Promise.resolve() - } - - await rrRepo.softRemove(reason) - - return Promise.resolve() - }) - } -} - -export default ReturnReasonService diff --git a/packages/medusa/src/services/return.ts b/packages/medusa/src/services/return.ts deleted file mode 100644 index 1197ada901..0000000000 --- a/packages/medusa/src/services/return.ts +++ /dev/null @@ -1,739 +0,0 @@ -import { CreateReturnInput, UpdateReturnInput } from "../types/return" -import { DeepPartial, EntityManager } from "typeorm" -import { FindConfig, Selector } from "../types/common" -import { - FulfillmentProviderService, - LineItemService, - OrderService, - ProductVariantInventoryService, - ReturnReasonService, - ShippingOptionService, - TaxProviderService, - TotalsService, -} from "." -import { - FulfillmentStatus, - LineItem, - Order, - PaymentStatus, - Return, - ReturnItem, - ReturnStatus, -} from "../models" -import { isDefined, MedusaError } from "medusa-core-utils" -import { FlagRouter, promiseAll } from "@medusajs/utils" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { buildQuery, calculatePriceTaxAmount, setMetadata } from "../utils" - -import { OrdersReturnItem } from "../types/orders" -import { ReturnItemRepository } from "../repositories/return-item" -import { ReturnRepository } from "../repositories/return" -import { TransactionBaseService } from "../interfaces" - -type InjectedDependencies = { - manager: EntityManager - totalsService: TotalsService - lineItemService: LineItemService - returnRepository: typeof ReturnRepository - returnItemRepository: typeof ReturnItemRepository - shippingOptionService: ShippingOptionService - returnReasonService: ReturnReasonService - taxProviderService: TaxProviderService - fulfillmentProviderService: FulfillmentProviderService - orderService: OrderService - productVariantInventoryService: ProductVariantInventoryService - featureFlagRouter: FlagRouter -} - -type Transformer = ( - item?: LineItem, - quantity?: number, - additional?: OrdersReturnItem -) => Promise> | DeepPartial - -class ReturnService extends TransactionBaseService { - protected readonly totalsService_: TotalsService - protected readonly returnRepository_: typeof ReturnRepository - protected readonly returnItemRepository_: typeof ReturnItemRepository - protected readonly lineItemService_: LineItemService - protected readonly taxProviderService_: TaxProviderService - protected readonly shippingOptionService_: ShippingOptionService - protected readonly fulfillmentProviderService_: FulfillmentProviderService - protected readonly returnReasonService_: ReturnReasonService - protected readonly orderService_: OrderService - // eslint-disable-next-line - protected readonly productVariantInventoryService_: ProductVariantInventoryService - protected readonly featureFlagRouter_: FlagRouter - - constructor({ - totalsService, - lineItemService, - returnRepository, - returnItemRepository, - shippingOptionService, - returnReasonService, - taxProviderService, - fulfillmentProviderService, - orderService, - productVariantInventoryService, - featureFlagRouter, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.totalsService_ = totalsService - this.returnRepository_ = returnRepository - this.returnItemRepository_ = returnItemRepository - this.lineItemService_ = lineItemService - this.taxProviderService_ = taxProviderService - this.shippingOptionService_ = shippingOptionService - this.fulfillmentProviderService_ = fulfillmentProviderService - this.returnReasonService_ = returnReasonService - this.orderService_ = orderService - this.productVariantInventoryService_ = productVariantInventoryService - this.featureFlagRouter_ = featureFlagRouter - } - - /** - * Retrieves the order line items, given an array of items - * @param order - the order to get line items from - * @param items - the items to get - * @param transformer - a function to apply to each of the items - * retrieved from the order, should return a line item. If the transformer - * returns an undefined value the line item will be filtered from the - * returned array. - * @return the line items generated by the transformer. - */ - protected async getFulfillmentItems( - order: Order, - items: OrdersReturnItem[], - transformer: Transformer - ): Promise< - (LineItem & { - reason_id?: string - note?: string - })[] - > { - let merged = [...order.items] - - // merge items from order with items from order swaps - if (order.swaps && order.swaps.length) { - for (const s of order.swaps) { - merged = [...merged, ...s.additional_items] - } - } - - if (order.claims && order.claims.length) { - for (const c of order.claims) { - merged = [...merged, ...c.additional_items] - } - } - - const toReturn = await promiseAll( - items.map(async (data) => { - const item = merged.find((i) => i.id === data.item_id) - return transformer(item, data.quantity, data) - }) - ) - - return toReturn.filter((i) => !!i) as (LineItem & OrdersReturnItem)[] - } - - /** - * @param selector - the query object for find - * @param config - the config object for find - * @return the result of the find operation - */ - async list( - selector: Selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise { - const [returns] = await this.listAndCount(selector, config) - return returns - } - - /** - * @param selector - the query object for find - * @param config - the config object for find - * @return the result of the find operation - */ - async listAndCount( - selector: Selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise<[Return[], number]> { - const returnRepo = this.activeManager_.withRepository( - this.returnRepository_ - ) - const query = buildQuery(selector, config) - return returnRepo.findAndCount(query) - } - - /** - * Cancels a return if possible. Returns can be canceled if it has not been received. - * @param returnId - the id of the return to cancel. - * @return the updated Return - */ - async cancel(returnId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const ret = await this.retrieve(returnId) - - if (ret.status === ReturnStatus.RECEIVED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Can't cancel a return which has been returned" - ) - } - - const retRepo = manager.withRepository(this.returnRepository_) - - ret.status = ReturnStatus.CANCELED - - return await retRepo.save(ret) - }) - } - - /** - * Checks that an order has the statuses necessary to complete a return. - * fulfillment_status cannot be not_fulfilled or returned. - * payment_status must be captured. - * @param order - the order to check statuses on - * @throws when statuses are not sufficient for returns. - */ - protected validateReturnStatuses(order: Order): void | never { - if ( - order.fulfillment_status === FulfillmentStatus.NOT_FULFILLED || - order.fulfillment_status === FulfillmentStatus.RETURNED - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Can't return an unfulfilled or already returned order" - ) - } - - if (order.payment_status !== PaymentStatus.CAPTURED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Can't return an order with payment unprocessed" - ) - } - } - - /** - * Checks that a given quantity of a line item can be returned. Fails if the - * item is undefined or if the returnable quantity of the item is lower, than - * the quantity that is requested to be returned. - * @param item - the line item to check has sufficient returnable - * quantity. - * @param quantity - the quantity that is requested to be returned. - * @param additional - the quantity that is requested to be returned. - * @return a line item where the quantity is set to the requested - * return quantity. - */ - protected validateReturnLineItem( - item?: LineItem, - quantity = 0, - additional: { reason_id?: string; note?: string } = {} - ): DeepPartial { - if (!item) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Return contains invalid line item" - ) - } - - const returnable = item.quantity - item.returned_quantity! - if (quantity > returnable) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot return more items than have been purchased" - ) - } - - const toReturn: DeepPartial = { - ...item, - quantity, - } - - if ("reason_id" in additional) { - toReturn.reason_id = additional.reason_id as string - } - - if ("note" in additional) { - toReturn.note = additional.note - } - - return toReturn - } - - /** - * Retrieves a return by its id. - * @param returnId - the id of the return to retrieve - * @param config - the config object - * @return the return - */ - async retrieve( - returnId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(returnId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"returnId" must be defined` - ) - } - - const returnRepository = this.activeManager_.withRepository( - this.returnRepository_ - ) - - const query = buildQuery({ id: returnId }, config) - - const returnObj = await returnRepository.findOne(query) - - if (!returnObj) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Return with id: ${returnId} was not found` - ) - } - return returnObj - } - - async retrieveBySwap( - swapId: string, - relations: string[] = [] - ): Promise { - const returnRepository = this.activeManager_.withRepository( - this.returnRepository_ - ) - - const returnObj = await returnRepository.findOne({ - where: { - swap_id: swapId, - }, - relations, - }) - - if (!returnObj) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Return with swa_id: ${swapId} was not found` - ) - } - - return returnObj - } - - async update(returnId: string, update: UpdateReturnInput): Promise { - return await this.atomicPhase_(async (manager) => { - const ret = await this.retrieve(returnId) - - if (ret.status === "canceled") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot update a canceled return" - ) - } - - const { metadata, ...rest } = update - - if (metadata) { - ret.metadata = setMetadata(ret, metadata) - } - - for (const [key, value] of Object.entries(rest)) { - ret[key] = value - } - - const retRepo = manager.withRepository(this.returnRepository_) - return await retRepo.save(ret) - }) - } - - /** - * Creates a return request for an order, with given items, and a shipping - * method. If no refund amount is provided the refund amount is calculated from - * the return lines and the shipping cost. - * @param data - data to use for the return e.g. shipping_method, - * items or refund_amount - * @return the created return - */ - async create(data: CreateReturnInput): Promise { - return await this.atomicPhase_(async (manager) => { - const returnRepository = manager.withRepository(this.returnRepository_) - - const orderId = data.order_id - if (data.swap_id) { - delete (data as Partial).order_id - } - - for (const item of data.items ?? []) { - const line = await this.lineItemService_ - .withTransaction(manager) - .retrieve(item.item_id, { - relations: ["order", "swap", "claim_order"], - }) - - if ( - line.order?.canceled_at || - line.swap?.canceled_at || - line.claim_order?.canceled_at - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Cannot create a return for a canceled item.` - ) - } - } - - const order = await this.orderService_ - .withTransaction(manager) - .retrieve(orderId, { - select: ["refunded_total", "total", "refundable_amount"], - relations: [ - "swaps", - "swaps.additional_items", - "swaps.additional_items.tax_lines", - "claims", - "claims.additional_items", - "claims.additional_items.tax_lines", - "items", - "items.tax_lines", - "region", - "region.tax_rates", - ], - }) - - const returnLines = await this.getFulfillmentItems( - order, - data.items ?? [], - this.validateReturnLineItem - ) - - let toRefund = data.refund_amount - if (isDefined(toRefund)) { - // Merchant wants to do a custom refund amount; we check if amount is - // refundable - const refundable = order.refundable_amount - - if (toRefund! > refundable) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Cannot refund more than the original payment" - ) - } - } else { - // Merchant hasn't specified refund amount so we calculate it - toRefund = await this.totalsService_.getRefundTotal(order, returnLines) - } - - const method = data.shipping_method - delete data.shipping_method - - const returnObject = { - ...data, - status: ReturnStatus.REQUESTED, - refund_amount: Math.floor(toRefund!), - } - - const returnReasons = await this.returnReasonService_ - .withTransaction(manager) - .list( - { id: [...returnLines.map((rl) => rl.reason_id as string)] }, - { relations: ["return_reason_children"] } - ) - - if (returnReasons.some((rr) => rr.return_reason_children?.length > 0)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Cannot apply return reason category" - ) - } - - const rItemRepo = manager.withRepository(this.returnItemRepository_) - returnObject.items = returnLines.map((i) => - rItemRepo.create({ - item_id: i.id, - quantity: i.quantity, - requested_quantity: i.quantity, - reason_id: i.reason_id, - note: i.note, - metadata: i.metadata, - }) - ) - - const created = returnRepository.create(returnObject) - const result = await returnRepository.save(created) - - if (method && method.option_id) { - const shippingMethod = await this.shippingOptionService_ - .withTransaction(manager) - .createShippingMethod( - method.option_id, - {}, - { - price: method.price, - return_id: result.id, - } - ) - - const calculationContext = - await this.totalsService_.getCalculationContext(order) - - const taxLines = await this.taxProviderService_ - .withTransaction(manager) - .createShippingTaxLines(shippingMethod, calculationContext) - - const includesTax = - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && shippingMethod.includes_tax - - const taxRate = taxLines.reduce((acc, curr) => { - return acc + curr.rate / 100 - }, 0) - - const taxAmountIncludedInPrice = !includesTax - ? 0 - : Math.round( - calculatePriceTaxAmount({ - price: shippingMethod.price, - taxRate, - includesTax, - }) - ) - - const shippingPriceWithoutTax = - shippingMethod.price - taxAmountIncludedInPrice - - const shippingTotal = - shippingPriceWithoutTax + - taxLines.reduce( - (acc, tl) => - acc + Math.round(shippingPriceWithoutTax * (tl.rate / 100)), - 0 - ) - - if (typeof data.refund_amount === "undefined") { - result.refund_amount = toRefund! - shippingTotal - return await returnRepository.save(result) - } - } - - return result - }) - } - - async fulfill(returnId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const returnOrder = await this.retrieve(returnId, { - relations: [ - "items", - "shipping_method", - "shipping_method.tax_lines", - "shipping_method.shipping_option", - "swap", - "claim_order", - ], - }) - - if (returnOrder.status === "canceled") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot fulfill a canceled return" - ) - } - - const returnData = { ...returnOrder } - - const items = await this.lineItemService_.withTransaction(manager).list( - { - id: returnOrder.items.map(({ item_id }) => item_id), - }, - { - relations: ["tax_lines", "variant.product.profiles"], - } - ) - - returnData.items = returnOrder.items.map((item) => { - const found = items.find((i) => i.id === item.item_id) - return { - ...item, - item: found, - } as ReturnItem - }) - - if (returnOrder.shipping_data) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Return has already been fulfilled" - ) - } - - if (returnOrder.shipping_method === null) { - return returnOrder - } - - returnOrder.shipping_data = - await this.fulfillmentProviderService_.createReturn(returnData) - - const returnRepo = manager.withRepository(this.returnRepository_) - return await returnRepo.save(returnOrder) - }) - } - - /** - * Registers a previously requested return as received. This will create a - * refund to the customer. If the returned items don't match the requested - * items the return status will be updated to requires_action. This behaviour - * is useful in situations where a custom refund amount is requested, but the - * returned items are not matching the requested items. Setting the - * allowMismatch argument to true, will process the return, ignoring any - * mismatches. - * @param returnId - the orderId to return to - * @param receivedItems - the items received after return. - * @param refundAmount - the amount to return - * @param allowMismatch - whether to ignore return/received - * product mismatch - * @return the result of the update operation - */ - async receive( - returnId: string, - receivedItems: OrdersReturnItem[], - refundAmount?: number, - allowMismatch = false, - context: { locationId?: string } = {} - ): Promise { - return await this.atomicPhase_(async (manager) => { - const returnRepository = manager.withRepository(this.returnRepository_) - - const returnObj = await this.retrieve(returnId, { - relations: ["items", "swap", "swap.additional_items"], - }) - - if (returnObj.status === ReturnStatus.CANCELED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot receive a canceled return" - ) - } - - let orderId = returnObj.order_id - // check if return is requested on a swap - if (returnObj.swap) { - orderId = returnObj.swap.order_id - } - - const order = await this.orderService_ - .withTransaction(manager) - .retrieve(orderId!, { - relations: [ - "items", - "returns", - "payments", - "discounts", - "discounts.rule", - "refunds", - "shipping_methods", - "shipping_methods.shipping_option", - "region", - "swaps", - "swaps.additional_items", - "claims", - "claims.additional_items", - ], - }) - - if (returnObj.status === ReturnStatus.RECEIVED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Return with id ${returnId} has already been received` - ) - } - - const returnLines = await this.getFulfillmentItems( - order, - receivedItems, - this.validateReturnLineItem - ) - - const newLines = returnLines.map((l) => { - const existing = returnObj.items.find((i) => l.id === i.item_id) - if (existing) { - return { - ...existing, - quantity: l.quantity, - requested_quantity: existing.quantity, - received_quantity: l.quantity, - is_requested: l.quantity === existing.quantity, - } - } else { - return { - return_id: returnObj.id, - item_id: l.id, - quantity: l.quantity, - is_requested: false, - received_quantity: l.quantity, - metadata: l.metadata || {}, - } - } - }) - - let returnStatus = ReturnStatus.RECEIVED - - const isMatching = newLines.every((l) => l.is_requested) - if (!isMatching && !allowMismatch) { - returnStatus = ReturnStatus.REQUIRES_ACTION - } - - const totalRefundableAmount = refundAmount ?? returnObj.refund_amount - - const now = new Date() - const updateObj = { - ...returnObj, - location_id: context.locationId || returnObj.location_id, - status: returnStatus, - items: newLines, - refund_amount: totalRefundableAmount, - received_at: now.toISOString(), - } - - const result = await returnRepository.save(updateObj) - - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - for (const i of returnObj.items) { - const lineItem = await lineItemServiceTx.retrieve(i.item_id) - const returnedQuantity = (lineItem.returned_quantity || 0) + i.quantity - await lineItemServiceTx.update(i.item_id, { - returned_quantity: returnedQuantity, - }) - } - - const productVarInventoryTx = - this.productVariantInventoryService_.withTransaction(manager) - - for (const line of newLines) { - const orderItem = order.items.find((i) => i.id === line.item_id) - if (orderItem && orderItem.variant_id) { - await productVarInventoryTx.adjustInventory( - orderItem.variant_id, - result.location_id!, - line.received_quantity - ) - } - } - - return result - }) - } -} - -export default ReturnService diff --git a/packages/medusa/src/services/sales-channel-inventory.ts b/packages/medusa/src/services/sales-channel-inventory.ts deleted file mode 100644 index b38d23f2ec..0000000000 --- a/packages/medusa/src/services/sales-channel-inventory.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { EventBusTypes, IInventoryService } from "@medusajs/types" -import { TransactionBaseService } from "../interfaces" -import { EntityManager } from "typeorm" -import SalesChannelLocationService from "./sales-channel-location" - -type InjectedDependencies = { - inventoryService: IInventoryService - salesChannelLocationService: SalesChannelLocationService - eventBusService: EventBusTypes.IEventBusService - manager: EntityManager -} - -class SalesChannelInventoryService extends TransactionBaseService { - protected readonly salesChannelLocationService_: SalesChannelLocationService - protected readonly eventBusService_: EventBusTypes.IEventBusService - - protected get inventoryService_(): IInventoryService { - return this.__container__.inventoryService - } - - constructor({ - salesChannelLocationService, - eventBusService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.salesChannelLocationService_ = salesChannelLocationService - this.eventBusService_ = eventBusService - } - - /** - * Retrieves the available quantity of an item across all sales channel locations - * @param salesChannelId Sales channel id - * @param inventoryItemId Item id - * @returns available quantity of item across all sales channel locations - */ - async retrieveAvailableItemQuantity( - salesChannelId: string, - inventoryItemId: string - ): Promise { - const locationIds = await this.salesChannelLocationService_ - .withTransaction(this.activeManager_) - .listLocationIds(salesChannelId) - - return await this.inventoryService_.retrieveAvailableQuantity( - inventoryItemId, - locationIds - ) - } -} - -export default SalesChannelInventoryService diff --git a/packages/medusa/src/services/sales-channel-location.ts b/packages/medusa/src/services/sales-channel-location.ts deleted file mode 100644 index 2c1d7e7b43..0000000000 --- a/packages/medusa/src/services/sales-channel-location.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { IEventBusService, IStockLocationService } from "@medusajs/types" -import { MedusaError } from "medusa-core-utils" -import { EntityManager, In } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { SalesChannelLocation } from "../models/sales-channel-location" -import SalesChannelService from "./sales-channel" - -type InjectedDependencies = { - stockLocationService: IStockLocationService - salesChannelService: SalesChannelService - eventBusService: IEventBusService - manager: EntityManager -} - -/** - * Service for managing the stock locations of sales channels - */ - -class SalesChannelLocationService extends TransactionBaseService { - protected readonly salesChannelService_: SalesChannelService - protected readonly eventBusService_: IEventBusService - - protected get stockLocationService_(): IStockLocationService { - return this.__container__.stockLocationService - } - - constructor({ salesChannelService, eventBusService }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.salesChannelService_ = salesChannelService - this.eventBusService_ = eventBusService - } - - /** - * Removes an association between a sales channel and a stock location. - * @param salesChannelId - The ID of the sales channel or undefined if all the sales channel will be affected. - * @param locationId - The ID of the stock location. - * @returns A promise that resolves when the association has been removed. - */ - async removeLocation( - locationId: string, - salesChannelId?: string - ): Promise { - const salesChannelLocationRepo = - this.activeManager_.getRepository(SalesChannelLocation) - - const where: any = { - location_id: locationId, - } - if (salesChannelId) { - where.sales_channel_id = salesChannelId - } - - const scLoc = await salesChannelLocationRepo.find({ - where, - }) - - if (scLoc.length) { - await salesChannelLocationRepo.remove(scLoc) - } - } - - /** - * Associates a sales channel with a stock location. - * @param salesChannelId - The ID of the sales channel. - * @param locationId - The ID of the stock location. - * @returns A promise that resolves when the association has been created. - */ - async associateLocation( - salesChannelId: string, - locationId: string - ): Promise { - const salesChannel = await this.salesChannelService_ - .withTransaction(this.activeManager_) - .retrieve(salesChannelId) - - if (this.stockLocationService_) { - // throws error if not found - await this.stockLocationService_.retrieve(locationId, undefined, { - transactionManager: this.activeManager_, - }) - } - - const salesChannelLocationRepo = - this.activeManager_.getRepository(SalesChannelLocation) - - const salesChannelLocation = salesChannelLocationRepo.create({ - sales_channel_id: salesChannel.id, - location_id: locationId, - }) - - await salesChannelLocationRepo.save(salesChannelLocation) - } - - /** - * Lists the stock locations associated with a sales channel. - * @param salesChannelId - The ID of the sales channel. - * @returns A promise that resolves with an array of location IDs. - */ - async listLocationIds(salesChannelId: string | string[]): Promise { - const ids = Array.isArray(salesChannelId) - ? salesChannelId - : [salesChannelId] - - const [salesChannels, count] = await this.salesChannelService_ - .withTransaction(this.activeManager_) - .listAndCount({ id: ids }, { select: ["id"], skip: 0 }) - - if (!count) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Sales channel with id: ${ids.join(", ")} was not found` - ) - } - - const locations = await this.activeManager_.find(SalesChannelLocation, { - where: { sales_channel_id: In(salesChannels.map((sc) => sc.id)) }, - select: ["location_id"], - }) - - return locations.map((l) => l.location_id) - } - - /** - * Lists the sales channels associated with a stock location. - * @param {string} locationId - The ID of the stock location. - * @returns {Promise} A promise that resolves with an array of sales channel IDs. - */ - async listSalesChannelIds(locationId: string): Promise { - const location = await this.stockLocationService_.retrieve( - locationId, - undefined, - { - transactionManager: this.activeManager_, - } - ) - - const salesChannelRepo = - this.activeManager_.getRepository(SalesChannelLocation) - - const salesChannelLocations = await salesChannelRepo.find({ - where: { location_id: location.id }, - select: ["sales_channel_id"], - }) - - return salesChannelLocations.map((l) => l.sales_channel_id) - } -} - -export default SalesChannelLocationService diff --git a/packages/medusa/src/services/sales-channel.ts b/packages/medusa/src/services/sales-channel.ts deleted file mode 100644 index 7087fa0c3f..0000000000 --- a/packages/medusa/src/services/sales-channel.ts +++ /dev/null @@ -1,410 +0,0 @@ -import { EntityManager } from "typeorm" -import { isDefined, MedusaError } from "medusa-core-utils" -import { FlagRouter, MedusaV2Flag } from "@medusajs/utils" - -import { FindConfig, QuerySelector, Selector } from "../types/common" -import { - CreateSalesChannelInput, - UpdateSalesChannelInput, -} from "../types/sales-channels" - -import { TransactionBaseService } from "../interfaces" -import { SalesChannel } from "../models" -import { SalesChannelRepository } from "../repositories/sales-channel" -import { buildQuery } from "../utils" -import EventBusService from "./event-bus" -import StoreService from "./store" -import {selectorConstraintsToString} from "@medusajs/utils"; - -type InjectedDependencies = { - salesChannelRepository: typeof SalesChannelRepository - eventBusService: EventBusService - manager: EntityManager - storeService: StoreService - featureFlagRouter: FlagRouter -} - -class SalesChannelService extends TransactionBaseService { - static Events = { - UPDATED: "sales_channel.updated", - CREATED: "sales_channel.created", - DELETED: "sales_channel.deleted", - } - - protected readonly salesChannelRepository_: typeof SalesChannelRepository - protected readonly eventBusService_: EventBusService - protected readonly storeService_: StoreService - protected readonly featureFlagRouter_: FlagRouter - - constructor({ - salesChannelRepository, - eventBusService, - storeService, - featureFlagRouter, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.salesChannelRepository_ = salesChannelRepository - this.eventBusService_ = eventBusService - this.storeService_ = storeService - this.featureFlagRouter_ = featureFlagRouter - } - - /** - * A generic retrieve used to find a sales channel by different attributes. - * - * @param selector - SC selector - * @param config - find config - * @returns a single SC matching the query or throws - */ - protected async retrieve_( - selector: Selector, - config: FindConfig = {} - ): Promise { - const salesChannelRepo = this.activeManager_.withRepository( - this.salesChannelRepository_ - ) - - const query = buildQuery(selector, config) - - const salesChannel = await salesChannelRepo.findOne({ - ...query, - relationLoadStrategy: "query", - }) - - if (!salesChannel) { - const selectorConstraints = selectorConstraintsToString(selector) - - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Sales channel with ${selectorConstraints} was not found` - ) - } - - return salesChannel - } - - /** - * Retrieve a SalesChannel by id - * - * @param salesChannelId - id of the channel to retrieve - * @param config - SC config - * @experimental This feature is under development and may change in the future. - * To use this feature please enable the corresponding feature flag in your medusa backend project. - * @returns a sales channel - */ - async retrieve( - salesChannelId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(salesChannelId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"salesChannelId" must be defined` - ) - } - - return await this.retrieve_({ id: salesChannelId }, config) - } - - /** - * Find a sales channel by name. - * - * @param name of the sales channel - * @param config - find config - * @return a sales channel with matching name - */ - async retrieveByName( - name: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(name)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"name" must be defined` - ) - } - - return await this.retrieve_({ name }, config) - } - - /** - * Lists sales channels based on the provided parameters and include the count of - * sales channels that match the query. - * - * @return an array containing the sales channels as - * the first element and the total count of sales channels that matches the query - * as the second element. - */ - async listAndCount( - selector: QuerySelector, - config: FindConfig = { - skip: 0, - take: 20, - } - ): Promise<[SalesChannel[], number]> { - const salesChannelRepo = this.activeManager_.withRepository( - this.salesChannelRepository_ - ) - - const selector_ = { ...selector } - let q: string | undefined - if ("q" in selector_) { - q = selector_.q - delete selector_.q - } - - const query = buildQuery(selector_, config) - - if (q) { - return await salesChannelRepo.getFreeTextSearchResultsAndCount(q, query) - } - - return await salesChannelRepo.findAndCount(query) - } - - /** - * Lists sales channels based on the provided parameters. - * - * @return an array containing the sales channels - */ - async list( - selector: QuerySelector, - config: FindConfig = { - skip: 0, - take: 20, - } - ): Promise { - const salesChannelRepo = this.activeManager_.withRepository( - this.salesChannelRepository_ - ) - - const selector_ = { ...selector } - let q: string | undefined - if ("q" in selector_) { - q = selector_.q - delete selector_.q - } - - const query = buildQuery(selector_, config) - - if (q) { - return await salesChannelRepo.getFreeTextSearchResults(q, query) - } - - return await salesChannelRepo.find(query) - } - - /** - * Creates a SalesChannel - * - * @experimental This feature is under development and may change in the future. - * To use this feature please enable the corresponding feature flag in your medusa backend project. - * @returns the created channel - */ - async create(data: CreateSalesChannelInput): Promise { - return await this.atomicPhase_(async (manager) => { - const salesChannelRepo: typeof SalesChannelRepository = - manager.withRepository(this.salesChannelRepository_) - - const salesChannel = salesChannelRepo.create(data) - - await this.eventBusService_ - .withTransaction(manager) - .emit(SalesChannelService.Events.CREATED, { - id: salesChannel.id, - }) - - return await salesChannelRepo.save(salesChannel) - }) - } - - async update( - salesChannelId: string, - data: UpdateSalesChannelInput - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const salesChannelRepo: typeof SalesChannelRepository = - transactionManager.withRepository(this.salesChannelRepository_) - - const salesChannel = await this.retrieve(salesChannelId) - - for (const key of Object.keys(data)) { - if (typeof data[key] !== `undefined`) { - salesChannel[key] = data[key] - } - } - - const result = await salesChannelRepo.save(salesChannel) - - await this.eventBusService_ - .withTransaction(transactionManager) - .emit(SalesChannelService.Events.UPDATED, { - id: result.id, - }) - - return result - }) - } - - /** - * Deletes a sales channel from - * @experimental This feature is under development and may change in the future. - * To use this feature please enable the corresponding feature flag in your medusa backend project. - * @param salesChannelId - the id of the sales channel to delete - */ - async delete(salesChannelId: string): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const salesChannelRepo = transactionManager.withRepository( - this.salesChannelRepository_ - ) - - const salesChannel = await this.retrieve(salesChannelId, { - relations: ["locations"], - }).catch(() => void 0) - - if (!salesChannel) { - return - } - - const store = await this.storeService_.retrieve({ - select: ["default_sales_channel_id"], - }) - - if (salesChannel.id === store?.default_sales_channel_id) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "You cannot delete the default sales channel" - ) - } - - await salesChannelRepo.softRemove(salesChannel) - - await this.eventBusService_ - .withTransaction(transactionManager) - .emit(SalesChannelService.Events.DELETED, { - id: salesChannelId, - }) - }) - } - - /** - * Creates a default sales channel, if this does not already exist. - * @return the sales channel - */ - async createDefault(): Promise { - return this.atomicPhase_(async (transactionManager) => { - const store = await this.storeService_ - .withTransaction(transactionManager) - .retrieve({ - relations: ["default_sales_channel"], - }) - - if (store.default_sales_channel_id) { - return store.default_sales_channel - } - - const defaultSalesChannel = await this.create({ - description: "Created by Medusa", - name: "Default Sales Channel", - is_disabled: false, - }) - - await this.storeService_.withTransaction(transactionManager).update({ - default_sales_channel_id: defaultSalesChannel.id, - }) - - return defaultSalesChannel - }) - } - - /** - * Retrieves the default sales channel. - * @return the sales channel - */ - async retrieveDefault(): Promise { - const store = await this.storeService_ - .withTransaction(this.activeManager_) - .retrieve({ - relations: ["default_sales_channel"], - }) - - if (!store.default_sales_channel) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Default Sales channel was not found` - ) - } - - return store.default_sales_channel - } - - /** - * List all product ids that belongs to the sales channels ids - * - * @param salesChannelIds - */ - async listProductIdsBySalesChannelIds( - salesChannelIds: string | string[] - ): Promise<{ [salesChannelId: string]: string[] }> { - const salesChannelRepo = this.activeManager_.withRepository( - this.salesChannelRepository_ - ) - return await salesChannelRepo.listProductIdsBySalesChannelIds( - salesChannelIds - ) - } - - /** - * Remove a batch of product from a sales channel - * @param salesChannelId - The id of the sales channel on which to remove the products - * @param productIds - The products ids to remove from the sales channel - * @return the sales channel on which the products have been removed - */ - async removeProducts( - salesChannelId: string, - productIds: string[] - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const salesChannelRepo = transactionManager.withRepository( - this.salesChannelRepository_ - ) - - await salesChannelRepo.removeProducts(salesChannelId, productIds) - - return await this.retrieve(salesChannelId) - }) - } - - /** - * Add a batch of product to a sales channel - * @param salesChannelId - The id of the sales channel on which to add the products - * @param productIds - The products ids to attach to the sales channel - * @return the sales channel on which the products have been added - */ - async addProducts( - salesChannelId: string, - productIds: string[] - ): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const salesChannelRepo = transactionManager.withRepository( - this.salesChannelRepository_ - ) - - const isMedusaV2Enabled = this.featureFlagRouter_.isFeatureEnabled( - MedusaV2Flag.key - ) - - await salesChannelRepo.addProducts( - salesChannelId, - productIds, - isMedusaV2Enabled - ) - - return await this.retrieve(salesChannelId) - }) - } -} - -export default SalesChannelService diff --git a/packages/medusa/src/services/search.ts b/packages/medusa/src/services/search.ts deleted file mode 100644 index e4cd2afe43..0000000000 --- a/packages/medusa/src/services/search.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { AbstractSearchService } from "@medusajs/utils" -import { EntityManager } from "typeorm" -import { Logger } from "../types/global" - -type InjectedDependencies = { - logger: Logger - manager: EntityManager -} - -export default class DefaultSearchService extends AbstractSearchService { - isDefault = true - - protected readonly logger_: Logger - protected readonly options_: Record - - constructor({ logger, manager }: InjectedDependencies, options) { - super( - { - logger, - }, - options - ) - - this.options_ = options - this.logger_ = logger - } - - async createIndex(indexName: string, options: unknown): Promise { - this.logger_.warn( - "This is an empty method: createIndex must be overridden by a child class" - ) - } - - async getIndex(indexName: string): Promise { - this.logger_.warn( - "This is an empty method: getIndex must be overridden by a child class" - ) - } - - async addDocuments( - indexName: string, - documents: unknown, - type: string - ): Promise { - this.logger_.warn( - "This is an empty method: addDocuments must be overridden by a child class" - ) - } - - async replaceDocuments( - indexName: string, - documents: unknown, - type: string - ): Promise { - this.logger_.warn( - "This is an empty method: replaceDocuments must be overridden by a child class" - ) - } - - async deleteDocument( - indexName: string, - document_id: string | number - ): Promise { - this.logger_.warn( - "This is an empty method: deleteDocument must be overridden by a child class" - ) - } - - async deleteAllDocuments(indexName: string): Promise { - this.logger_.warn( - "This is an empty method: deleteAllDocuments must be overridden by a child class" - ) - } - - async search( - indexName: string, - query: unknown, - options: unknown - ): Promise<{ hits: unknown[] }> { - this.logger_.warn( - "This is an empty method: search must be overridden a the child class" - ) - return { hits: [] } - } - - async updateSettings(indexName: string, settings: unknown): Promise { - this.logger_.warn( - "This is an empty method: updateSettings must be overridden by a child class" - ) - } -} diff --git a/packages/medusa/src/services/shipping-option.ts b/packages/medusa/src/services/shipping-option.ts deleted file mode 100644 index f9dba97b60..0000000000 --- a/packages/medusa/src/services/shipping-option.ts +++ /dev/null @@ -1,823 +0,0 @@ -import { FlagRouter, promiseAll } from "@medusajs/utils" -import { MedusaError, isDefined } from "medusa-core-utils" -import { - Cart, - Order, - ShippingMethod, - ShippingOption, - ShippingOptionPriceType, - ShippingOptionRequirement, -} from "../models" -import { FindConfig, Selector } from "../types/common" -import { - CreateShippingMethodDto, - CreateShippingOptionInput, - ShippingMethodUpdate, - UpdateShippingOptionInput, - ValidatePriceTypeAndAmountInput, - ValidateRequirementTypeInput, -} from "../types/shipping-options" -import { buildQuery, isString, setMetadata } from "../utils" - -import { EntityManager, FindOptionsWhere, ILike } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { ShippingMethodRepository } from "../repositories/shipping-method" -import { ShippingOptionRepository } from "../repositories/shipping-option" -import { ShippingOptionRequirementRepository } from "../repositories/shipping-option-requirement" -import FulfillmentProviderService from "./fulfillment-provider" -import RegionService from "./region" - -type InjectedDependencies = { - manager: EntityManager - fulfillmentProviderService: FulfillmentProviderService - regionService: RegionService - // eslint-disable-next-line max-len - shippingOptionRequirementRepository: typeof ShippingOptionRequirementRepository - shippingOptionRepository: typeof ShippingOptionRepository - shippingMethodRepository: typeof ShippingMethodRepository - featureFlagRouter: FlagRouter -} - -/** - * Provides layer to manipulate profiles. - */ -class ShippingOptionService extends TransactionBaseService { - protected readonly providerService_: FulfillmentProviderService - protected readonly regionService_: RegionService - // eslint-disable-next-line max-len - protected readonly requirementRepository_: typeof ShippingOptionRequirementRepository - protected readonly optionRepository_: typeof ShippingOptionRepository - protected readonly methodRepository_: typeof ShippingMethodRepository - protected readonly featureFlagRouter_: FlagRouter - - constructor({ - shippingOptionRepository, - shippingOptionRequirementRepository, - shippingMethodRepository, - fulfillmentProviderService, - regionService, - featureFlagRouter, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.optionRepository_ = shippingOptionRepository - this.methodRepository_ = shippingMethodRepository - this.requirementRepository_ = shippingOptionRequirementRepository - this.providerService_ = fulfillmentProviderService - this.regionService_ = regionService - this.featureFlagRouter_ = featureFlagRouter - } - - /** - * Validates a requirement - * @param {ShippingOptionRequirement} requirement - the requirement to validate - * @param {string} optionId - the id to validate the requirement - * @return {ShippingOptionRequirement} a validated shipping requirement - */ - async validateRequirement_( - requirement: ValidateRequirementTypeInput, - optionId: string | undefined = undefined - ): Promise { - return await this.atomicPhase_(async (manager) => { - if (!requirement.type) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "A Shipping Requirement must have a type field" - ) - } - - if ( - requirement.type !== "min_subtotal" && - requirement.type !== "max_subtotal" - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Requirement type must be one of min_subtotal, max_subtotal" - ) - } - - const reqRepo = manager.withRepository(this.requirementRepository_) - - const existingReq = requirement.id - ? await reqRepo.findOne({ - where: { id: requirement.id }, - }) - : undefined - - if (!existingReq && requirement.id) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Shipping option requirement with id ${requirement.id} does not exist` - ) - } - - // If no option id is provided, we are currently in the process of creating - // a new shipping option. Therefore, simply return the requirement, such - // that the cascading will take care of the creation of the requirement. - if (!optionId) { - return requirement - } - - let req - if (existingReq) { - req = await reqRepo.save({ - ...existingReq, - ...requirement, - }) - } else { - const created = reqRepo.create({ - ...requirement, - shipping_option_id: optionId, - }) - - req = await reqRepo.save(created) - } - - return req - }) - } - - /** - * @param {Object} selector - the query object for find - * @param {object} config - config object - * @return {Promise} the result of the find operation - */ - async list( - selector: Selector & { q?: string } = {}, - config: FindConfig = { skip: 0, take: 50 } - ): Promise { - const optRepo = this.activeManager_.withRepository(this.optionRepository_) - - let q: string | undefined - if (selector.q) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - - if (q) { - const where = query.where as FindOptionsWhere - delete where.name - - query.where = [ - { - ...where, - name: ILike(`%${q}%`), - }, - ] - } - - return optRepo.find(query) - } - - /** - * @param selector - the query object for find - * @param config - config object - * @return the result of the find operation - */ - async listAndCount( - selector: Selector & { q?: string } = {}, - config: FindConfig = { skip: 0, take: 50 } - ): Promise<[ShippingOption[], number]> { - const optRepo = this.activeManager_.withRepository(this.optionRepository_) - - let q: string | undefined - if (selector.q) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - - if (q) { - const where = query.where as FindOptionsWhere - delete where.name - - query.where = [ - { - ...where, - name: ILike(`%${q}%`), - }, - ] - } - - return await optRepo.findAndCount(query) - } - - /** - * Gets a profile by id. - * Throws in case of DB Error and if profile was not found. - * @param {string} optionId - the id of the profile to get. - * @param {object} options - the options to get a profile - * @return {Promise} the profile document. - */ - async retrieve( - optionId, - options: FindConfig = {} - ): Promise { - if (!isDefined(optionId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"optionId" must be defined` - ) - } - - const soRepo = this.activeManager_.withRepository(this.optionRepository_) - - const query = buildQuery({ id: optionId }, options) - - const option = await soRepo.findOne(query) - - if (!option) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Shipping Option with ${optionId} was not found` - ) - } - - return option - } - - /** - * Updates a shipping method's associations. Useful when a cart is completed - * and its methods should be copied to an order/swap entity. - * @param {string} id - the id of the shipping method to update - * @param {object} update - the values to update the method with - * @return {Promise} the resulting shipping method - */ - async updateShippingMethod( - id: string, - update: ShippingMethodUpdate - ): Promise { - return await this.atomicPhase_(async (manager) => { - const methodRepo = manager.withRepository(this.methodRepository_) - const method = await methodRepo.findOne({ where: { id } }) - - if (!method) { - return undefined - } - - for (const key of Object.keys(update).filter( - (k) => typeof update[k] !== `undefined` - )) { - method[key] = update[key] - } - - return methodRepo.save(method) - }) - } - - /** - * Removes a given shipping method - * @param {ShippingMethod | Array} shippingMethods - the shipping method to remove - * @returns removed shipping methods - */ - async deleteShippingMethods( - shippingMethods: ShippingMethod | ShippingMethod[] - ): Promise { - const removeEntities: ShippingMethod[] = Array.isArray(shippingMethods) - ? shippingMethods - : [shippingMethods] - - return await this.atomicPhase_(async (manager) => { - const methodRepo = manager.withRepository(this.methodRepository_) - return await methodRepo.remove(removeEntities) - }) - } - - /** - * Creates a shipping method for a given cart. - * @param {string} optionId - the id of the option to use for the method. - * @param {object} data - the optional provider data to use. - * @param {object} config - the cart to create the shipping method for. - * @return {ShippingMethod} the resulting shipping method. - */ - async createShippingMethod( - optionId: string, - data: Record, - config: CreateShippingMethodDto - ): Promise { - return await this.atomicPhase_(async (manager) => { - const option = await this.retrieve(optionId, { - relations: ["requirements"], - }) - - const methodRepo = manager.withRepository(this.methodRepository_) - - if (isDefined(config.cart)) { - await this.validateCartOption(option, config.cart) - } - - const validatedData = await this.providerService_.validateFulfillmentData( - option, - data, - config.cart || {} - ) - - let methodPrice - if (typeof config.price === "number") { - methodPrice = config.price - } else { - methodPrice = await this.getPrice_(option, validatedData, config.cart) - } - - const toCreate: Partial = { - shipping_option_id: option.id, - data: validatedData, - price: methodPrice, - } - - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) - ) { - if (typeof option.includes_tax !== "undefined") { - toCreate.includes_tax = option.includes_tax - } - } - - if (config.order) { - toCreate.order_id = config.order.id - } - - if (config.cart) { - toCreate.cart_id = config.cart.id - } - - if (config.cart_id) { - toCreate.cart_id = config.cart_id - } - - if (config.return_id) { - toCreate.return_id = config.return_id - } - - if (config.order_id) { - toCreate.order_id = config.order_id - } - - if (config.claim_order_id) { - toCreate.claim_order_id = config.claim_order_id - } - - const method = methodRepo.create(toCreate) - - const created = await methodRepo.save(method) - - return (await methodRepo.findOne({ - where: { id: created.id }, - relations: ["shipping_option"], - })) as ShippingMethod - }) - } - - /** - * Checks if a given option id is a valid option for a cart. If it is the - * option is returned with the correct price. Throws when region_ids do not - * match, or when the shipping option requirements are not satisfied. - * @param {object} option - the option object to check - * @param {Cart} cart - the cart object to check against - * @return {ShippingOption} the validated shipping option - */ - async validateCartOption( - option: ShippingOption, - cart: Cart - ): Promise { - if (option.is_return) { - return null - } - - if (cart.region_id !== option.region_id) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "The shipping option is not available in the cart's region" - ) - } - - const amount = option.includes_tax ? (cart.subtotal! + cart.item_tax_total!) : cart.subtotal! - - const requirementResults: boolean[] = option.requirements.map( - (requirement) => { - switch (requirement.type) { - case "max_subtotal": - return requirement.amount > amount - case "min_subtotal": - return requirement.amount <= amount - default: - return true - } - } - ) - - if (requirementResults.some((requirement) => !requirement)) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "The Cart does not satisfy the shipping option's requirements" - ) - } - - option.amount = await this.getPrice_(option, option.data, cart) - - return option - } - - private async validateAndMutatePrice( - option: ShippingOption | CreateShippingOptionInput, - priceInput: ValidatePriceTypeAndAmountInput - ): Promise | CreateShippingOptionInput> { - const option_: - | Omit - | CreateShippingOptionInput = { ...option } - - if (isDefined(priceInput.amount)) { - option_.amount = priceInput.amount - } - - if (isDefined(priceInput.price_type)) { - option_.price_type = await this.validatePriceType_( - priceInput.price_type, - option_ as ShippingOption - ) - - if (priceInput.price_type === ShippingOptionPriceType.CALCULATED) { - option_.amount = null - } - } - - if ( - option_.price_type === ShippingOptionPriceType.FLAT_RATE && - (option_.amount == null || option_.amount < 0) - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Shipping options of type `flat_rate` must have an `amount`" - ) - } - - return option_ - } - - /** - * Creates a new shipping option. Used both for outbound and inbound shipping - * options. The difference is registered by the `is_return` field which - * defaults to false. - * @param {ShippingOption} data - the data to create shipping options - * @return {Promise} the result of the create operation - */ - async create(data: CreateShippingOptionInput): Promise { - return this.atomicPhase_(async (manager) => { - const optionWithValidatedPrice = await this.validateAndMutatePrice(data, { - price_type: data.price_type, - }) - - const optionRepo = manager.withRepository(this.optionRepository_) - const option = optionRepo.create(optionWithValidatedPrice) - - const region = await this.regionService_ - .withTransaction(manager) - .retrieve(option.region_id, { - relations: ["fulfillment_providers"], - }) - - if ( - !region.fulfillment_providers.find( - ({ id }) => id === option.provider_id - ) - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "The fulfillment provider is not available in the provided region" - ) - } - - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) - ) { - if (typeof data.includes_tax !== "undefined") { - option.includes_tax = data.includes_tax - } - } - - const isValid = await this.providerService_.validateOption( - option as ShippingOption - ) - - if (!isValid) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "The fulfillment provider cannot validate the shipping option" - ) - } - - if (isDefined(data.requirements)) { - const acc: ShippingOptionRequirement[] = [] - for (const r of data.requirements) { - const validated = await this.validateRequirement_(r) - - if (acc.find((raw) => raw.type === validated.type)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Only one requirement of each type is allowed" - ) - } - - if ( - acc.find( - (raw) => - (raw.type === "max_subtotal" && - validated.amount > raw.amount) || - (raw.type === "min_subtotal" && validated.amount < raw.amount) - ) - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Max. subtotal must be greater than Min. subtotal" - ) - } - - acc.push(validated) - } - } - - const result = await optionRepo.save(option) - return result - }) - } - - /** - * Validates a shipping option price - * @param {ShippingOptionPriceType} priceType - the price to validate - * @param {ShippingOption} option - the option to validate against - * @return {Promise} the validated price - */ - async validatePriceType_( - priceType: ShippingOptionPriceType, - option: ShippingOption - ): Promise { - if ( - !priceType || - (priceType !== ShippingOptionPriceType.FLAT_RATE && - priceType !== ShippingOptionPriceType.CALCULATED) - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "The price must be of type flat_rate or calculated" - ) - } - - if (priceType === ShippingOptionPriceType.CALCULATED) { - const canCalculate = await this.providerService_.canCalculate({ - provider_id: option.provider_id, - data: option.data, - }) - if (!canCalculate) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "The fulfillment provider cannot calculate prices for this option" - ) - } - } - - return priceType - } - - /** - * Updates a profile. Metadata updates and product updates should use - * dedicated methods, e.g. `setMetadata`, etc. The function - * will throw errors if metadata or product updates are attempted. - * @param {string} optionId - the id of the option. Must be a string that - * can be casted to an ObjectId - * @param {object} update - an object with the update values. - * @return {Promise} resolves to the update result. - */ - async update( - optionId: string, - update: UpdateShippingOptionInput - ): Promise { - return this.atomicPhase_(async (manager) => { - const option = await this.retrieve(optionId, { - relations: ["requirements"], - }) - - if (isDefined(update.metadata)) { - option.metadata = setMetadata(option, update.metadata) - } - - if (update.region_id || update.provider_id || update.data) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Region and Provider cannot be updated after creation" - ) - } - - if (isDefined(update.is_return)) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "is_return cannot be changed after creation" - ) - } - - if (isDefined(update.requirements)) { - const acc: ShippingOptionRequirement[] = [] - for (const r of update.requirements) { - const validated = await this.validateRequirement_(r, optionId) - - if (acc.find((raw) => raw.type === validated.type)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Only one requirement of each type is allowed" - ) - } - - if ( - acc.find( - (raw) => - (raw.type === "max_subtotal" && - validated.amount > raw.amount) || - (raw.type === "min_subtotal" && validated.amount < raw.amount) - ) - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Max. subtotal must be greater than Min. subtotal" - ) - } - - acc.push(validated) - } - - if (option.requirements) { - const accReqs = acc.map((a) => a.id) - const toRemove = option.requirements.filter( - (r) => !accReqs.includes(r.id) - ) - await promiseAll( - toRemove.map(async (req) => { - await this.removeRequirement(req.id) - }) - ) - } - - option.requirements = acc - } - - const optionWithValidatedPrice = await this.validateAndMutatePrice( - option, - { - price_type: update.price_type, - amount: update.amount, - } - ) - - if (isDefined(update.name)) { - optionWithValidatedPrice.name = update.name - } - - if (isDefined(update.admin_only)) { - optionWithValidatedPrice.admin_only = update.admin_only - } - - if (isDefined(update.profile_id)) { - optionWithValidatedPrice.profile_id = update.profile_id - } - - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) - ) { - if (typeof update.includes_tax !== "undefined") { - optionWithValidatedPrice.includes_tax = update.includes_tax - } - } - - const optionRepo = manager.withRepository(this.optionRepository_) - return await optionRepo.save(optionWithValidatedPrice) - }) - } - - /** - * Deletes a profile with a given profile id. - * @param {string} optionId - the id of the profile to delete. Must be - * castable as an ObjectId - * @return {Promise} the result of the delete operation. - */ - async delete(optionId: string): Promise { - return await this.atomicPhase_(async (manager) => { - try { - const option = await this.retrieve(optionId) - - const optionRepo = manager.withRepository(this.optionRepository_) - - return optionRepo.softRemove(option) - } catch (error) { - // Delete is idempotent, but we return a promise to allow then-chaining - return - } - }) - } - - /** - * Adds a requirement to a shipping option. Only 1 requirement of each type - * is allowed. - * @param {string} optionId - the option to add the requirement to. - * @param {ShippingOptionRequirement} requirement - the requirement for the option. - * @return {Promise} the result of update - */ - async addRequirement( - optionId: string, - requirement: ShippingOptionRequirement - ): Promise { - return this.atomicPhase_(async (manager) => { - const option = await this.retrieve(optionId, { - relations: ["requirements"], - }) - const validatedReq = await this.validateRequirement_(requirement) - - if (option.requirements.find((r) => r.type === validatedReq.type)) { - throw new MedusaError( - MedusaError.Types.DUPLICATE_ERROR, - `A requirement with type: ${validatedReq.type} already exists` - ) - } - - option.requirements.push(validatedReq) - - const optionRepo = manager.withRepository(this.optionRepository_) - return optionRepo.save(option) - }) - } - - /** - * Removes a requirement from a shipping option - * @param {string} requirementId - the id of the requirement to remove - * @return {Promise} the result of update - */ - async removeRequirement( - requirementId - ): Promise { - return await this.atomicPhase_(async (manager) => { - const reqRepo = manager.withRepository(this.requirementRepository_) - - const requirement = await reqRepo.findOne({ - where: { id: requirementId }, - }) - - // Delete is idempotent, but we return a promise to allow then-chaining - if (!requirement) { - return Promise.resolve() - } - - return await reqRepo.softRemove(requirement) - }) - } - - /** - * - * @param optionIds ID or IDs of the shipping options to update - * @param profileId Shipping profile ID to update the shipping options with - * @returns updated shipping options - */ - async updateShippingProfile( - optionIds: string | string[], - profileId: string - ): Promise { - return await this.atomicPhase_(async (manager) => { - const optionRepo = manager.withRepository(this.optionRepository_) - - const ids = isString(optionIds) ? [optionIds] : optionIds - - return await optionRepo.upsertShippingProfile(ids, profileId) - }) - } - - /** - * Returns the amount to be paid for a shipping method. Will ask the - * fulfillment provider to calculate the price if the shipping option has the - * price type "calculated". - * @param {ShippingOption} option - the shipping option to retrieve the price - * for. - * @param {ShippingData} data - the shipping data to retrieve the price. - * @param {Cart | Order} cart - the context in which the price should be - * retrieved. - * @return {Promise} the price of the shipping option. - */ - async getPrice_( - option: ShippingOption, - data: Record, - cart: Cart | Order | undefined - ): Promise { - if (option.price_type === "calculated") { - return this.providerService_.calculatePrice(option, data, cart) - } - return option.amount as number - } -} - -export default ShippingOptionService diff --git a/packages/medusa/src/services/shipping-profile.ts b/packages/medusa/src/services/shipping-profile.ts deleted file mode 100644 index f40f6b5ec5..0000000000 --- a/packages/medusa/src/services/shipping-profile.ts +++ /dev/null @@ -1,542 +0,0 @@ -import { - FlagRouter, - MedusaV2Flag, - isDefined, - promiseAll, -} from "@medusajs/utils" -import { MedusaError } from "medusa-core-utils" -import { EntityManager, In } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { - Cart, - CustomShippingOption, - ShippingOption, - ShippingProfile, - ShippingProfileType, -} from "../models" -import { ProductRepository } from "../repositories/product" -import { ShippingProfileRepository } from "../repositories/shipping-profile" -import { FindConfig, Selector } from "../types/common" -import { - CreateShippingProfile, - UpdateShippingProfile, -} from "../types/shipping-profile" -import { buildQuery, isString, setMetadata } from "../utils" -import CustomShippingOptionService from "./custom-shipping-option" -import ProductService from "./product" -import ShippingOptionService from "./shipping-option" - -type InjectedDependencies = { - manager: EntityManager - productService: ProductService - shippingOptionService: ShippingOptionService - customShippingOptionService: CustomShippingOptionService - shippingProfileRepository: typeof ShippingProfileRepository - productRepository: typeof ProductRepository - featureFlagRouter: FlagRouter -} - -/** - * Provides layer to manipulate profiles. - * @constructor - * @implements {BaseService} - */ -class ShippingProfileService extends TransactionBaseService { - protected readonly productService_: ProductService - protected readonly shippingOptionService_: ShippingOptionService - protected readonly customShippingOptionService_: CustomShippingOptionService - // eslint-disable-next-line max-len - protected readonly shippingProfileRepository_: typeof ShippingProfileRepository - protected readonly productRepository_: typeof ProductRepository - protected readonly featureFlagRouter_: FlagRouter - - constructor({ - shippingProfileRepository, - productService, - productRepository, - shippingOptionService, - customShippingOptionService, - featureFlagRouter, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.shippingProfileRepository_ = shippingProfileRepository - this.productService_ = productService - this.productRepository_ = productRepository - this.shippingOptionService_ = shippingOptionService - this.customShippingOptionService_ = customShippingOptionService - this.featureFlagRouter_ = featureFlagRouter - } - - /** - * @param selector - the query object for find - * @param config - the config object for find - * @return the result of the find operation - */ - async list( - selector: Selector = {}, - config: FindConfig = { relations: [], skip: 0, take: 10 } - ): Promise { - const shippingProfileRepo = this.activeManager_.withRepository( - this.shippingProfileRepository_ - ) - - const query = buildQuery, ShippingProfile>( - selector, - config - ) - return shippingProfileRepo.find(query) - } - - async getMapProfileIdsByProductIds( - productIds: string[] - ): Promise> { - const mappedProfiles = new Map() - - if (!productIds?.length) { - return mappedProfiles - } - - const shippingProfiles = await this.shippingProfileRepository_.find({ - select: { - id: true, - products: { - id: true, - }, - }, - where: { - products: { - id: In(productIds), - }, - }, - relations: { - products: true, - }, - }) - - shippingProfiles.forEach((profile) => { - profile.products.forEach((product) => { - mappedProfiles.set(product.id, profile.id) - }) - }) - - return mappedProfiles - } - - /** - * Gets a profile by id. - * Throws in case of DB Error and if profile was not found. - * @param profileId - the id of the profile to get. - * @param options - options opf the query. - * @return {Promise} the profile document. - */ - async retrieve( - profileId: string, - options: FindConfig = {} - ): Promise { - if (!isDefined(profileId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"profileId" must be defined` - ) - } - - const profileRepository = this.activeManager_.withRepository( - this.shippingProfileRepository_ - ) - - const query = buildQuery({ id: profileId }, options) - - const profile = await profileRepository.findOne(query) - - if (!profile) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Profile with id: ${profileId} was not found` - ) - } - - return profile - } - - async retrieveForProducts( - productIds: string | string[] - ): Promise<{ [product_id: string]: ShippingProfile[] }> { - if (!isDefined(productIds)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"productIds" must be defined` - ) - } - - productIds = isString(productIds) ? [productIds] : productIds - - const profileRepository = this.activeManager_.withRepository( - this.shippingProfileRepository_ - ) - - const productProfilesMap = await profileRepository.findByProducts( - productIds - ) - - if (!Object.keys(productProfilesMap)?.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `No Profile found for products with id: ${productIds.join(", ")}` - ) - } - - return productProfilesMap - } - - async retrieveDefault(): Promise { - const profileRepository = this.activeManager_.withRepository( - this.shippingProfileRepository_ - ) - - const profile = await profileRepository.findOne({ - where: { type: ShippingProfileType.DEFAULT }, - }) - - return profile - } - - /** - * Creates a default shipping profile, if this does not already exist. - * @return {Promise} the shipping profile - */ - async createDefault(): Promise { - return await this.atomicPhase_(async (manager) => { - let profile = await this.retrieveDefault() - - if (!profile) { - const profileRepository = manager.withRepository( - this.shippingProfileRepository_ - ) - - const toCreate = { - type: ShippingProfileType.DEFAULT, - name: "Default Shipping Profile", - } - - const created = profileRepository.create(toCreate) - - profile = await profileRepository.save(created) - } - - return profile - }) - } - - /** - * Retrieves the default gift card profile - * @return the shipping profile for gift cards - */ - async retrieveGiftCardDefault(): Promise { - const profileRepository = this.activeManager_.withRepository( - this.shippingProfileRepository_ - ) - - const giftCardProfile = await profileRepository.findOne({ - where: { type: ShippingProfileType.GIFT_CARD }, - }) - - return giftCardProfile - } - - /** - * Creates a default shipping profile, for gift cards if unless it already - * exists. - * @return the shipping profile - */ - async createGiftCardDefault(): Promise { - return await this.atomicPhase_(async (manager) => { - let profile = await this.retrieveGiftCardDefault() - - if (!profile) { - const profileRepository = manager.withRepository( - this.shippingProfileRepository_ - ) - - const created = profileRepository.create({ - type: ShippingProfileType.GIFT_CARD, - name: "Gift Card Profile", - }) - - profile = await profileRepository.save(created) - } - - return profile - }) - } - - /** - * Creates a new shipping profile. - * @param profile - the shipping profile to create from - * @return the result of the create operation - */ - async create(profile: CreateShippingProfile): Promise { - return await this.atomicPhase_(async (manager) => { - const profileRepository = manager.withRepository( - this.shippingProfileRepository_ - ) - - if (profile["products"] || profile["shipping_options"]) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Please add products and shipping_options after creating Shipping Profiles" - ) - } - - const { metadata, ...rest } = profile - - const created = profileRepository.create(rest) - - if (metadata) { - created.metadata = setMetadata(created, metadata) - } - - const result = await profileRepository.save(created) - return result - }) - } - - /** - * Updates a profile. Metadata updates and product updates should use - * dedicated methods, e.g. `setMetadata`, `addProduct`, etc. The function - * will throw errors if metadata or product updates are attempted. - * @param profileId - the id of the profile. Must be a string that - * can be casted to an ObjectId - * @param update - an object with the update values. - * @return resolves to the update result. - */ - async update( - profileId: string, - update: UpdateShippingProfile - ): Promise { - return await this.atomicPhase_(async (manager) => { - const profileRepository = manager.withRepository( - this.shippingProfileRepository_ - ) - - const profile = await this.retrieve(profileId) - - const { metadata, products, shipping_options, ...rest } = update - - if (products) { - await this.addProduct(profile.id, products) - } - - if (shipping_options) { - await this.addShippingOption(profile.id, shipping_options) - } - - if (metadata) { - profile.metadata = setMetadata(profile, metadata) - } - - for (const [key, value] of Object.entries(rest)) { - profile[key] = value - } - - return await profileRepository.save(profile) - }) - } - - /** - * Deletes a profile with a given profile id. - * @param profileId - the id of the profile to delete. Must be - * castable as an ObjectId - * @return the result of the delete operation. - */ - async delete(profileId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const profileRepo = manager.withRepository( - this.shippingProfileRepository_ - ) - - // Should not fail, if profile does not exist, since delete is idempotent - const profile = await profileRepo.findOne({ where: { id: profileId } }) - - if (!profile) { - return Promise.resolve() - } - - await profileRepo.softRemove(profile) - - return Promise.resolve() - }) - } - - /** - * @deprecated use {@link addProducts} instead - */ - async addProduct( - profileId: string, - productId: string | string[] - ): Promise { - return await this.addProducts(profileId, productId) - } - - /** - * Adds a product or an array of products to the profile. - * @param profileId - the profile to add the products to. - * @param productId - the ID of the product or multiple products to add. - * @return the result of update - */ - async addProducts( - profileId: string, - productId: string | string[] - ): Promise { - return await this.atomicPhase_(async (manager) => { - const productServiceTx = this.productService_.withTransaction(manager) - - await productServiceTx.updateShippingProfile( - isString(productId) ? [productId] : productId, - profileId - ) - - return await this.retrieve(profileId) - }) - } - - /** - * Removes a product or an array of products from the profile. - * @param profileId - the profile to add the products to. - * @param productId - the ID of the product or multiple products to add. - * @return the result of update - */ - async removeProducts( - profileId: string | null, - productId: string | string[] - ): Promise { - return await this.atomicPhase_(async (manager) => { - const productServiceTx = this.productService_.withTransaction(manager) - - await productServiceTx.updateShippingProfile( - isString(productId) ? [productId] : productId, - null - ) - }) - } - - /** - * Adds a shipping option to the profile. The shipping option can be used to - * fulfill the products in the products field. - * @param profileId - the profile to apply the shipping option to - * @param optionId - the ID of the option or multiple options to add to the profile - * @return the result of the model update operation - */ - async addShippingOption( - profileId: string, - optionId: string | string[] - ): Promise { - return await this.atomicPhase_(async (manager) => { - const shippingOptionServiceTx = - this.shippingOptionService_.withTransaction(manager) - - await shippingOptionServiceTx.updateShippingProfile( - isString(optionId) ? [optionId] : optionId, - profileId - ) - - return await this.retrieve(profileId, { - relations: ["products.profiles", "shipping_options.profile"], - }) - }) - } - - /** - * Finds all the shipping profiles that cover the products in a cart, and - * validates all options that are available for the cart. - * @param cart - the cart object to find shipping options for - * @return a list of the available shipping options - */ - async fetchCartOptions(cart): Promise { - return await this.atomicPhase_(async (manager) => { - const profileIds = await this.getProfilesInCart(cart) - - const selector: Selector = { - profile_id: profileIds, - admin_only: false, - } - - const customShippingOptions = await this.customShippingOptionService_ - .withTransaction(manager) - .list( - { - cart_id: cart.id, - }, - { select: ["id", "shipping_option_id", "price"] } - ) - - const hasCustomShippingOptions = customShippingOptions?.length - // if there are custom shipping options associated with the cart, use those - if (hasCustomShippingOptions) { - selector.id = customShippingOptions.map((cso) => cso.shipping_option_id) - } - - const rawOpts = await this.shippingOptionService_ - .withTransaction(manager) - .list(selector, { - relations: ["requirements", "profile"], - }) - - // if there are custom shipping options associated with the cart, return cart shipping options with custom price - if (hasCustomShippingOptions) { - const customShippingOptionsMap = new Map() - - customShippingOptions.forEach((option) => { - customShippingOptionsMap.set(option.shipping_option_id, option) - }) - - return rawOpts.map((so) => { - const customOption = customShippingOptionsMap.get(so.id) - - return { - ...so, - amount: customOption?.price, - } - }) as ShippingOption[] - } - - return ( - await promiseAll( - rawOpts.map(async (so) => { - return await this.shippingOptionService_ - .withTransaction(manager) - .validateCartOption(so, cart) - .catch(() => null) // if validateCartOption fails it means the option is not valid - }) - ) - ).filter((option): option is ShippingOption => !!option) - }) - } - - /** - * Returns a list of all the productIds in the cart. - * @param cart - the cart to extract products from - * @return a list of product ids - */ - protected async getProfilesInCart(cart: Cart): Promise { - let profileIds = new Set() - - if (this.featureFlagRouter_.isFeatureEnabled(MedusaV2Flag.key)) { - const productShippinProfileMap = await this.getMapProfileIdsByProductIds( - cart.items.map((item) => item.variant?.product_id) - ) - profileIds = new Set([...productShippinProfileMap.values()]) - } else { - cart.items.forEach((item) => { - if (item.variant?.product) { - profileIds.add(item.variant.product.profile_id) - } - }) - } - - return [...profileIds] - } -} - -export default ShippingProfileService diff --git a/packages/medusa/src/services/shipping-tax-rate.ts b/packages/medusa/src/services/shipping-tax-rate.ts deleted file mode 100644 index f6df5666a7..0000000000 --- a/packages/medusa/src/services/shipping-tax-rate.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ShippingTaxRate } from "../models" -import { ShippingTaxRateRepository } from "../repositories/shipping-tax-rate" -import { FindConfig } from "../types/common" -import { FilterableShippingTaxRateProps } from "../types/shipping-tax-rate" -import { TransactionBaseService } from "../interfaces" -import { buildQuery } from "../utils" - -class ShippingTaxRateService extends TransactionBaseService { - // eslint-disable-next-line max-len - protected readonly shippingTaxRateRepository_: typeof ShippingTaxRateRepository - - constructor({ shippingTaxRateRepository }) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.shippingTaxRateRepository_ = shippingTaxRateRepository - } - - /** - * Lists Shipping Tax Rates given a certain query. - * @param selector - the query object for find - * @param config - query config object for variant retrieval - * @return the result of the find operation - */ - async list( - selector: FilterableShippingTaxRateProps, - config: FindConfig = { relations: [], skip: 0, take: 20 } - ): Promise { - const sTaxRateRepo = this.activeManager_.withRepository( - this.shippingTaxRateRepository_ - ) - - const query = buildQuery(selector, config) - - return await sTaxRateRepo.find(query) - } -} - -export default ShippingTaxRateService diff --git a/packages/medusa/src/services/store.ts b/packages/medusa/src/services/store.ts deleted file mode 100644 index afbd48f1f1..0000000000 --- a/packages/medusa/src/services/store.ts +++ /dev/null @@ -1,274 +0,0 @@ -import { MedusaError } from "medusa-core-utils" -import { EntityManager, IsNull, Not } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { Currency, Store } from "../models" -import { CurrencyRepository } from "../repositories/currency" -import { StoreRepository } from "../repositories/store" -import { FindConfig } from "../types/common" -import { UpdateStoreInput } from "../types/store" -import { buildQuery, setMetadata } from "../utils" -import { currencies } from "../utils/currencies" -import EventBusService from "./event-bus" -import { promiseAll } from "@medusajs/utils" - -type InjectedDependencies = { - manager: EntityManager - storeRepository: typeof StoreRepository - currencyRepository: typeof CurrencyRepository - eventBusService: EventBusService -} - -/** - * Provides layer to manipulate store settings. - */ -class StoreService extends TransactionBaseService { - protected readonly storeRepository_: typeof StoreRepository - protected readonly currencyRepository_: typeof CurrencyRepository - protected readonly eventBus_: EventBusService - - constructor({ - storeRepository, - currencyRepository, - eventBusService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.storeRepository_ = storeRepository - this.currencyRepository_ = currencyRepository - this.eventBus_ = eventBusService - } - - /** - * Creates a store if it doesn't already exist. - * @return The store. - */ - async create(): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const storeRepository = transactionManager.withRepository( - this.storeRepository_ - ) - const currencyRepository = transactionManager.withRepository( - this.currencyRepository_ - ) - - let store = await this.retrieve().catch(() => void 0) - if (store) { - return store - } - - const newStore = storeRepository.create() - // Add default currency (USD) to store currencies - const usd = await currencyRepository.findOne({ - where: { - code: "usd", - }, - }) - - if (usd) { - newStore.currencies = [usd] - } - - store = await storeRepository.save(newStore) - return store - } - ) - } - - /** - * Retrieve the store settings. There is always a maximum of one store. - * @param config The config object from which the query will be built - * @return the store - */ - async retrieve(config: FindConfig = {}): Promise { - const storeRepo = this.activeManager_.withRepository(this.storeRepository_) - const query = buildQuery( - { - id: Not(IsNull()), - }, - config - ) - const stores = await storeRepo.find(query) - - if (!stores.length) { - throw new MedusaError(MedusaError.Types.NOT_FOUND, "Store does not exist") - } - - return stores[0] - } - - protected getDefaultCurrency_(code: string): Partial { - const currencyObject = currencies[code.toUpperCase()] - - return { - code: currencyObject.code.toLowerCase(), - symbol: currencyObject.symbol, - symbol_native: currencyObject.symbol_native, - name: currencyObject.name, - } - } - - /** - * Updates a store - * @param data - an object with the update values. - * @return resolves to the update result. - */ - async update(data: UpdateStoreInput): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const storeRepository = transactionManager.withRepository( - this.storeRepository_ - ) - const currencyRepository = transactionManager.withRepository( - this.currencyRepository_ - ) - - const { - metadata, - default_currency_code, - currencies: storeCurrencies, - ...rest - } = data - - const store = await this.retrieve({ relations: ["currencies"] }) - - if (metadata) { - store.metadata = setMetadata(store, metadata) - } - - if (storeCurrencies) { - const defaultCurr = - default_currency_code ?? store.default_currency_code - const hasDefCurrency = storeCurrencies.find( - (c) => c.toLowerCase() === defaultCurr.toLowerCase() - ) - - // throw if we are trying to remove a currency from store currently used as default - if (!hasDefCurrency) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `You are not allowed to remove default currency from store currencies without replacing it as well` - ) - } - - store.currencies = await promiseAll( - storeCurrencies.map(async (curr) => { - const currency = await currencyRepository.findOne({ - where: { code: curr.toLowerCase() }, - }) - - if (!currency) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Currency with code ${curr} does not exist` - ) - } - - return currency - }) - ) - } - - if (default_currency_code) { - const hasDefCurrency = store.currencies.find( - (c) => c.code.toLowerCase() === default_currency_code.toLowerCase() - ) - - if (!hasDefCurrency) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Store does not have currency: ${default_currency_code}` - ) - } - - const curr = (await currencyRepository.findOne({ - where: { - code: default_currency_code.toLowerCase(), - }, - })) as Currency - - store.default_currency = curr - store.default_currency_code = curr.code - } - - for (const [key, value] of Object.entries(rest)) { - store[key] = value - } - - return await storeRepository.save(store) - } - ) - } - - /** - * Add a currency to the store - * @param code - 3 character ISO currency code - * @return result after update - */ - async addCurrency(code: string): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const storeRepo = transactionManager.withRepository( - this.storeRepository_ - ) - const currencyRepository = transactionManager.withRepository( - this.currencyRepository_ - ) - - const curr = await currencyRepository.findOne({ - where: { code: code.toLowerCase() }, - }) - - if (!curr) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Currency ${code} not found` - ) - } - - const store = await this.retrieve({ relations: ["currencies"] }) - - const doesStoreInclCurrency = store.currencies - .map((c) => c.code.toLowerCase()) - .includes(curr.code.toLowerCase()) - if (doesStoreInclCurrency) { - throw new MedusaError( - MedusaError.Types.DUPLICATE_ERROR, - `Currency already added` - ) - } - - store.currencies = [...store.currencies, curr] - return await storeRepo.save(store) - } - ) - } - - /** - * Removes a currency from the store - * @param code - 3 character ISO currency code - * @return result after update - */ - async removeCurrency(code: string): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const storeRepo = transactionManager.withRepository( - this.storeRepository_ - ) - const store = await this.retrieve({ relations: ["currencies"] }) - const doesCurrencyExists = store.currencies.some( - (c) => c.code === code.toLowerCase() - ) - if (!doesCurrencyExists) { - return store - } - - store.currencies = store.currencies.filter((c) => c.code !== code) - return await storeRepo.save(store) - } - ) - } -} - -export default StoreService diff --git a/packages/medusa/src/services/strategy-resolver.ts b/packages/medusa/src/services/strategy-resolver.ts deleted file mode 100644 index 7cc6b4fbe4..0000000000 --- a/packages/medusa/src/services/strategy-resolver.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { AbstractBatchJobStrategy, TransactionBaseService } from "../interfaces" -import { EntityManager } from "typeorm" -import { MedusaError } from "medusa-core-utils" - -type InjectedDependencies = { - manager: EntityManager - [key: string]: unknown -} - -export default class StrategyResolver extends TransactionBaseService { - constructor(protected readonly container: InjectedDependencies) { - super(container) - } - - resolveBatchJobByType(type: string): AbstractBatchJobStrategy { - let resolved: AbstractBatchJobStrategy - try { - resolved = this.container[`batchType_${type}`] as AbstractBatchJobStrategy - } catch (e) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Unable to find a BatchJob strategy with the type ${type}` - ) - } - return resolved - } -} diff --git a/packages/medusa/src/services/swap.ts b/packages/medusa/src/services/swap.ts deleted file mode 100644 index d61223fb42..0000000000 --- a/packages/medusa/src/services/swap.ts +++ /dev/null @@ -1,1269 +0,0 @@ -import { - Cart, - CartType, - FulfillmentItem, - FulfillmentStatus, - LineItem, - Order, - PaymentSessionStatus, - PaymentStatus, - ReturnItem, - ReturnStatus, - Swap, - SwapFulfillmentStatus, - SwapPaymentStatus, -} from "../models" -import { - CartService, - CustomShippingOptionService, - EventBusService, - FulfillmentService, - LineItemAdjustmentService, - LineItemService, - OrderService, - PaymentProviderService, - ProductVariantInventoryService, - ReturnService, - ShippingOptionService, - TotalsService, -} from "./index" -import { EntityManager, In } from "typeorm" -import { FindConfig, Selector, WithRequiredProperty } from "../types/common" -import { isDefined, MedusaError } from "medusa-core-utils" -import { buildQuery, setMetadata, validateId } from "../utils" - -import { CreateShipmentConfig } from "../types/fulfillment" -import { OrdersReturnItem } from "../types/orders" -import { SwapRepository } from "../repositories/swap" -import { TransactionBaseService } from "../interfaces" -import { promiseAll } from "@medusajs/utils" - -type InjectedProps = { - manager: EntityManager - - swapRepository: typeof SwapRepository - - cartService: CartService - orderService: OrderService - returnService: ReturnService - totalsService: TotalsService - eventBusService: EventBusService - lineItemService: LineItemService - productVariantInventoryService: ProductVariantInventoryService - fulfillmentService: FulfillmentService - shippingOptionService: ShippingOptionService - paymentProviderService: PaymentProviderService - lineItemAdjustmentService: LineItemAdjustmentService - customShippingOptionService: CustomShippingOptionService -} - -/** - * Handles swaps - */ -class SwapService extends TransactionBaseService { - static Events = { - CREATED: "swap.created", - RECEIVED: "swap.received", - SHIPMENT_CREATED: "swap.shipment_created", - PAYMENT_COMPLETED: "swap.payment_completed", - PAYMENT_CAPTURED: "swap.payment_captured", - PAYMENT_CAPTURE_FAILED: "swap.payment_capture_failed", - PROCESS_REFUND_FAILED: "swap.process_refund_failed", - REFUND_PROCESSED: "swap.refund_processed", - FULFILLMENT_CREATED: "swap.fulfillment_created", - } - - protected readonly swapRepository_: typeof SwapRepository - - protected readonly cartService_: CartService - protected readonly eventBus_: EventBusService - protected readonly orderService_: OrderService - protected readonly returnService_: ReturnService - protected readonly totalsService_: TotalsService - protected readonly lineItemService_: LineItemService - protected readonly fulfillmentService_: FulfillmentService - protected readonly shippingOptionService_: ShippingOptionService - protected readonly paymentProviderService_: PaymentProviderService - protected readonly lineItemAdjustmentService_: LineItemAdjustmentService - protected readonly customShippingOptionService_: CustomShippingOptionService - // eslint-disable-next-line max-len - protected readonly productVariantInventoryService_: ProductVariantInventoryService - - constructor({ - swapRepository, - eventBusService, - cartService, - totalsService, - returnService, - lineItemService, - paymentProviderService, - shippingOptionService, - fulfillmentService, - orderService, - productVariantInventoryService, - customShippingOptionService, - lineItemAdjustmentService, - }: InjectedProps) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.swapRepository_ = swapRepository - this.totalsService_ = totalsService - this.lineItemService_ = lineItemService - this.returnService_ = returnService - this.paymentProviderService_ = paymentProviderService - this.cartService_ = cartService - this.fulfillmentService_ = fulfillmentService - this.orderService_ = orderService - this.shippingOptionService_ = shippingOptionService - this.productVariantInventoryService_ = productVariantInventoryService - this.eventBus_ = eventBusService - this.customShippingOptionService_ = customShippingOptionService - this.lineItemAdjustmentService_ = lineItemAdjustmentService - } - - /** - * Transform find config object for retrieval. - * - * @param config parsed swap find config - * @return transformed find swap config - */ - protected transformQueryForCart( - config: Omit, "select"> & { select?: string[] } - ): Omit, "select"> & { select?: string[] } & { - cartSelects: FindConfig["select"] - cartRelations: FindConfig["relations"] - } { - let { select, relations } = config - - let cartSelects: FindConfig["select"] - let cartRelations: FindConfig["relations"] - - if (isDefined(relations) && relations.includes("cart")) { - const [swapRelations, cartRels] = relations.reduce( - (acc: string[][], next) => { - if (next === "cart") { - return acc - } - - if (next.startsWith("cart.")) { - const [, ...rel] = next.split(".") - acc[1].push(rel.join(".")) - } else { - acc[0].push(next) - } - - return acc - }, - [[], []] - ) - - relations = swapRelations - cartRelations = cartRels - - let foundCartId = false - if (isDefined(select)) { - const [swapSelects, cartSels] = select.reduce( - (acc, next) => { - if (next.startsWith("cart.")) { - const [, ...rel] = next.split(".") - acc[1].push(rel.join(".")) - } else { - if (next === "cart_id") { - foundCartId = true - } - acc[0].push(next) - } - - return acc - }, - [[] as string[], [] as string[]] - ) - - select = foundCartId ? swapSelects : [...swapSelects, "cart_id"] - ;(cartSelects as string[]) = cartSels - } - } - - return { - ...config, - relations, - select, - cartSelects, - cartRelations, - } - } - - /** - * Retrieves a swap with the given id. - * - * @param swapId - the id of the swap to retrieve - * @param config - the configuration to retrieve the swap - * @return the swap - */ - async retrieve( - swapId: string, - config: Omit, "select"> & { select?: string[] } = {} - ): Promise { - if (!isDefined(swapId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"swapId" must be defined` - ) - } - - const swapRepo = this.activeManager_.withRepository(this.swapRepository_) - - const { cartSelects, cartRelations, ...newConfig } = - this.transformQueryForCart(config) - - const query = buildQuery({ id: swapId }, newConfig) - - const swap = await swapRepo.findOne(query) - - if (!swap) { - throw new MedusaError(MedusaError.Types.NOT_FOUND, "Swap was not found") - } - - if (cartRelations || cartSelects) { - swap.cart = await this.cartService_ - .withTransaction(this.activeManager_) - .retrieve(swap.cart_id, { - select: cartSelects, - relations: cartRelations, - }) - } - - return swap - } - - /** - * Retrieves a swap based on its associated cart id - * - * @param cartId - the cart id that the swap's cart has - * @param relations - the relations to retrieve swap - * @return the swap - */ - async retrieveByCartId( - cartId: string, - relations: FindConfig["relations"] = [] - ): Promise { - const swapRepo = this.activeManager_.withRepository(this.swapRepository_) - - const swap = await swapRepo.findOne({ - where: { - cart_id: cartId, - }, - relations, - }) - - if (!swap) { - throw new MedusaError(MedusaError.Types.NOT_FOUND, "Swap was not found") - } - - return swap - } - - /** - * List swaps. - * - * @param selector - the query object for find - * @param config - the configuration used to find the objects. contains relations, skip, and take. - * @return the result of the find operation - */ - async list( - selector: Selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise { - const [swaps] = await this.listAndCount(selector, config) - - return swaps - } - - /** - * List swaps. - * - * @param selector - the query object for find - * @param config - the configuration used to find the objects. contains relations, skip, and take. - * @return the result of the find operation - */ - async listAndCount( - selector: Selector, - config: FindConfig = { - skip: 0, - take: 50, - order: { created_at: "DESC" }, - } - ): Promise<[Swap[], number]> { - const swapRepo = this.activeManager_.withRepository(this.swapRepository_) - const query = buildQuery(selector, config) - query.relationLoadStrategy = "query" - - return await swapRepo.findAndCount(query) - } - - /** - * Creates a swap from an order, with given return items, additional items - * and an optional return shipping method. - * - * @param order - the order to base the swap off - * @param returnItems - the items to return in the swap - * @param additionalItems - the items to send to the customer - * @param returnShipping - an optional shipping method for returning the returnItems - * @param custom - contains relevant custom information. This object may - * include no_notification which will disable sending notification when creating - * swap. If set, it overrules the attribute inherited from the order - * @return the newly created swap - */ - async create( - order: Order, - returnItems: WithRequiredProperty, "item_id">[], - additionalItems?: Pick[], - returnShipping?: { option_id: string; price?: number }, - custom: { - no_notification?: boolean - idempotency_key?: string - allow_backorder?: boolean - location_id?: string - } = { no_notification: undefined } - ): Promise { - const { no_notification, ...rest } = custom - return await this.atomicPhase_(async (manager) => { - if (order.payment_status !== PaymentStatus.CAPTURED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot swap an order that has not been captured" - ) - } - - if (order.fulfillment_status === FulfillmentStatus.NOT_FULFILLED) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot swap an order that has not been fulfilled" - ) - } - - const areReturnItemsValid = await this.areReturnItemsValid(returnItems) - - if (!areReturnItemsValid) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Cannot create a swap on a canceled item.` - ) - } - - let newItems: LineItem[] = [] - - if (additionalItems) { - newItems = await promiseAll( - additionalItems.map(async ({ variant_id, quantity }) => { - if (variant_id === null) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "You must include a variant when creating additional items on a swap" - ) - } - return this.lineItemService_.withTransaction(manager).generate( - { variantId: variant_id, quantity }, - { - region_id: order.region_id, - cart: order.cart, - } - ) - }) - ) - } - - const evaluatedNoNotification = - no_notification !== undefined ? no_notification : order.no_notification - - const swapRepo = manager.withRepository(this.swapRepository_) - const created = swapRepo.create({ - ...rest, - fulfillment_status: SwapFulfillmentStatus.NOT_FULFILLED, - payment_status: SwapPaymentStatus.NOT_PAID, - order_id: order.id, - additional_items: newItems, - no_notification: evaluatedNoNotification, - }) - - const result = await swapRepo.save(created) - - await this.returnService_.withTransaction(manager).create({ - swap_id: result.id, - order_id: order.id, - items: returnItems as OrdersReturnItem[], - shipping_method: returnShipping, - no_notification: evaluatedNoNotification, - location_id: custom.location_id, - }) - - await this.eventBus_ - .withTransaction(manager) - .emit(SwapService.Events.CREATED, { - id: result.id, - no_notification: evaluatedNoNotification, - }) - - return result - }) - } - - /** - * Process difference for the requested swap. - * - * @param swapId id of a swap being processed - * @return processed swap - */ - async processDifference(swapId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const swap = await this.retrieve(swapId, { - relations: ["payment", "order", "order.payments"], - }) - - if (swap.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Canceled swap cannot be processed" - ) - } - - if (!swap.confirmed_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot process a swap that hasn't been confirmed by the customer" - ) - } - - const swapRepo = manager.withRepository(this.swapRepository_) - if (swap.difference_due < 0) { - if (swap.payment_status === "difference_refunded") { - return swap - } - - try { - await this.paymentProviderService_ - .withTransaction(manager) - .refundPayment( - swap.order.payments, - -1 * swap.difference_due, - "swap" - ) - } catch (err) { - swap.payment_status = SwapPaymentStatus.REQUIRES_ACTION - const result = await swapRepo.save(swap) - - await this.eventBus_ - .withTransaction(manager) - .emit(SwapService.Events.PROCESS_REFUND_FAILED, { - id: result.id, - no_notification: swap.no_notification, - }) - - return result - } - - swap.payment_status = SwapPaymentStatus.DIFFERENCE_REFUNDED - - const result = await swapRepo.save(swap) - - await this.eventBus_ - .withTransaction(manager) - .emit(SwapService.Events.REFUND_PROCESSED, { - id: result.id, - no_notification: swap.no_notification, - }) - - return result - } else if (swap.difference_due === 0) { - if (swap.payment_status === SwapPaymentStatus.DIFFERENCE_REFUNDED) { - return swap - } - - swap.payment_status = SwapPaymentStatus.DIFFERENCE_REFUNDED - - const result = await swapRepo.save(swap) - - await this.eventBus_ - .withTransaction(manager) - .emit(SwapService.Events.REFUND_PROCESSED, { - id: result.id, - no_notification: swap.no_notification, - }) - - return result - } - - try { - if (swap.payment_status === SwapPaymentStatus.CAPTURED) { - return swap - } - - await this.paymentProviderService_ - .withTransaction(manager) - .capturePayment(swap.payment) - } catch (err) { - swap.payment_status = SwapPaymentStatus.REQUIRES_ACTION - const result = await swapRepo.save(swap) - - await this.eventBus_ - .withTransaction(manager) - .emit(SwapService.Events.PAYMENT_CAPTURE_FAILED, { - id: swap.id, - no_notification: swap.no_notification, - }) - - return result - } - - swap.payment_status = SwapPaymentStatus.CAPTURED - - const result = await swapRepo.save(swap) - - await this.eventBus_ - .withTransaction(manager) - .emit(SwapService.Events.PAYMENT_CAPTURED, { - id: result.id, - no_notification: swap.no_notification, - }) - - return result - }) - } - - /** - * Update the swap record. - * - * @param swapId id of a swap to update - * @param update new data - * @return updated swap record - */ - async update(swapId: string, update: Partial): Promise { - return await this.atomicPhase_(async (manager) => { - const swap = await this.retrieve(swapId) - - if ("metadata" in update) { - swap.metadata = setMetadata(swap, update.metadata!) - } - - if ("no_notification" in update) { - swap.no_notification = update.no_notification! - } - - if ("shipping_address" in update) { - // TODO: Check this - calling method that doesn't exist - // also it seems that update swap isn't call anywhere - // await this.updateShippingAddress_(swap, update.shipping_address) - } - - const swapRepo = manager.withRepository(this.swapRepository_) - return await swapRepo.save(swap) - }) - } - - /** - * Creates a cart from the given swap. The cart can be used to pay - * for differences associated with the swap. The swap represented by the - * swapId must belong to the order. Fails if there is already a cart on the - * swap. - * - * @param swapId - the id of the swap to create the cart from - * @param customShippingOptions - the shipping options - * @return the swap with its cart_id prop set to the id of the new cart. - */ - async createCart( - swapId: string, - customShippingOptions: { option_id: string; price: number }[] = [], - context: { sales_channel_id?: string } = {} - ): Promise { - return await this.atomicPhase_(async (manager) => { - const swapRepo = manager.withRepository(this.swapRepository_) - - const swap = await this.retrieve(swapId, { - relations: [ - "order.items.variant.product.profiles", - "order.swaps", - "order.swaps.additional_items", - "order.discounts", - "order.discounts.rule", - "order.claims", - "order.claims.additional_items", - "additional_items", - "additional_items.variant", - "return_order", - "return_order.items", - "return_order.shipping_method", - "return_order.shipping_method.shipping_option", - "return_order.shipping_method.tax_lines", - ], - }) - - if (swap.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Canceled swap cannot be used to create a cart" - ) - } - - if (swap.cart_id) { - throw new MedusaError( - MedusaError.Types.DUPLICATE_ERROR, - "A cart has already been created for the swap" - ) - } - - const order = swap.order - - // filter out free shipping discounts - const discounts = - order?.discounts?.filter(({ rule }) => rule.type !== "free_shipping") || - undefined - - let cart = await this.cartService_.withTransaction(manager).create({ - discounts, - email: order.email, - billing_address_id: order.billing_address_id, - shipping_address_id: order.shipping_address_id, - region_id: order.region_id, - customer_id: order.customer_id, - sales_channel_id: - context.sales_channel_id ?? order.sales_channel_id ?? undefined, - type: CartType.SWAP, - metadata: { - swap_id: swap.id, - parent_order_id: order.id, - }, - }) - - const customShippingOptionServiceTx = - this.customShippingOptionService_.withTransaction(manager) - for (const customShippingOption of customShippingOptions) { - await customShippingOptionServiceTx.create({ - cart_id: cart.id, - shipping_option_id: customShippingOption.option_id, - price: customShippingOption.price, - }) - } - - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - const lineItemAdjustmentServiceTx = - this.lineItemAdjustmentService_.withTransaction(manager) - - await promiseAll( - swap.additional_items.map( - async (item) => - await lineItemServiceTx.update(item.id, { - cart_id: cart.id, - }) - ) - ) - - cart = await this.cartService_ - .withTransaction(manager) - .retrieve(cart.id, { - relations: [ - "items", - "items.variant", - "region", - "discounts", - "discounts.rule", - ], - }) - - await promiseAll( - cart.items.map(async (item) => { - // we generate adjustments in case the cart has any discounts that should be applied to the additional items - await lineItemAdjustmentServiceTx.createAdjustmentForLineItem( - cart, - item - ) - }) - ) - - // If the swap has a return shipping method the price has to be added to - // the cart. - if (swap.return_order && swap.return_order.shipping_method) { - await this.lineItemService_.withTransaction(manager).create({ - cart_id: cart.id, - title: "Return shipping", - quantity: 1, - has_shipping: true, - allow_discounts: false, - unit_price: swap.return_order.shipping_method.price, - is_return: true, - tax_lines: swap.return_order.shipping_method.tax_lines.map((tl) => { - return lineItemServiceTx.createTaxLine({ - name: tl.name, - code: tl.code, - rate: tl.rate, - metadata: tl.metadata, - }) - }), - }) - } - - await this.lineItemService_ - .withTransaction(manager) - .createReturnLines(swap.return_order.id, cart.id) - - swap.cart_id = cart.id - - return await swapRepo.save(swap) - }) - } - - /** - * Register a cart completion - * - * @param swapId - The id of the swap - * @return swap related to the cart - */ - async registerCartCompletion(swapId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const swap = await this.retrieve(swapId, { - select: [ - "id", - "order_id", - "no_notification", - "allow_backorder", - "canceled_at", - "confirmed_at", - "cart_id", - ], - }) - - // If we already registered the cart completion we just return - if (swap.confirmed_at) { - return swap - } - - if (swap.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cart related to canceled swap cannot be completed" - ) - } - - const cart = await this.cartService_ - .withTransaction(manager) - .retrieveWithTotals(swap.cart_id, { - relations: ["payment"], - }) - - const { payment } = cart - - const items = cart.items - - const total = cart.total! - - if (total > 0) { - if (!payment) { - throw new MedusaError( - MedusaError.Types.INVALID_ARGUMENT, - "Cart does not contain a payment" - ) - } - - const paymentStatus = await this.paymentProviderService_ - .withTransaction(manager) - .getStatus(payment) - - // If payment status is not authorized, we throw - if ( - paymentStatus !== PaymentSessionStatus.AUTHORIZED && - // @ts-ignore TODO: check why this is not in the enum - paymentStatus !== "succeeded" - ) { - throw new MedusaError( - MedusaError.Types.INVALID_ARGUMENT, - "Payment method is not authorized" - ) - } - - await this.paymentProviderService_ - .withTransaction(manager) - .updatePayment(payment.id, { - swap_id: swapId, - order_id: swap.order_id, - }) - - await promiseAll( - items.map(async (item) => { - if (item.variant_id) { - await this.productVariantInventoryService_.reserveQuantity( - item.variant_id, - item.quantity, - { - lineItemId: item.id, - salesChannelId: cart.sales_channel_id, - } - ) - } - }) - ) - } - - swap.difference_due = total - swap.shipping_address_id = cart.shipping_address_id - // TODO: Due to cascade insert we have to remove the tax_lines that have been added by the cart decorate totals. - // Is the cascade insert really used? Also, is it really necessary to pass the entire entities when creating or updating? - // We normally should only pass what is needed? - swap.shipping_methods = cart.shipping_methods.map((method) => { - ;(method.tax_lines as any) = undefined - return method - }) - swap.confirmed_at = new Date() - swap.payment_status = - total === 0 ? SwapPaymentStatus.CONFIRMED : SwapPaymentStatus.AWAITING - - const swapRepo = manager.withRepository(this.swapRepository_) - const result = await swapRepo.save(swap) - - const shippingOptionServiceTx = - this.shippingOptionService_.withTransaction(manager) - - for (const method of cart.shipping_methods) { - await shippingOptionServiceTx.updateShippingMethod(method.id, { - swap_id: result.id, - }) - } - - await this.eventBus_ - .withTransaction(manager) - .emit(SwapService.Events.PAYMENT_COMPLETED, { - id: swap.id, - no_notification: swap.no_notification, - }) - - await this.cartService_ - .withTransaction(manager) - .update(cart.id, { completed_at: new Date() }) - - return result - }) - } - - /** - * Cancels a given swap if possible. A swap can only be canceled if all - * related returns, fulfillments, and payments have been canceled. If a swap - * is associated with a refund, it cannot be canceled. - * - * @param swapId - the id of the swap to cancel. - * @return the canceled swap. - */ - async cancel(swapId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const swapRepo = manager.withRepository(this.swapRepository_) - - const swap = await this.retrieve(swapId, { - relations: ["payment", "fulfillments", "return_order"], - }) - - if ( - swap.payment_status === SwapPaymentStatus.DIFFERENCE_REFUNDED || - swap.payment_status === SwapPaymentStatus.PARTIALLY_REFUNDED || - swap.payment_status === SwapPaymentStatus.REFUNDED - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Swap with a refund cannot be canceled" - ) - } - - if (swap.fulfillments) { - for (const f of swap.fulfillments) { - if (!f.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "All fulfillments must be canceled before the swap can be canceled" - ) - } - } - } - - if ( - swap.return_order && - swap.return_order.status !== ReturnStatus.CANCELED - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Return must be canceled before the swap can be canceled" - ) - } - - swap.payment_status = SwapPaymentStatus.CANCELED - swap.fulfillment_status = SwapFulfillmentStatus.CANCELED - swap.canceled_at = new Date() - - if (swap.payment) { - await this.paymentProviderService_ - .withTransaction(manager) - .cancelPayment(swap.payment) - } - - return await swapRepo.save(swap) - }) - } - - /** - * Fulfills the additional items associated with the swap. Will call the - * fulfillment providers associated with the shipping methods. - * - * @param {string} swapId - the id of the swap to fulfill, - * @param {object} config - optional configurations, includes optional metadata to attach to the shipment, and a no_notification flag. - * @return {Promise} the updated swap with new status and fulfillments. - */ - async createFulfillment( - swapId: string, - config: CreateShipmentConfig = { - metadata: {}, - no_notification: undefined, - } - ): Promise { - return await this.atomicPhase_(async (manager) => { - const { metadata, no_notification } = config - const swapRepo = manager.withRepository(this.swapRepository_) - - const swap = await this.retrieve(swapId, { - relations: [ - "payment", - "shipping_address", - "additional_items.tax_lines", - "additional_items.variant.product.profiles", - "shipping_methods", - "shipping_methods.shipping_option", - "shipping_methods.tax_lines", - "order", - "order.region", - "order.billing_address", - "order.discounts", - "order.discounts.rule", - "order.payments", - ], - }) - const order = swap.order - - if (swap.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Canceled swap cannot be fulfilled" - ) - } - - if ( - swap.fulfillment_status !== "not_fulfilled" && - swap.fulfillment_status !== "canceled" - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "The swap was already fulfilled" - ) - } - - if (!swap.shipping_methods?.length) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Cannot fulfill an swap that doesn't have shipping methods" - ) - } - - const evaluatedNoNotification = - no_notification !== undefined ? no_notification : swap.no_notification - - swap.fulfillments = await this.fulfillmentService_ - .withTransaction(manager) - .createFulfillment( - // @ts-ignore TODO: check - claim_items,refund_amount,type: these fields are missing - { - ...swap, - payments: swap.payment ? [swap.payment] : order.payments, - email: order.email, - discounts: order.discounts, - currency_code: order.currency_code, - tax_rate: order.tax_rate, - region_id: order.region_id, - region: order.region, - display_id: order.display_id, - billing_address: order.billing_address, - items: swap.additional_items, - shipping_methods: swap.shipping_methods, - is_swap: true, - no_notification: evaluatedNoNotification, - }, - swap.additional_items.map((i) => ({ - item_id: i.id, - quantity: i.quantity, - })), - { swap_id: swapId, metadata, location_id: config.location_id } - ) - - let successfullyFulfilled: FulfillmentItem[] = [] - for (const f of swap.fulfillments) { - successfullyFulfilled = successfullyFulfilled.concat(f.items) - } - - swap.fulfillment_status = SwapFulfillmentStatus.FULFILLED - - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - - // Update all line items to reflect fulfillment - for (const item of swap.additional_items) { - const fulfillmentItem = successfullyFulfilled.find( - (f) => item.id === f.item_id - ) - - if (fulfillmentItem) { - const fulfilledQuantity = - (item.fulfilled_quantity || 0) + fulfillmentItem.quantity - - // Update the fulfilled quantity - await lineItemServiceTx.update(item.id, { - fulfilled_quantity: fulfilledQuantity, - }) - - if (item.quantity !== fulfilledQuantity) { - swap.fulfillment_status = SwapFulfillmentStatus.REQUIRES_ACTION - } - } else { - if (item.quantity !== item.fulfilled_quantity) { - swap.fulfillment_status = SwapFulfillmentStatus.REQUIRES_ACTION - } - } - } - - const result = await swapRepo.save(swap) - - await this.eventBus_.withTransaction(manager).emit( - SwapService.Events.FULFILLMENT_CREATED, - - { - id: swapId, - fulfillment_id: result.id, - no_notification: evaluatedNoNotification, - } - ) - - return result - }) - } - - /** - * Cancels a fulfillment (if related to a swap) - * - * @param fulfillmentId - the ID of the fulfillment to cancel - * @return updated swap - */ - async cancelFulfillment(fulfillmentId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const swapRepo = manager.withRepository(this.swapRepository_) - const canceled = await this.fulfillmentService_ - .withTransaction(manager) - .cancelFulfillment(fulfillmentId) - - if (!canceled.swap_id) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Fufillment not related to a swap` - ) - } - - const swap = await this.retrieve(canceled.swap_id) - - swap.fulfillment_status = SwapFulfillmentStatus.CANCELED - - return await swapRepo.save(swap) - }) - } - - /** - * Marks a fulfillment as shipped and attaches tracking numbers. - * - * @param swapId - the id of the swap that has been shipped. - * @param fulfillmentId - the id of the specific fulfillment that has been shipped - * @param trackingLinks - the tracking numbers associated with the shipment - * @param config - optional configurations, includes optional metadata to attach to the shipment, and a noNotification flag. - * @return the updated swap with new fulfillments and status. - */ - async createShipment( - swapId: string, - fulfillmentId: string, - trackingLinks?: { tracking_number: string }[], - config: CreateShipmentConfig = { - metadata: {}, - no_notification: undefined, - } - ): Promise { - return await this.atomicPhase_(async (manager) => { - const { metadata, no_notification } = config - const swapRepo = manager.withRepository(this.swapRepository_) - - const swap = await this.retrieve(swapId, { - relations: ["additional_items"], - }) - - if (swap.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Canceled swap cannot be fulfilled as shipped" - ) - } - const evaluatedNoNotification = - no_notification !== undefined ? no_notification : swap.no_notification - - // Update the fulfillment to register - const shipment = await this.fulfillmentService_ - .withTransaction(manager) - .createShipment(fulfillmentId, trackingLinks, { - metadata, - no_notification: evaluatedNoNotification, - }) - - swap.fulfillment_status = SwapFulfillmentStatus.SHIPPED - - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - - // Go through all the additional items in the swap - for (const i of swap.additional_items) { - const shipped = shipment.items.find((si) => si.item_id === i.id) - if (shipped) { - const shippedQty = (i.shipped_quantity || 0) + shipped.quantity - await lineItemServiceTx.update(i.id, { - shipped_quantity: shippedQty, - }) - - if (shippedQty !== i.quantity) { - swap.fulfillment_status = SwapFulfillmentStatus.PARTIALLY_SHIPPED - } - } else { - if (i.shipped_quantity !== i.quantity) { - swap.fulfillment_status = SwapFulfillmentStatus.PARTIALLY_SHIPPED - } - } - } - - const result = await swapRepo.save(swap) - - await this.eventBus_ - .withTransaction(manager) - .emit(SwapService.Events.SHIPMENT_CREATED, { - id: swapId, - fulfillment_id: shipment.id, - no_notification: swap.no_notification, - }) - - return result - }) - } - - /** - * Dedicated method to delete metadata for a swap. - * - * @param swapId - the order to delete metadata from. - * @param key - key for metadata field - * @return resolves to the updated result. - */ - async deleteMetadata(swapId: string, key: string): Promise { - return await this.atomicPhase_( - async (transactionManager: EntityManager) => { - const validatedId = validateId(swapId) - - const swapRepo = transactionManager.withRepository(this.swapRepository_) - - const swap = await swapRepo.findOne({ where: { id: validatedId } }) - - if (!swap) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Swap with id: ${validatedId} was not found` - ) - } - - const updated = swap.metadata || {} - delete updated[key] - swap.metadata = updated - - const updatedSwap = await swapRepo.save(swap) - - await this.eventBus_ - .withTransaction(transactionManager) - .emit(CartService.Events.UPDATED, updatedSwap) - - return updatedSwap - } - ) - } - - /** - * Registers the swap return items as received so that they cannot be used - * as a part of other swaps/returns. - * - * @param id - the id of the order with the swap. - * @return the resulting order - */ - async registerReceived(id): Promise { - return await this.atomicPhase_(async (manager) => { - const swap = await this.retrieve(id, { - relations: ["return_order", "return_order.items"], - }) - - if (swap.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Canceled swap cannot be registered as received" - ) - } - - if (swap.return_order.status !== "received") { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Swap is not received" - ) - } - - const result = await this.retrieve(id) - - await this.eventBus_ - .withTransaction(manager) - .emit(SwapService.Events.RECEIVED, { - id: id, - order_id: result.order_id, - no_notification: swap.no_notification, - }) - - return result - }) - } - - protected async areReturnItemsValid( - returnItems: WithRequiredProperty, "item_id">[] - ): Promise { - const manager = this.transactionManager_ ?? this.manager_ - - const returnItemsEntities = await this.lineItemService_ - .withTransaction(manager) - .list( - { - id: In(returnItems.map((r) => r.item_id)), - }, - { - relations: ["order", "swap", "claim_order"], - } - ) - - const hasCanceledItem = returnItemsEntities.some((item) => { - return ( - item.order?.canceled_at || - item.swap?.canceled_at || - item.claim_order?.canceled_at - ) - }) - - return !hasCanceledItem - } -} - -export default SwapService diff --git a/packages/medusa/src/services/system-payment-provider.ts b/packages/medusa/src/services/system-payment-provider.ts deleted file mode 100644 index 8a30e31ab1..0000000000 --- a/packages/medusa/src/services/system-payment-provider.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { TransactionBaseService } from "../interfaces/transaction-base-service" - -class SystemProviderService extends TransactionBaseService { - static identifier = "system" - - constructor(_) { - super(_) - } - - async createPayment(_): Promise> { - return {} - } - - async getStatus(_): Promise { - return "authorized" - } - - async getPaymentData(_): Promise> { - return {} - } - - async authorizePayment(_): Promise> { - return { data: {}, status: "authorized" } - } - - async updatePaymentData(_): Promise> { - return {} - } - - async updatePayment(_): Promise> { - return {} - } - - async deletePayment(_): Promise> { - return {} - } - - async capturePayment(_): Promise> { - return {} - } - - async refundPayment(_): Promise> { - return {} - } - - async cancelPayment(_): Promise> { - return {} - } -} - -export default SystemProviderService diff --git a/packages/medusa/src/services/system-tax.ts b/packages/medusa/src/services/system-tax.ts deleted file mode 100644 index 6bf2437215..0000000000 --- a/packages/medusa/src/services/system-tax.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - AbstractTaxService, - ItemTaxCalculationLine, - ShippingTaxCalculationLine, - TaxCalculationContext, -} from "../interfaces/tax-service" -import { ProviderTaxLine } from "../types/tax-service" - -class SystemTaxService extends AbstractTaxService { - static identifier = "system" - - constructor(...args: any[]) { - // @ts-ignore - // eslint-disable-next-line prefer-rest-params - super(...arguments) - } - - async getTaxLines( - itemLines: ItemTaxCalculationLine[], - shippingLines: ShippingTaxCalculationLine[], - context: TaxCalculationContext // eslint-disable-line - ): Promise { - let taxLines: ProviderTaxLine[] = itemLines.flatMap((l) => { - return l.rates.map((r) => ({ - rate: r.rate || 0, - name: r.name, - code: r.code, - item_id: l.item.id, - })) - }) - - taxLines = taxLines.concat( - shippingLines.flatMap((l) => { - return l.rates.map((r) => ({ - rate: r.rate || 0, - name: r.name, - code: r.code, - shipping_method_id: l.shipping_method.id, - })) - }) - ) - - return taxLines - } -} - -export default SystemTaxService diff --git a/packages/medusa/src/services/tax-provider.ts b/packages/medusa/src/services/tax-provider.ts deleted file mode 100644 index 519ee81988..0000000000 --- a/packages/medusa/src/services/tax-provider.ts +++ /dev/null @@ -1,508 +0,0 @@ -import { AwilixContainer } from "awilix" -import { MedusaError } from "medusa-core-utils" -import { In } from "typeorm" - -import { ICacheService, IEventBusService } from "@medusajs/types" -import { - ITaxService, - ItemTaxCalculationLine, - TaxCalculationContext, - TransactionBaseService, -} from "../interfaces" -import { - Cart, - LineItem, - LineItemTaxLine, - Region, - ShippingMethod, - ShippingMethodTaxLine, - TaxProvider, -} from "../models" -import { LineItemTaxLineRepository } from "../repositories/line-item-tax-line" -import { ShippingMethodTaxLineRepository } from "../repositories/shipping-method-tax-line" -import { TaxProviderRepository } from "../repositories/tax-provider" -import { isCart } from "../types/cart" -import { TaxLinesMaps, TaxServiceRate } from "../types/tax-service" -import TaxRateService from "./tax-rate" -import { promiseAll } from "@medusajs/utils" - -type RegionDetails = { - id: string - tax_rate: number | null -} - -/** - * Finds tax providers and assists in tax related operations. - */ -class TaxProviderService extends TransactionBaseService { - protected readonly container_: AwilixContainer - protected readonly cacheService_: ICacheService - protected readonly taxRateService_: TaxRateService - protected readonly taxLineRepo_: typeof LineItemTaxLineRepository - protected readonly smTaxLineRepo_: typeof ShippingMethodTaxLineRepository - protected readonly taxProviderRepo_: typeof TaxProviderRepository - protected readonly eventBus_: IEventBusService - - constructor(container: AwilixContainer) { - super(container) - - this.container_ = container - this.cacheService_ = container["cacheService"] - this.taxLineRepo_ = container["lineItemTaxLineRepository"] - this.smTaxLineRepo_ = container["shippingMethodTaxLineRepository"] - this.taxRateService_ = container["taxRateService"] - this.eventBus_ = container["eventBusService"] - this.taxProviderRepo_ = container["taxProviderRepository"] - } - - async list(): Promise { - const tpRepo = this.activeManager_.withRepository(this.taxProviderRepo_) - return tpRepo.find({}) - } - - /** - * Retrieves the relevant tax provider for the given region. - * @param region - the region to get tax provider for. - * @return the region specific tax provider - */ - retrieveProvider(region: Region): ITaxService { - let provider: ITaxService - if (region.tax_provider_id) { - try { - provider = this.container_[`tp_${region.tax_provider_id}`] - } catch (e) { - // noop - } - } else { - provider = this.container_["systemTaxService"] - } - - if (!provider!) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Could not find a tax provider with id: ${region.tax_provider_id}` - ) - } - - return provider - } - - async clearLineItemsTaxLines(itemIds: string[]): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const taxLineRepo = transactionManager.withRepository(this.taxLineRepo_) - - await taxLineRepo.delete({ item_id: In(itemIds) }) - }) - } - - async clearTaxLines(cartId: string): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const taxLineRepo = transactionManager.withRepository(this.taxLineRepo_) - const shippingTaxRepo = transactionManager.withRepository( - this.smTaxLineRepo_ - ) - - await promiseAll([ - taxLineRepo.deleteForCart(cartId), - shippingTaxRepo.deleteForCart(cartId), - ]) - }) - } - - /** - * Persists the tax lines relevant for an order to the database. - * @param cartOrLineItems - the cart or line items to create tax lines for - * @param calculationContext - the calculation context to get tax lines by - * @return the newly created tax lines - */ - async createTaxLines( - cartOrLineItems: Cart | LineItem[], - calculationContext: TaxCalculationContext - ): Promise<(ShippingMethodTaxLine | LineItemTaxLine)[]> { - return await this.atomicPhase_(async (transactionManager) => { - let taxLines: (ShippingMethodTaxLine | LineItemTaxLine)[] = [] - if (isCart(cartOrLineItems)) { - taxLines = await this.getTaxLines( - cartOrLineItems.items, - calculationContext - ) - } else { - taxLines = await this.getTaxLines(cartOrLineItems, calculationContext) - } - - const itemTaxLineRepo = transactionManager.withRepository( - this.taxLineRepo_ - ) - const shippingTaxLineRepo = transactionManager.withRepository( - this.smTaxLineRepo_ - ) - - const { shipping, lineItems } = taxLines.reduce<{ - shipping: ShippingMethodTaxLine[] - lineItems: LineItemTaxLine[] - }>( - (acc, tl) => { - if ("item_id" in tl) { - acc.lineItems.push(tl) - } else { - acc.shipping.push(tl) - } - - return acc - }, - { shipping: [], lineItems: [] } - ) - - return ( - await promiseAll([ - itemTaxLineRepo.upsertLines(lineItems), - shippingTaxLineRepo.upsertLines(shipping), - ]) - ).flat() - }) - } - - /** - * Persists the tax lines relevant for a shipping method to the database. Used - * for return shipping methods. - * @param shippingMethod - the shipping method to create tax lines for - * @param calculationContext - the calculation context to get tax lines by - * @return the newly created tax lines - */ - async createShippingTaxLines( - shippingMethod: ShippingMethod, - calculationContext: TaxCalculationContext - ): Promise<(ShippingMethodTaxLine | LineItemTaxLine)[]> { - return await this.atomicPhase_(async (transactionManager) => { - const taxLines = await this.getShippingTaxLines( - shippingMethod, - calculationContext - ) - return await transactionManager.save(taxLines) - }) - } - - /** - * Gets the relevant tax lines for a shipping method. Note: this method - * doesn't persist the tax lines. Use createShippingTaxLines if you wish to - * persist the tax lines to the DB layer. - * @param shippingMethod - the shipping method to get tax lines for - * @param calculationContext - the calculation context to get tax lines by - * @return the computed tax lines - */ - async getShippingTaxLines( - shippingMethod: ShippingMethod, - calculationContext: TaxCalculationContext - ): Promise { - const calculationLines = [ - { - shipping_method: shippingMethod, - rates: await this.getRegionRatesForShipping( - shippingMethod.shipping_option_id, - calculationContext.region - ), - }, - ] - - const taxProvider = this.retrieveProvider(calculationContext.region) - const providerLines = await taxProvider.getTaxLines( - [], - calculationLines, - calculationContext - ) - - const smTaxLineRepo = this.activeManager_.withRepository( - this.smTaxLineRepo_ - ) - - // .create only creates entities nothing is persisted in DB - return providerLines.map((pl) => { - if (!("shipping_method_id" in pl)) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Expected only shipping method tax lines" - ) - } - - return smTaxLineRepo.create({ - shipping_method_id: pl.shipping_method_id, - rate: pl.rate, - name: pl.name, - code: pl.code, - metadata: pl.metadata, - }) - }) - } - - /** - * Gets the relevant tax lines for an order or cart. If an order is provided - * the order's tax lines will be returned. If a cart is provided the tax lines - * will be computed from the tax rules and potentially a 3rd party tax plugin. - * Note: this method doesn't persist the tax lines. Use createTaxLines if you - * wish to persist the tax lines to the DB layer. - * @param lineItems - the cart or order to get tax lines for - * @param calculationContext - the calculation context to get tax lines by - * @return the computed tax lines - */ - async getTaxLines( - lineItems: LineItem[], - calculationContext: TaxCalculationContext - ): Promise<(ShippingMethodTaxLine | LineItemTaxLine)[]> { - const productIds = [ - ...new Set( - lineItems.map((item) => item?.variant?.product_id).filter((p) => p) - ), - ] - - const productRatesMap = await this.getRegionRatesForProduct( - productIds, - calculationContext.region - ) - - const calculationLines = lineItems.map((item) => { - if (item.is_return) { - return null - } - - if (item.variant?.product_id) { - return { - item: item, - rates: productRatesMap.get(item.variant?.product_id) ?? [], - } - } - - /* - * If the line item is custom and therefore not associated with a - * product we assume no taxes - we should consider adding rate overrides - * to custom lines at some point - */ - return { - item: item, - rates: [], - } - }) - - const shippingCalculationLines = await promiseAll( - calculationContext.shipping_methods.map(async (sm) => { - return { - shipping_method: sm, - rates: await this.getRegionRatesForShipping( - sm.shipping_option_id, - calculationContext.region - ), - } - }) - ) - - const taxProvider = this.retrieveProvider(calculationContext.region) - const providerLines = await taxProvider.getTaxLines( - calculationLines.filter((v) => v !== null) as ItemTaxCalculationLine[], - shippingCalculationLines, - calculationContext - ) - - const liTaxLineRepo = this.activeManager_.withRepository(this.taxLineRepo_) - const smTaxLineRepo = this.activeManager_.withRepository( - this.smTaxLineRepo_ - ) - - // .create only creates entities nothing is persisted in DB - return providerLines.map((pl) => { - if ("shipping_method_id" in pl) { - return smTaxLineRepo.create({ - shipping_method_id: pl.shipping_method_id, - rate: pl.rate, - name: pl.name, - code: pl.code, - metadata: pl.metadata, - }) - } - - if (!("item_id" in pl)) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Tax Provider returned invalid tax lines" - ) - } - - return liTaxLineRepo.create({ - item_id: pl.item_id, - rate: pl.rate, - name: pl.name, - code: pl.code, - metadata: pl.metadata, - }) - }) - } - - /** - * Return a map of tax lines for line items and shipping methods - * @param items - * @param calculationContext - * @protected - */ - async getTaxLinesMap( - items: LineItem[], - calculationContext: TaxCalculationContext - ): Promise { - const lineItemsTaxLinesMap = {} - const shippingMethodsTaxLinesMap = {} - - const taxLines = await this.getTaxLines(items, calculationContext) - - taxLines.forEach((taxLine) => { - if ("item_id" in taxLine) { - const itemTaxLines = lineItemsTaxLinesMap[taxLine.item_id] ?? [] - itemTaxLines.push(taxLine) - lineItemsTaxLinesMap[taxLine.item_id] = itemTaxLines - } - if ("shipping_method_id" in taxLine) { - const shippingMethodTaxLines = - shippingMethodsTaxLinesMap[taxLine.shipping_method_id] ?? [] - shippingMethodTaxLines.push(taxLine) - shippingMethodsTaxLinesMap[taxLine.shipping_method_id] = - shippingMethodTaxLines - } - }) - - return { - lineItemsTaxLines: lineItemsTaxLinesMap, - shippingMethodsTaxLines: shippingMethodsTaxLinesMap, - } - } - - /** - * Gets the tax rates configured for a shipping option. The rates are cached - * between calls. - * @param optionId - the option id of the shipping method. - * @param regionDetails - the region to get configured rates for. - * @return the tax rates configured for the shipping option. - */ - async getRegionRatesForShipping( - optionId: string, - regionDetails: RegionDetails - ): Promise { - const cacheKey = this.getCacheKey(optionId, regionDetails.id) - const cacheHit = await this.cacheService_.get(cacheKey) - if (cacheHit) { - return cacheHit - } - - let toReturn: TaxServiceRate[] = [] - const optionRates = await this.taxRateService_ - .withTransaction(this.activeManager_) - .listByShippingOption(optionId) - - if (optionRates.length > 0) { - toReturn = optionRates.map((pr) => { - return { - rate: pr.rate, - name: pr.name, - code: pr.code, - } - }) - } - - if (toReturn.length === 0) { - toReturn = [ - { - rate: regionDetails.tax_rate, - name: "default", - code: "default", - }, - ] - } - - await this.cacheService_.set(cacheKey, toReturn) - - return toReturn - } - - /** - * Gets the tax rates configured for a product. The rates are cached between - * calls. - * @param productIds - * @param region - the region to get configured rates for. - * @return the tax rates configured for the shipping option. A map by product id - */ - async getRegionRatesForProduct( - productIds: string | string[], - region: RegionDetails - ): Promise> { - productIds = Array.isArray(productIds) ? productIds : [productIds] - - const nonCachedProductIds: string[] = [] - - const cacheKeysMap = new Map( - productIds.map((id) => [id, this.getCacheKey(id, region.id)]) - ) - - const productRatesMapResult = new Map() - await promiseAll( - [...cacheKeysMap].map(async ([id, cacheKey]) => { - const cacheHit = await this.cacheService_.get( - cacheKey - ) - - if (!cacheHit) { - nonCachedProductIds.push(id) - return - } - - productRatesMapResult.set(id, cacheHit) - }) - ) - - // All products rates are cached so we can return early - if (!nonCachedProductIds.length) { - return productRatesMapResult - } - - await promiseAll( - nonCachedProductIds.map(async (id) => { - const rates = await this.taxRateService_ - .withTransaction(this.activeManager_) - .listByProduct(id, { - region_id: region.id, - }) - - const toReturn: TaxServiceRate[] = rates.length - ? rates - : [ - { - rate: region.tax_rate, - name: "default", - code: "default", - }, - ] - - await this.cacheService_.set(cacheKeysMap.get(id)!, toReturn) - productRatesMapResult.set(id, toReturn) - }) - ) - - return productRatesMapResult - } - - /** - * The cache key to get cache hits by. - * @param id - the entity id to cache - * @param regionId - the region id to cache - * @return the cache key to use for the id set - */ - private getCacheKey(id: string, regionId: string): string { - return `txrtcache:${id}:${regionId}` - } - - async registerInstalledProviders(providers: string[]): Promise { - const model = this.activeManager_.withRepository(this.taxProviderRepo_) - await model.update({}, { is_installed: false }) - - for (const p of providers) { - const n = model.create({ id: p, is_installed: true }) - await model.save(n) - } - } -} - -export default TaxProviderService diff --git a/packages/medusa/src/services/tax-rate.ts b/packages/medusa/src/services/tax-rate.ts deleted file mode 100644 index 8488742c5e..0000000000 --- a/packages/medusa/src/services/tax-rate.ts +++ /dev/null @@ -1,360 +0,0 @@ -import { promiseAll } from "@medusajs/utils" -import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager, ILike, In } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import { - ProductTaxRate, - ProductTypeTaxRate, - ShippingTaxRate, - TaxRate, -} from "../models" -import { TaxRateRepository } from "../repositories/tax-rate" -import ProductService from "../services/product" -import ProductTypeService from "../services/product-type" -import ShippingOptionService from "../services/shipping-option" -import { FindConfig } from "../types/common" -import { - CreateTaxRateInput, - FilterableTaxRateProps, - TaxRateListByConfig, - UpdateTaxRateInput, -} from "../types/tax-rate" -import { buildQuery, PostgresError } from "../utils" - -class TaxRateService extends TransactionBaseService { - protected readonly productService_: ProductService - protected readonly productTypeService_: ProductTypeService - protected readonly shippingOptionService_: ShippingOptionService - protected readonly taxRateRepository_: typeof TaxRateRepository - - constructor({ - productService, - productTypeService, - shippingOptionService, - taxRateRepository, - }) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.taxRateRepository_ = taxRateRepository - this.productService_ = productService - this.productTypeService_ = productTypeService - this.shippingOptionService_ = shippingOptionService - } - - async list( - selector: FilterableTaxRateProps, - config: FindConfig = {} - ): Promise { - const taxRateRepo = this.activeManager_.withRepository( - this.taxRateRepository_ - ) - - let q: string | undefined - - if (selector.q) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - - if (q) { - query.where["name"] = ILike(`%${q}%`) - } - - return await taxRateRepo.findWithResolution(query) - } - - async listAndCount( - selector: FilterableTaxRateProps, - config: FindConfig = {} - ): Promise<[TaxRate[], number]> { - const taxRateRepo = this.activeManager_.withRepository( - this.taxRateRepository_ - ) - - let q: string | undefined - - if (selector.q) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - - if (q) { - query.where["name"] = ILike(`%${q}%`) - } - - return await taxRateRepo.findAndCountWithResolution(query) - } - - async retrieve( - taxRateId: string, - config: FindConfig = {} - ): Promise { - if (!isDefined(taxRateId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"taxRateId" must be defined` - ) - } - - const taxRateRepo = this.activeManager_.withRepository( - this.taxRateRepository_ - ) - const query = buildQuery({ id: taxRateId }, config) - - const taxRate = await taxRateRepo.findOneWithResolution(query) - if (!taxRate) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `TaxRate with ${taxRateId} was not found` - ) - } - - return taxRate - } - - async create(data: CreateTaxRateInput): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const taxRateRepo = manager.withRepository(this.taxRateRepository_) - - if (typeof data.region_id === "undefined") { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "TaxRates must belong to a Region" - ) - } - - const taxRate = taxRateRepo.create(data) - return await taxRateRepo.save(taxRate) - }) - } - - async update(id: string, data: UpdateTaxRateInput): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const taxRateRepo = manager.withRepository(this.taxRateRepository_) - const taxRate = await this.retrieve(id) - - for (const [k, v] of Object.entries(data)) { - if (isDefined(v)) { - taxRate[k] = v - } - } - - return await taxRateRepo.save(taxRate) - }) - } - - async delete(id: string | string[]): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const taxRateRepo = manager.withRepository(this.taxRateRepository_) - const query = buildQuery({ id }) - if (Array.isArray(id)) { - await taxRateRepo.delete({ id: In(id) }) - } else { - await taxRateRepo.delete({ id: id }) - } - }) - } - - async removeFromProduct( - id: string, - productIds: string | string[] - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const taxRateRepo = manager.withRepository(this.taxRateRepository_) - - let ids: string[] - if (typeof productIds === "string") { - ids = [productIds] - } else { - ids = productIds - } - - await taxRateRepo.removeFromProduct(id, ids) - }) - } - - async removeFromProductType( - id: string, - typeIds: string | string[] - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const taxRateRepo = manager.withRepository(this.taxRateRepository_) - - let ids: string[] - if (typeof typeIds === "string") { - ids = [typeIds] - } else { - ids = typeIds - } - - await taxRateRepo.removeFromProductType(id, ids) - }) - } - - async removeFromShippingOption( - id: string, - optionIds: string | string[] - ): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const taxRateRepo = manager.withRepository(this.taxRateRepository_) - - let ids: string[] - if (typeof optionIds === "string") { - ids = [optionIds] - } else { - ids = optionIds - } - - await taxRateRepo.removeFromShippingOption(id, ids) - }) - } - - async addToProduct( - id: string, - productIds: string | string[], - replace = false - ): Promise { - let ids: string[] - if (typeof productIds === "string") { - ids = [productIds] - } else { - ids = productIds - } - - const result = await this.atomicPhase_( - async (manager: EntityManager) => { - const taxRateRepo = manager.withRepository(this.taxRateRepository_) - return await taxRateRepo.addToProduct(id, ids, replace) - }, - // eslint-disable-next-line - async (err: any) => { - if (err.code === PostgresError.FOREIGN_KEY_ERROR) { - // A foreign key constraint failed meaning some thing doesn't exist - // either it is a product or the tax rate itself. Using promiseAll - // will try to retrieve all of the resources and will fail when - // something is not found. - await promiseAll([ - this.retrieve(id, { select: ["id"] }), - ...ids.map(async (pId) => - this.productService_.retrieve(pId, { select: ["id"] }) - ), - ]) - } - } - ) - return result - } - - async addToProductType( - id: string, - productTypeIds: string | string[], - replace = false - ): Promise { - let ids: string[] - if (typeof productTypeIds === "string") { - ids = [productTypeIds] - } else { - ids = productTypeIds - } - - return await this.atomicPhase_( - async (manager: EntityManager) => { - const taxRateRepo = manager.withRepository(this.taxRateRepository_) - return await taxRateRepo.addToProductType(id, ids, replace) - }, - // eslint-disable-next-line - async (err: any) => { - if (err.code === PostgresError.FOREIGN_KEY_ERROR) { - // A foreign key constraint failed meaning some thing doesn't exist - // either it is a product or the tax rate itself. Using promiseAll - // will try to retrieve all of the resources and will fail when - // something is not found. - await promiseAll([ - this.retrieve(id, { - select: ["id"], - }) as Promise, - ...ids.map( - async (pId) => - this.productTypeService_.retrieve(pId, { - select: ["id"], - }) as Promise - ), - ]) - } - } - ) - } - - async addToShippingOption( - id: string, - optionIds: string | string[], - replace = false - ): Promise { - let ids: string[] - if (typeof optionIds === "string") { - ids = [optionIds] - } else { - ids = optionIds - } - - return await this.atomicPhase_( - async (manager: EntityManager) => { - const taxRateRepo = manager.withRepository(this.taxRateRepository_) - const taxRate = await this.retrieve(id, { select: ["id", "region_id"] }) - const options = await this.shippingOptionService_.list( - { id: ids }, - { select: ["id", "region_id"] } - ) - for (const o of options) { - if (o.region_id !== taxRate.region_id) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Shipping Option and Tax Rate must belong to the same Region to be associated. Shipping Option with id: ${o.id} belongs to Region with id: ${o.region_id} and Tax Rate with id: ${taxRate.id} belongs to Region with id: ${taxRate.region_id}` - ) - } - } - return await taxRateRepo.addToShippingOption(id, ids, replace) - }, - // eslint-disable-next-line - async (err: any) => { - if (err.code === PostgresError.FOREIGN_KEY_ERROR) { - // A foreign key constraint failed meaning some thing doesn't exist - // either it is a product or the tax rate itself. Using promiseAll - // will try to retrieve all of the resources and will fail when - // something is not found. - await promiseAll([ - this.retrieve(id, { select: ["id"] }), - ...ids.map(async (sId) => - this.shippingOptionService_.retrieve(sId, { select: ["id"] }) - ), - ]) - } - } - ) - } - - async listByProduct( - productId: string, - config: TaxRateListByConfig - ): Promise { - // Check both ProductTaxRate + ProductTypeTaxRate - const taxRateRepo = this.activeManager_.withRepository( - this.taxRateRepository_ - ) - return await taxRateRepo.listByProduct(productId, config) - } - - async listByShippingOption(shippingOptionId: string): Promise { - const taxRateRepo = this.activeManager_.withRepository( - this.taxRateRepository_ - ) - return await taxRateRepo.listByShippingOption(shippingOptionId) - } -} - -export default TaxRateService diff --git a/packages/medusa/src/services/token.ts b/packages/medusa/src/services/token.ts deleted file mode 100644 index 193b8c6e5d..0000000000 --- a/packages/medusa/src/services/token.ts +++ /dev/null @@ -1,47 +0,0 @@ -import jwt, { Jwt, JwtPayload, SignOptions, VerifyOptions } from "jsonwebtoken" -import { ConfigModule } from "../types/global" -import formatRegistrationName from "../utils/format-registration-name" -import { resolve } from "path" -import { MedusaError } from "medusa-core-utils" - -type InjectedDependencies = { - configModule: ConfigModule -} - -class TokenService { - static RESOLUTION_KEY = formatRegistrationName(resolve(__dirname, __filename)) - - protected readonly configModule_: ConfigModule - - constructor({ configModule }: InjectedDependencies) { - this.configModule_ = configModule - } - - verifyToken( - token: string, - options?: VerifyOptions - ): Jwt | JwtPayload | string { - const { jwt_secret } = this.configModule_.projectConfig - if (jwt_secret) { - return jwt.verify(token, jwt_secret, options) - } - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Please configure jwt_secret" - ) - } - - signToken(data: string | Buffer | object, options?: SignOptions): string { - const { jwt_secret } = this.configModule_.projectConfig - if (jwt_secret) { - return jwt.sign(data, jwt_secret, options) - } else { - throw new MedusaError( - MedusaError.Types.INVALID_ARGUMENT, - "Please configure a jwt token" - ) - } - } -} - -export default TokenService diff --git a/packages/medusa/src/services/totals.ts b/packages/medusa/src/services/totals.ts deleted file mode 100644 index 20e2617aa9..0000000000 --- a/packages/medusa/src/services/totals.ts +++ /dev/null @@ -1,1063 +0,0 @@ -import { isDefined, MedusaError } from "@medusajs/utils" -import { EntityManager } from "typeorm" -import { - ITaxCalculationStrategy, - TaxCalculationContext, - TransactionBaseService, -} from "../interfaces" -import { - Cart, - ClaimOrder, - Discount, - DiscountRuleType, - LineItem, - LineItemTaxLine, - Order, - ShippingMethod, - ShippingMethodTaxLine, - Swap, -} from "../models" -import { isCart } from "../types/cart" -import { isOrder } from "../types/orders" -import { - CalculationContextData, - LineAllocationsMap, - LineDiscount, - LineDiscountAmount, - SubtotalOptions, -} from "../types/totals" -import { NewTotalsService, TaxProviderService } from "./index" - -import { FlagRouter } from "@medusajs/utils" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { calculatePriceTaxAmount } from "../utils" - -type ShippingMethodTotals = { - price: number - tax_total: number - total: number - subtotal: number - original_total: number - original_tax_total: number - tax_lines: ShippingMethodTaxLine[] -} - -type GetShippingMethodTotalsOptions = { - include_tax?: boolean - use_tax_lines?: boolean - calculation_context?: TaxCalculationContext -} - -type LineItemTotals = { - unit_price: number - quantity: number - subtotal: number - tax_total: number - total: number - original_total: number - original_tax_total: number - tax_lines: LineItemTaxLine[] - discount_total: number - - raw_discount_total: number -} - -type LineItemTotalsOptions = { - include_tax?: boolean - use_tax_lines?: boolean - exclude_gift_cards?: boolean - calculation_context?: TaxCalculationContext -} - -type GetLineItemTotalOptions = { - include_tax?: boolean - exclude_discounts?: boolean -} - -type TotalsServiceProps = { - taxProviderService: TaxProviderService - newTotalsService: NewTotalsService - taxCalculationStrategy: ITaxCalculationStrategy - manager: EntityManager - featureFlagRouter: FlagRouter -} - -type GetTotalsOptions = { - exclude_gift_cards?: boolean - force_taxes?: boolean -} - -type AllocationMapOptions = { - exclude_gift_cards?: boolean - exclude_discounts?: boolean -} - -type CalculationContextOptions = { - is_return?: boolean - exclude_shipping?: boolean - exclude_gift_cards?: boolean - exclude_discounts?: boolean -} - -/** - * A service that calculates total and subtotals for orders, carts etc.. - * @implements {BaseService} - */ -class TotalsService extends TransactionBaseService { - protected readonly taxProviderService_: TaxProviderService - protected readonly newTotalsService_: NewTotalsService - protected readonly taxCalculationStrategy_: ITaxCalculationStrategy - protected readonly featureFlagRouter_: FlagRouter - - constructor({ - taxProviderService, - newTotalsService, - taxCalculationStrategy, - featureFlagRouter, - }: TotalsServiceProps) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.taxProviderService_ = taxProviderService - this.newTotalsService_ = newTotalsService - this.taxCalculationStrategy_ = taxCalculationStrategy - - this.featureFlagRouter_ = featureFlagRouter - } - - /** - * Calculates total of a given cart or order. - * @param cartOrOrder - object to calculate total for - * @param options - options to calculate by - * @return the calculated subtotal - */ - async getTotal( - cartOrOrder: Cart | Order, - options: GetTotalsOptions = {} - ): Promise { - const subtotal = await this.getSubtotal(cartOrOrder) - const taxTotal = - (await this.getTaxTotal(cartOrOrder, options.force_taxes)) || 0 - const discountTotal = await this.getDiscountTotal(cartOrOrder) - const giftCardTotal = options.exclude_gift_cards - ? { total: 0 } - : await this.getGiftCardTotal(cartOrOrder) - const shippingTotal = await this.getShippingTotal(cartOrOrder) - - return ( - subtotal + taxTotal + shippingTotal - discountTotal - giftCardTotal.total - ) - } - - /** - * Gets the total payments made on an order - * @param order - the order to calculate paid amount for - * @return the total paid amount - */ - getPaidTotal(order: Order): number { - const total = order.payments?.reduce((acc, next) => { - acc += next.amount - return acc - }, 0) - - return total - } - - /** - * The total paid for swaps. May be negative in case of negative swap - * difference. - * @param order - the order to calculate swap total for - * @return the swap total - */ - getSwapTotal(order: Order): number { - let swapTotal = 0 - if (order.swaps && order.swaps.length) { - for (const s of order.swaps) { - swapTotal = swapTotal + s.difference_due - } - } - - return swapTotal - } - - /** - * Gets the totals breakdown for a shipping method. Fetches tax lines if not - * already provided. - * @param shippingMethod - the shipping method to get totals breakdown for. - * @param cartOrOrder - the cart or order to use as context for the breakdown - * @param opts - options for what should be included - * @returns An object that breaks down the totals for the shipping method - */ - async getShippingMethodTotals( - shippingMethod: ShippingMethod, - cartOrOrder: Cart | Order, - opts: GetShippingMethodTotalsOptions = {} - ): Promise { - const calculationContext = - opts.calculation_context || - (await this.getCalculationContext(cartOrOrder, { - exclude_shipping: true, - })) - calculationContext.shipping_methods = [shippingMethod] - - const totals = { - price: shippingMethod.price, - original_total: shippingMethod.price, - total: shippingMethod.price, - subtotal: shippingMethod.price, - original_tax_total: 0, - tax_total: 0, - tax_lines: shippingMethod.tax_lines || [], - } - - if (opts.include_tax) { - if (isOrder(cartOrOrder) && cartOrOrder.tax_rate != null) { - totals.original_tax_total = Math.round( - totals.price * (cartOrOrder.tax_rate / 100) - ) - totals.tax_total = Math.round( - totals.price * (cartOrOrder.tax_rate / 100) - ) - } else if (totals.tax_lines.length === 0) { - const orderLines = await this.taxProviderService_ - .withTransaction(this.activeManager_) - .getTaxLines(cartOrOrder.items, calculationContext) - - totals.tax_lines = orderLines.filter((ol) => { - if ("shipping_method_id" in ol) { - return ol.shipping_method_id === shippingMethod.id - } - return false - }) as ShippingMethodTaxLine[] - - if (totals.tax_lines.length === 0 && isOrder(cartOrOrder)) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Tax Lines must be joined on shipping method to calculate taxes" - ) - } - } - - if (totals.tax_lines.length > 0) { - const includesTax = - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && shippingMethod.includes_tax - - totals.original_tax_total = - await this.taxCalculationStrategy_.calculate( - [], - totals.tax_lines, - calculationContext - ) - totals.tax_total = totals.original_tax_total - - if (includesTax) { - totals.subtotal -= totals.tax_total - } else { - totals.original_total += totals.original_tax_total - totals.total += totals.tax_total - } - } - } - - const hasFreeShipping = cartOrOrder.discounts?.some( - (d) => d.rule.type === DiscountRuleType.FREE_SHIPPING - ) - - if (hasFreeShipping) { - totals.total = 0 - totals.subtotal = 0 - totals.tax_total = 0 - } - - return totals - } - - /** - * Calculates subtotal of a given cart or order. - * @param cartOrOrder - cart or order to calculate subtotal for - * @param opts - options - * @return the calculated subtotal - */ - async getSubtotal( - cartOrOrder: Cart | Order, - opts: SubtotalOptions = {} - ): Promise { - let subtotal = 0 - if (!cartOrOrder.items) { - return subtotal - } - - const getLineItemSubtotal = async (item: LineItem): Promise => { - const totals = await this.getLineItemTotals(item, cartOrOrder, { - include_tax: true, - exclude_gift_cards: true, - }) - return totals.subtotal - } - - for (const item of cartOrOrder.items) { - if (opts.excludeNonDiscounts) { - if (item.allow_discounts) { - subtotal += await getLineItemSubtotal(item) - } - continue - } - - subtotal += await getLineItemSubtotal(item) - } - - return this.rounded(subtotal) - } - - /** - * Calculates shipping total - * @param cartOrOrder - cart or order to calculate subtotal for - * @return shipping total - */ - async getShippingTotal(cartOrOrder: Cart | Order): Promise { - const { shipping_methods } = cartOrOrder - - let total = 0 - for (const shippingMethod of shipping_methods) { - const totals = await this.getShippingMethodTotals( - shippingMethod, - cartOrOrder, - { - include_tax: true, - } - ) - - total += totals.subtotal - } - - return total - } - - /** - * Calculates tax total - * Currently based on the Danish tax system - * @param cartOrOrder - cart or order to calculate tax total for - * @param forceTaxes - whether taxes should be calculated regardless - * of region settings - * @return tax total - */ - async getTaxTotal( - cartOrOrder: Cart | Order, - forceTaxes = false - ): Promise { - if ( - isCart(cartOrOrder) && - !forceTaxes && - !cartOrOrder.region.automatic_taxes - ) { - return null - } - - const calculationContext = await this.getCalculationContext(cartOrOrder) - const giftCardTotal = await this.getGiftCardTotal(cartOrOrder) - - let taxLines: (ShippingMethodTaxLine | LineItemTaxLine)[] - if (isOrder(cartOrOrder)) { - const taxLinesJoined = cartOrOrder.items.every((i) => - isDefined(i.tax_lines) - ) - if (!taxLinesJoined) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Order tax calculations must have tax lines joined on line items" - ) - } - - if (cartOrOrder.tax_rate === null) { - taxLines = cartOrOrder.items.flatMap((li) => li.tax_lines) - - const shippingTaxLines = cartOrOrder.shipping_methods.flatMap( - (sm) => sm.tax_lines - ) - - taxLines = taxLines.concat(shippingTaxLines) - } else { - const subtotal = await this.getSubtotal(cartOrOrder) - const shippingTotal = await this.getShippingTotal(cartOrOrder) - const discountTotal = await this.getDiscountTotal(cartOrOrder) - return this.rounded( - (subtotal - discountTotal - giftCardTotal.total + shippingTotal) * - (cartOrOrder.tax_rate / 100) - ) - } - } else { - taxLines = await this.taxProviderService_ - .withTransaction(this.activeManager_) - .getTaxLines(cartOrOrder.items, calculationContext) - - if (cartOrOrder.type === "swap") { - const returnTaxLines = cartOrOrder.items.flatMap((i) => { - if (i.is_return) { - if (typeof i.tax_lines === "undefined") { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Return Line Items must join tax lines" - ) - } - return i.tax_lines - } - - return [] - }) - - taxLines = taxLines.concat(returnTaxLines) - } - } - - const toReturn = await this.taxCalculationStrategy_.calculate( - cartOrOrder.items, - taxLines, - calculationContext - ) - - if (cartOrOrder.region.gift_cards_taxable) { - return this.rounded(toReturn - giftCardTotal.tax_total) - } - - return this.rounded(toReturn) - } - - /** - * Gets a map of discounts and gift cards that apply to line items in an - * order. The function calculates the amount of a discount or gift card that - * applies to a specific line item. - * @param orderOrCart - the order or cart to get an allocation map for - * @param options - controls what should be included in allocation map - * @return the allocation map for the line items in the cart or order. - */ - async getAllocationMap( - orderOrCart: { - discounts?: Discount[] - items: LineItem[] - swaps?: Swap[] - claims?: ClaimOrder[] - }, - options: AllocationMapOptions = {} - ): Promise { - const allocationMap: LineAllocationsMap = {} - - if (!options.exclude_discounts) { - const discount = orderOrCart.discounts?.find( - ({ rule }) => rule.type !== DiscountRuleType.FREE_SHIPPING - ) - - const lineDiscounts: LineDiscountAmount[] = this.getLineDiscounts( - orderOrCart, - discount - ) - - for (const ld of lineDiscounts) { - const adjustmentAmount = ld.amount + ld.customAdjustmentsAmount - - if (allocationMap[ld.item.id]) { - allocationMap[ld.item.id].discount = { - amount: adjustmentAmount, - /** - * Used for the refund computation - */ - unit_amount: adjustmentAmount / ld.item.quantity, - } - } else { - allocationMap[ld.item.id] = { - discount: { - amount: adjustmentAmount, - /** - * Used for the refund computation - */ - unit_amount: Math.round(adjustmentAmount / ld.item.quantity), - }, - } - } - } - } - - return allocationMap - } - - /** - * Gets the total refund amount for an order. - * @param order - the order to get total refund amount for. - * @return the total refunded amount for an order. - */ - getRefundedTotal(order: Order): number { - if (!order.refunds) { - return 0 - } - - const total = order.refunds.reduce((acc, next) => acc + next.amount, 0) - return this.rounded(total) - } - - /** - * The amount that can be refunded for a given line item. - * @param order - order to use as context for the calculation - * @param lineItem - the line item to calculate the refund amount for. - * @return the line item refund amount. - */ - async getLineItemRefund(order: Order, lineItem: LineItem): Promise { - const allocationMap = await this.getAllocationMap(order) - - const includesTax = - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && lineItem.includes_tax - - const discountAmount = - (allocationMap[lineItem.id]?.discount?.unit_amount || 0) * - lineItem.quantity - - let lineSubtotal = lineItem.unit_price * lineItem.quantity - discountAmount - - /* - * Used for backcompat with old tax system - */ - if (order.tax_rate !== null) { - const taxAmountIncludedInPrice = !includesTax - ? 0 - : Math.round( - calculatePriceTaxAmount({ - price: lineItem.unit_price, - taxRate: order.tax_rate / 100, - includesTax, - }) - ) - - lineSubtotal = - (lineItem.unit_price - taxAmountIncludedInPrice) * lineItem.quantity - - discountAmount - - const taxRate = order.tax_rate / 100 - return this.rounded(lineSubtotal * (1 + taxRate)) - } - - /* - * New tax system uses the tax lines registerd on the line items - */ - if (typeof lineItem.tax_lines === "undefined") { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Tax calculation did not receive tax_lines" - ) - } - - const taxRate = lineItem.tax_lines.reduce((acc, next) => { - return acc + next.rate / 100 - }, 0) - const taxAmountIncludedInPrice = !includesTax - ? 0 - : Math.round( - calculatePriceTaxAmount({ - price: lineItem.unit_price, - taxRate, - includesTax, - }) - ) - - lineSubtotal = - (lineItem.unit_price - taxAmountIncludedInPrice) * lineItem.quantity - - discountAmount - - const taxTotal = lineItem.tax_lines.reduce((acc, next) => { - const taxRate = next.rate / 100 - return acc + this.rounded(lineSubtotal * taxRate) - }, 0) - - return lineSubtotal + taxTotal - } - - /** - * Calculates refund total of line items. - * If any of the items to return have been discounted, we need to - * apply the discount again before refunding them. - * @param order - cart or order to calculate subtotal for - * @param lineItems - the line items to calculate refund total for - * @return the calculated subtotal - */ - async getRefundTotal(order: Order, lineItems: LineItem[]): Promise { - let itemIds = order.items.map((i) => i.id) - - // in case we swap a swap, we need to include swap items - if (order.swaps && order.swaps.length) { - for (const s of order.swaps) { - const swapItemIds = s.additional_items.map((el) => el.id) - itemIds = [...itemIds, ...swapItemIds] - } - } - - if (order.claims && order.claims.length) { - for (const c of order.claims) { - const claimItemIds = c.additional_items.map((el) => el.id) - itemIds = [...itemIds, ...claimItemIds] - } - } - - const refunds: number[] = [] - for (const item of lineItems) { - if (!itemIds.includes(item.id)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Line item does not exist on order" - ) - } - - const refund = await this.getLineItemRefund(order, item) - refunds.push(refund) - } - - return this.rounded(refunds.reduce((acc, next) => acc + next, 0)) - } - - /** - * Calculates either fixed or percentage discount of a variant - * @param lineItem - id of line item - * @param variant - id of variant in line item - * @param variantPrice - price of the variant based on region - * @param value - discount value - * @param discountType - the type of discount (fixed or percentage) - * @return triples of lineitem, variant and applied discount - * @deprecated - in favour of DiscountService.calculateDiscountForLineItem - */ - calculateDiscount_( - lineItem: LineItem, - variant: string, - variantPrice: number, - value: number, - discountType: DiscountRuleType - ): LineDiscount { - if (!lineItem.allow_discounts) { - return { - lineItem, - variant, - amount: 0, - } - } - if (discountType === DiscountRuleType.PERCENTAGE) { - return { - lineItem, - variant, - amount: ((variantPrice * lineItem.quantity) / 100) * value, - } - } else { - return { - lineItem, - variant, - amount: - value >= variantPrice * lineItem.quantity - ? variantPrice * lineItem.quantity - : value * lineItem.quantity, - } - } - } - - /** - * If the rule of a discount has allocation="item", then we need - * to calculate discount on each item in the cart. Furthermore, we need to - * make sure to only apply the discount on valid variants. And finally we - * return ether an array of percentages discounts or fixed discounts - * alongside the variant on which the discount was applied. - * @param discount - the discount to which we do the calculation - * @param cart - the cart to calculate discounts for - * @return array of triples of lineitem, variant and applied discount - */ - getAllocationItemDiscounts( - discount: Discount, - cart: Cart | Order - ): LineDiscount[] { - const discounts: LineDiscount[] = cart.items.map((item) => ({ - lineItem: item, - variant: item.variant.id, - amount: this.getLineItemDiscountAdjustment(item, discount), - })) - - return discounts - } - - getLineItemDiscountAdjustment( - lineItem: LineItem, - discount: Discount - ): number { - const matchingDiscount = lineItem.adjustments?.find( - (adjustment) => adjustment.discount_id === discount.id - ) - - if (!matchingDiscount) { - return 0 - } - - return matchingDiscount.amount - } - - getLineItemAdjustmentsTotal(cartOrOrder: Cart | Order): number { - if (!cartOrOrder?.items?.length) { - return 0 - } - - return cartOrOrder.items.reduce( - (total, item) => - total + - item.adjustments?.reduce( - (total, adjustment) => total + adjustment.amount, - 0 - ) || 0, - 0 - ) - } - - /** - * Returns the discount amount allocated to the line items of an order. - * @param cartOrOrder - the cart or order to get line discount allocations for - * @param discount - the discount to use as context for the calculation - * @return the allocations that the discount has on the items in the cart or - * order - */ - getLineDiscounts( - cartOrOrder: { - items: LineItem[] - swaps?: Swap[] - claims?: ClaimOrder[] - }, - discount?: Discount - ): LineDiscountAmount[] { - let merged: LineItem[] = [...(cartOrOrder.items ?? [])] - - // merge items from order with items from order swaps - if ("swaps" in cartOrOrder && cartOrOrder.swaps?.length) { - for (const s of cartOrOrder.swaps) { - merged = [...merged, ...s.additional_items] - } - } - - if ("claims" in cartOrOrder && cartOrOrder.claims?.length) { - for (const c of cartOrOrder.claims) { - merged = [...merged, ...c.additional_items] - } - } - - return merged.map((item) => { - const adjustments = item?.adjustments || [] - const discountAdjustments = discount - ? adjustments.filter( - (adjustment) => adjustment.discount_id === discount.id - ) - : [] - - const customAdjustments = adjustments.filter( - (adjustment) => adjustment.discount_id === null - ) - - const sumAdjustments = (total, adjustment) => total + adjustment.amount - - return { - item, - amount: item.allow_discounts - ? discountAdjustments.reduce(sumAdjustments, 0) - : 0, - customAdjustmentsAmount: customAdjustments.reduce(sumAdjustments, 0), - } - }) - } - - /** - * Breaks down the totals related to a line item; these are the subtotal, the - * amount of discount applied to the line item, the amount of a gift card - * applied to a line item and the amount of tax applied to a line item. - * @param lineItem - the line item to calculate totals for - * @param cartOrOrder - the cart or order to use as context for the calculation - * @param options - the options to evaluate the line item totals for - * @returns the breakdown of the line item totals - */ - async getLineItemTotals( - lineItem: LineItem, - cartOrOrder: Cart | Order, - options: LineItemTotalsOptions = {} - ): Promise { - const calculationContext = - options.calculation_context || - (await this.getCalculationContext(cartOrOrder, { - exclude_shipping: true, - exclude_gift_cards: options.exclude_gift_cards, - })) - const lineItemAllocation = - calculationContext.allocation_map[lineItem.id] || {} - - let subtotal = lineItem.unit_price * lineItem.quantity - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && - lineItem.includes_tax && - options.include_tax - ) { - subtotal = 0 // in that case we need to know the tax rate to compute it later - } - - const raw_discount_total = lineItemAllocation.discount?.amount ?? 0 - const discount_total = Math.round(raw_discount_total) - - const lineItemTotals: LineItemTotals = { - unit_price: lineItem.unit_price, - quantity: lineItem.quantity, - subtotal, - discount_total, - total: subtotal - discount_total, - original_total: subtotal, - original_tax_total: 0, - tax_total: 0, - tax_lines: lineItem.tax_lines || [], - - raw_discount_total, - } - - // Tax Information - if (options.include_tax) { - // When we have an order with a tax rate we know that it is an - // order from the old tax system. The following is a backward compat - // calculation. - if (isOrder(cartOrOrder) && cartOrOrder.tax_rate != null) { - const taxRate = cartOrOrder.tax_rate / 100 - - const includesTax = - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && lineItem.includes_tax - const taxIncludedInPrice = !lineItem.includes_tax - ? 0 - : Math.round( - calculatePriceTaxAmount({ - price: lineItem.unit_price, - taxRate: taxRate, - includesTax, - }) - ) - lineItemTotals.subtotal = - (lineItem.unit_price - taxIncludedInPrice) * lineItem.quantity - lineItemTotals.total = lineItemTotals.subtotal - - lineItemTotals.original_tax_total = lineItemTotals.subtotal * taxRate - lineItemTotals.tax_total = - (lineItemTotals.subtotal - discount_total) * taxRate - - lineItemTotals.total += lineItemTotals.tax_total - lineItemTotals.original_total += lineItemTotals.original_tax_total - } else { - let taxLines: LineItemTaxLine[] - - /* - * Line Items on orders will already have tax lines. But for cart line - * items we have to get the line items from the tax provider. - */ - if (options.use_tax_lines || isOrder(cartOrOrder)) { - if (!isDefined(lineItem.tax_lines) && lineItem.variant_id) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Tax Lines must be joined on items to calculate taxes" - ) - } - - taxLines = lineItem.tax_lines - } else { - if (lineItem.is_return) { - if (!isDefined(lineItem.tax_lines) && lineItem.variant_id) { - throw new MedusaError( - MedusaError.Types.UNEXPECTED_STATE, - "Return Line Items must join tax lines" - ) - } - taxLines = lineItem.tax_lines - } else { - taxLines = (await this.taxProviderService_ - .withTransaction(this.activeManager_) - .getTaxLines([lineItem], calculationContext)) as LineItemTaxLine[] - } - } - - lineItemTotals.tax_lines = taxLines - } - } - - if (lineItemTotals.tax_lines.length > 0) { - lineItemTotals.tax_total = await this.taxCalculationStrategy_.calculate( - [lineItem], - lineItemTotals.tax_lines, - calculationContext - ) - const noDiscountContext = { - ...calculationContext, - allocation_map: {}, // Don't account for discounts - } - - lineItemTotals.original_tax_total = - await this.taxCalculationStrategy_.calculate( - [lineItem], - lineItemTotals.tax_lines, - noDiscountContext - ) - - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && - lineItem.includes_tax - ) { - lineItemTotals.subtotal += - lineItem.unit_price * lineItem.quantity - - lineItemTotals.original_tax_total - lineItemTotals.total += lineItemTotals.subtotal - lineItemTotals.original_total += lineItemTotals.subtotal - } - - lineItemTotals.total += lineItemTotals.tax_total - lineItemTotals.original_total += lineItemTotals.original_tax_total - } - - return lineItemTotals - } - - /** - * Gets a total for a line item. The total can take gift cards, discounts and - * taxes into account. This can be controlled through the options. - * @param lineItem - the line item to calculate a total for - * @param cartOrOrder - the cart or order to use as context for the calculation - * @param options - the options to use for the calculation - * @returns the line item total - */ - async getLineItemTotal( - lineItem: LineItem, - cartOrOrder: Cart | Order, - options: GetLineItemTotalOptions = {} - ): Promise { - const lineItemTotals = await this.getLineItemTotals(lineItem, cartOrOrder, { - include_tax: options.include_tax, - }) - - let toReturn = lineItemTotals.subtotal - if (!options.exclude_discounts) { - toReturn += lineItemTotals.discount_total - } - - if (options.include_tax) { - toReturn += lineItemTotals.tax_total - } - - return toReturn - } - - /** - * Gets the amount that can be gift carded on a cart. In regions where gift - * cards are taxable this amount should exclude taxes. - * @param cartOrOrder - the cart or order to get gift card amount for - * @return the gift card amount applied to the cart or order - */ - async getGiftCardableAmount(cartOrOrder: Cart | Order): Promise { - if (cartOrOrder.region?.gift_cards_taxable) { - const subtotal = await this.getSubtotal(cartOrOrder) - const discountTotal = await this.getDiscountTotal(cartOrOrder) - return subtotal - discountTotal - } - - return await this.getTotal(cartOrOrder, { - exclude_gift_cards: true, - }) - } - - /** - * Gets the gift card amount on a cart or order. - * @param cartOrOrder - the cart or order to get gift card amount for - * @return the gift card amount applied to the cart or order - */ - async getGiftCardTotal( - cartOrOrder: Cart | Order, - opts: { gift_cardable?: number } = {} - ): Promise<{ - total: number - tax_total: number - }> { - let giftCardable: number - - if (typeof opts.gift_cardable !== "undefined") { - giftCardable = opts.gift_cardable - } else { - const subtotal = await this.getSubtotal(cartOrOrder) - const discountTotal = await this.getDiscountTotal(cartOrOrder) - - giftCardable = subtotal - discountTotal - } - - return await this.newTotalsService_.getGiftCardTotals(giftCardable, { - region: cartOrOrder.region, - giftCards: cartOrOrder.gift_cards || [], - giftCardTransactions: cartOrOrder["gift_card_transactions"] || [], - }) - } - - /** - * Calculates the total discount amount for each of the different supported - * discount types. If discounts aren't present or invalid returns 0. - * @param cartOrOrder - the cart or order to calculate discounts for - * @return the total discounts amount - */ - async getDiscountTotal(cartOrOrder: Cart | Order): Promise { - const subtotal = await this.getSubtotal(cartOrOrder, { - excludeNonDiscounts: true, - }) - - const discountTotal = Math.round( - this.getLineItemAdjustmentsTotal(cartOrOrder) - ) - - if (subtotal < 0) { - return this.rounded(Math.max(subtotal, discountTotal)) - } - - return this.rounded(Math.min(subtotal, discountTotal)) - } - - /** - * Prepares the calculation context for a tax total calculation. - * @param calculationContextData - the calculationContextData to get the calculation context for - * @param options - options to gather context by - * @return the tax calculation context - */ - async getCalculationContext( - calculationContextData: CalculationContextData, - options: CalculationContextOptions = {} - ): Promise { - const allocationMap = await this.getAllocationMap(calculationContextData, { - exclude_gift_cards: options.exclude_gift_cards, - exclude_discounts: options.exclude_discounts, - }) - - let shippingMethods: ShippingMethod[] = [] - // Default to include shipping methods - if (!options.exclude_shipping) { - shippingMethods = calculationContextData.shipping_methods || [] - } - - return { - shipping_address: calculationContextData.shipping_address, - shipping_methods: shippingMethods, - customer: calculationContextData.customer, - region: calculationContextData.region, - is_return: options.is_return ?? false, - allocation_map: allocationMap, - } - } - - /** - * Rounds a number using Math.round. - * @param value - the value to round - * @return the rounded value - */ - rounded(value: number): number { - return Math.round(value) - } -} - -export default TotalsService diff --git a/packages/medusa/src/services/user.ts b/packages/medusa/src/services/user.ts deleted file mode 100644 index e5ad0fe310..0000000000 --- a/packages/medusa/src/services/user.ts +++ /dev/null @@ -1,428 +0,0 @@ -import { Selector } from "@medusajs/types" -import { FlagRouter } from "@medusajs/utils" -import jwt from "jsonwebtoken" -import { isDefined, MedusaError } from "medusa-core-utils" -import Scrypt from "scrypt-kdf" -import { EntityManager, FindOptionsWhere, ILike } from "typeorm" -import { TransactionBaseService } from "../interfaces" -import AnalyticsFeatureFlag from "../loaders/feature-flags/analytics" -import { User } from "../models" -import { UserRepository } from "../repositories/user" -import { FindConfig } from "../types/common" -import { - CreateUserInput, - FilterableUserProps, - UpdateUserInput, -} from "../types/user" -import { buildQuery, setMetadata } from "../utils" -import { validateEmail } from "../utils/is-email" -import AnalyticsConfigService from "./analytics-config" -import EventBusService from "./event-bus" - -type UserServiceProps = { - userRepository: typeof UserRepository - analyticsConfigService: AnalyticsConfigService - eventBusService: EventBusService - manager: EntityManager - featureFlagRouter: FlagRouter -} - -/** - * Provides layer to manipulate users. - */ -class UserService extends TransactionBaseService { - static Events = { - PASSWORD_RESET: "user.password_reset", - CREATED: "user.created", - UPDATED: "user.updated", - DELETED: "user.deleted", - } - - protected readonly analyticsConfigService_: AnalyticsConfigService - protected readonly userRepository_: typeof UserRepository - protected readonly eventBus_: EventBusService - protected readonly featureFlagRouter_: FlagRouter - - constructor({ - userRepository, - eventBusService, - analyticsConfigService, - featureFlagRouter, - }: UserServiceProps) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.userRepository_ = userRepository - this.analyticsConfigService_ = analyticsConfigService - this.featureFlagRouter_ = featureFlagRouter - this.eventBus_ = eventBusService - } - - /** - * @param {FilterableUserProps} selector - the query object for find - * @param {Object} config - the configuration object for the query - * @return {Promise} the result of the find operation - */ - async list( - selector: Selector & { q?: string } = {}, - config: FindConfig = { skip: 0, take: 50 } - ): Promise { - const userRepo = this.activeManager_.withRepository(this.userRepository_) - - let q: string | undefined - - if (selector.q) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - - if (q) { - const where = query.where as FindOptionsWhere - - delete where.email - delete where.first_name - delete where.last_name - - query.where = [ - { - ...where, - email: ILike(`%${q}%`), - }, - { - ...where, - first_name: ILike(`%${q}%`), - }, - { - ...where, - last_name: ILike(`%${q}%`), - }, - ] - } - - return await userRepo.find(query) - } - - async listAndCount( - selector: Selector & { q?: string } = {}, - config: FindConfig = { skip: 0, take: 50 } - ) { - const userRepo = this.activeManager_.withRepository(this.userRepository_) - - let q: string | undefined - - if (selector.q) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - - if (q) { - const where = query.where as FindOptionsWhere - - delete where.email - delete where.first_name - delete where.last_name - - query.where = [ - { - ...where, - email: ILike(`%${q}%`), - }, - { - ...where, - first_name: ILike(`%${q}%`), - }, - { - ...where, - last_name: ILike(`%${q}%`), - }, - ] - } - - return await userRepo.findAndCount(query) - } - - /** - * Gets a user by id. - * Throws in case of DB Error and if user was not found. - * @param {string} userId - the id of the user to get. - * @param {FindConfig} config - query configs - * @return {Promise} the user document. - */ - async retrieve(userId: string, config: FindConfig = {}): Promise { - if (!isDefined(userId)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `"userId" must be defined` - ) - } - - const userRepo = this.activeManager_.withRepository(this.userRepository_) - const query = buildQuery({ id: userId }, config) - - const users = await userRepo.find(query) - - if (!users.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `User with id: ${userId} was not found` - ) - } - - return users[0] - } - - /** - * Gets a user by api token. - * Throws in case of DB Error and if user was not found. - * @param {string} apiToken - the token of the user to get. - * @param {string[]} relations - relations to include with the user. - * @return {Promise} the user document. - */ - async retrieveByApiToken( - apiToken: string, - relations: string[] = [] - ): Promise { - const userRepo = this.activeManager_.withRepository(this.userRepository_) - - const user = await userRepo.findOne({ - where: { api_token: apiToken }, - relations, - }) - - if (!user) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `User with api token: ${apiToken} was not found` - ) - } - - return user - } - - /** - * Gets a user by email. - * Throws in case of DB Error and if user was not found. - * @param {string} email - the email of the user to get. - * @param {FindConfig} config - query config - * @return {Promise} the user document. - */ - async retrieveByEmail( - email: string, - config: FindConfig = {} - ): Promise { - const userRepo = this.activeManager_.withRepository(this.userRepository_) - - const query = buildQuery({ email: email.toLowerCase() }, config) - const user = await userRepo.findOne(query) - - if (!user) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `User with email: ${email} was not found` - ) - } - - return user - } - - /** - * Hashes a password - * @param {string} password - the value to hash - * @return {string} hashed password - */ - async hashPassword_(password: string): Promise { - const buf = await Scrypt.kdf(password, { logN: 1, r: 1, p: 1 }) - return buf.toString("base64") - } - - /** - * Creates a user with username being validated. - * Fails if email is not a valid format. - * @param {object} user - the user to create - * @param {string} password - user's password to hash - * @return {Promise} the result of create - */ - async create(user: CreateUserInput, password: string): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const userRepo = manager.withRepository(this.userRepository_) - - const createData = { ...user } as CreateUserInput & { - password_hash: string - } - - const validatedEmail = validateEmail(user.email) - - const userEntity = await userRepo.findOne({ - where: { email: validatedEmail }, - }) - - if (userEntity) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "A user with the same email already exists." - ) - } - - if (password) { - const hashedPassword = await this.hashPassword_(password) - createData.password_hash = hashedPassword - } - - createData.email = validatedEmail - - const created = userRepo.create(createData) - - const newUser = await userRepo.save(created) - - await this.eventBus_ - .withTransaction(manager) - .emit(UserService.Events.CREATED, { id: newUser.id }) - - return newUser - }) - } - - /** - * Updates a user. - * @param {object} userId - id of the user to update - * @param {object} update - the values to be updated on the user - * @return {Promise} the result of create - */ - async update(userId: string, update: UpdateUserInput): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const userRepo = manager.withRepository(this.userRepository_) - - const user = await this.retrieve(userId) - - const { email, password_hash, metadata, ...rest } = update - - if (email) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "You are not allowed to update email" - ) - } - - if (password_hash) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Use dedicated methods, `setPassword`, `generateResetPasswordToken` for password operations" - ) - } - - if (metadata) { - user.metadata = setMetadata(user, metadata) - } - - for (const [key, value] of Object.entries(rest)) { - user[key] = value - } - - const updatedUser = await userRepo.save(user) - - await this.eventBus_ - .withTransaction(manager) - .emit(UserService.Events.UPDATED, { id: updatedUser.id }) - - return updatedUser - }) - } - - /** - * Deletes a user from a given user id. - * @param {string} userId - the id of the user to delete. Must be - * castable as an ObjectId - * @return {Promise} the result of the delete operation. - */ - async delete(userId: string): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const userRepo = manager.withRepository(this.userRepository_) - const analyticsServiceTx = - this.analyticsConfigService_.withTransaction(manager) - - // Should not fail, if user does not exist, since delete is idempotent - const user = await userRepo.findOne({ where: { id: userId } }) - - if (!user) { - return Promise.resolve() - } - - if (this.featureFlagRouter_.isFeatureEnabled(AnalyticsFeatureFlag.key)) { - await analyticsServiceTx.delete(userId) - } - - await userRepo.softRemove(user) - - await this.eventBus_ - .withTransaction(manager) - .emit(UserService.Events.DELETED, { id: user.id }) - - return Promise.resolve() - }) - } - - /** - * Sets a password for a user - * Fails if no user exists with userId and if the hashing of the new - * password does not work. - * @param {string} userId - the userId to set password for - * @param {string} password - the old password to set - * @return {Promise} the result of the update operation - */ - async setPassword_(userId: string, password: string): Promise { - return await this.atomicPhase_(async (manager: EntityManager) => { - const userRepo = manager.withRepository(this.userRepository_) - - const user = await this.retrieve(userId) - - const hashedPassword = await this.hashPassword_(password) - if (!hashedPassword) { - throw new MedusaError( - MedusaError.Types.DB_ERROR, - `An error occured while hashing password` - ) - } - - user.password_hash = hashedPassword - - return await userRepo.save(user) - }) - } - - /** - * Generate a JSON Web token, that will be sent to a user, that wishes to - * reset password. - * The token will be signed with the users current password hash as a secret - * a long side a payload with userId and the expiry time for the token, which - * is always 15 minutes. - * @param {string} userId - the id of the user to reset password for - * @return {string} the generated JSON web token - */ - async generateResetPasswordToken(userId: string): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const user = await this.retrieve(userId, { - select: ["id", "email", "password_hash"], - }) - const secret = user.password_hash - const expiry = Math.floor(Date.now() / 1000) + 60 * 15 - const payload = { user_id: user.id, email: user.email, exp: expiry } - const token = jwt.sign(payload, secret) - - // Notify subscribers - await this.eventBus_ - .withTransaction(transactionManager) - .emit(UserService.Events.PASSWORD_RESET, { - email: user.email, - token, - }) - - return token - }) - } -} - -export default UserService diff --git a/packages/medusa/src/strategies/__fixtures__/order-export-data.ts b/packages/medusa/src/strategies/__fixtures__/order-export-data.ts deleted file mode 100644 index 2c5fd5209c..0000000000 --- a/packages/medusa/src/strategies/__fixtures__/order-export-data.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { DeepPartial } from "typeorm" -import { IdMap } from "medusa-test-utils" -import { - FulfillmentStatus, - Order, - OrderStatus, - PaymentStatus, -} from "../../models" - -const createdAtDate = new Date("2019-01-01T00:00:00.000Z") - -export const ordersToExport: DeepPartial[] = [ - { - id: "order_1", - created_at: createdAtDate, - display_id: 123, - status: OrderStatus.PENDING, - fulfillment_status: FulfillmentStatus.PARTIALLY_FULFILLED, - payment_status: PaymentStatus.CAPTURED, - subtotal: 10, - shipping_total: 10, - discount_total: 0, - gift_card_total: 0, - refunded_total: 0, - tax_total: 5, - total: 25, - currency_code: "usd", - region_id: "region_1", - shipping_address: { - id: "address_1", - address_1: "123 Main St", - address_2: "", - city: "New York", - country_code: "US", - postal_code: "10001", - }, - customer: { - id: "customer_1", - first_name: "John", - last_name: "Doe", - email: "John@Doe.com", - }, - sales_channel: { - id: IdMap.getId("sc_1"), - name: "SC 1", - description: "SC 1", - }, - }, - { - id: "order_2", - created_at: createdAtDate, - display_id: 124, - status: OrderStatus.COMPLETED, - fulfillment_status: FulfillmentStatus.FULFILLED, - payment_status: PaymentStatus.CAPTURED, - subtotal: 125, - shipping_total: 10, - discount_total: 0, - gift_card_total: 0, - refunded_total: 0, - tax_total: 0, - total: 135, - currency_code: "eur", - region_id: "region_2", - shipping_address: { - id: "address_2", - address_1: "Hovedgaden 1", - address_2: "", - city: "Copenhagen", - country_code: "DK", - postal_code: "1150", - }, - customer: { - id: "customer_2", - first_name: "Jane", - last_name: "Doe", - email: "Jane@Doe.com", - }, - sales_channel: { - id: IdMap.getId("sc_2"), - name: "SC 2", - description: "SC 2", - }, - }, -] diff --git a/packages/medusa/src/strategies/__fixtures__/product-export-data.ts b/packages/medusa/src/strategies/__fixtures__/product-export-data.ts deleted file mode 100644 index 3fe70ea8e4..0000000000 --- a/packages/medusa/src/strategies/__fixtures__/product-export-data.ts +++ /dev/null @@ -1,410 +0,0 @@ -import { IdMap } from "medusa-test-utils" - -const productIds = [ - "product-export-strategy-product-1", - "product-export-strategy-product-2", -] -const variantIds = [ - "product-export-strategy-variant-1", - "product-export-strategy-variant-2", - "product-export-strategy-variant-3", -] -export const productsToExport = [ - { - sales_channels: [ - { - id: IdMap.getId("sc_1"), - name: "SC 1", - description: "SC 1\nSC 1 second line\nSC 1 third line\nSC 1 forth line", - }, - ], - collection: { - created_at: "randomString", - deleted_at: null, - handle: "test-collection1", - id: IdMap.getId("product-export-collection_1"), - metadata: null, - title: "Test collection 1", - updated_at: "randomString", - }, - collection_id: IdMap.getId("product-export-collection_1"), - created_at: "randomString", - deleted_at: null, - description: - "test-product-description-1\ntest-product-description-1 second line\ntest-product-description-1 third line\nforth line", - discountable: true, - external_id: null, - handle: "test-product-product-1", - height: null, - hs_code: null, - id: productIds[0], - images: [ - { - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-image_1"), - metadata: null, - updated_at: "randomString", - url: "test-image.png", - }, - ], - is_giftcard: false, - length: null, - material: null, - metadata: null, - mid_code: null, - options: [ - { - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-option_1"), - metadata: null, - product_id: productIds[0], - title: "test-option-1", - updated_at: "randomString", - }, - { - created_at: "randomString2", - deleted_at: null, - id: IdMap.getId("product-export-option_2"), - metadata: null, - product_id: productIds[0], - title: "test-option-2", - updated_at: "randomString2", - }, - ], - origin_country: null, - profile_id: IdMap.getId("product-export-profile_1"), - profile: { - id: IdMap.getId("product-export-profile_1"), - name: "profile_1", - type: "profile_type_1", - }, - status: "draft", - subtitle: null, - tags: [ - { - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-tag_1"), - metadata: null, - updated_at: "randomString", - value: "123_1", - }, - ], - thumbnail: null, - title: "Test product", - type: { - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-type_1"), - metadata: null, - updated_at: "randomString", - value: "test-type-1", - }, - type_id: IdMap.getId("product-export-type_1"), - updated_at: "randomString", - variants: [ - { - allow_backorder: false, - barcode: "test-barcode", - calculated_price: null, - created_at: "randomString", - deleted_at: null, - ean: "test-ean", - height: null, - hs_code: null, - id: variantIds[0], - inventory_quantity: 10, - length: null, - manage_inventory: true, - material: null, - metadata: null, - mid_code: null, - options: [ - { - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-variant_option_1"), - metadata: null, - option_id: IdMap.getId("product-export-option_1"), - updated_at: "randomString", - value: "option 1 value 1", - variant_id: variantIds[0], - }, - { - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-variant_option_2"), - metadata: null, - option_id: IdMap.getId("product-export-option_2"), - updated_at: "randomString", - value: "option 2 value 1", - variant_id: variantIds[0], - }, - ], - origin_country: null, - original_price: null, - prices: [ - { - amount: 100, - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-price_1"), - region_id: IdMap.getId("product-export-region_1"), - max_quantity: null, - min_quantity: null, - price_list: null, - price_list_id: null, - region: { - id: IdMap.getId("product-export-region_1"), - currency_code: "usd", - name: "france", - }, - updated_at: "randomString", - variant_id: variantIds[0], - }, - { - amount: 110, - created_at: "randomString", - currency_code: "usd", - deleted_at: null, - id: IdMap.getId("product-export-price_1"), - region_id: null, - max_quantity: null, - min_quantity: null, - price_list: null, - price_list_id: null, - updated_at: "randomString", - variant_id: variantIds[0], - }, - { - amount: 130, - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-price_1"), - region_id: IdMap.getId("product-export-region_1"), - max_quantity: null, - min_quantity: null, - price_list: null, - price_list_id: null, - region: { - id: IdMap.getId("product-export-region_3"), - name: "denmark", - currency_code: "dkk", - }, - updated_at: "randomString", - variant_id: variantIds[0], - }, - ], - product_id: IdMap.getId("product-export-product_1"), - sku: "test-sku", - title: "Test variant", - upc: "test-upc", - updated_at: "randomString", - weight: null, - width: null, - }, - ], - weight: null, - width: null, - }, - { - sales_channels: [ - { id: IdMap.getId("sc_1"), name: "SC 1", description: "SC 1" }, - { id: IdMap.getId("sc_2"), name: "SC 2", description: "SC 2" }, - ], - collection: { - created_at: "randomString", - deleted_at: null, - handle: "test-collection2", - id: IdMap.getId("product-export-collection_2"), - metadata: null, - title: "Test collection", - updated_at: "randomString", - }, - collection_id: "test-collection", - created_at: "randomString", - deleted_at: null, - description: "test-product-description", - discountable: true, - external_id: null, - handle: "test-product-product-2", - height: null, - hs_code: null, - id: productIds[1], - images: [ - { - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-image_2"), - metadata: null, - updated_at: "randomString", - url: "test-image.png", - }, - ], - is_giftcard: false, - length: null, - material: null, - metadata: null, - mid_code: null, - options: [ - { - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-option_2"), - metadata: null, - product_id: productIds[1], - title: "test-option", - updated_at: "randomString", - }, - ], - origin_country: null, - profile_id: IdMap.getId("product-export-profile_2"), - profile: { - id: IdMap.getId("product-export-profile_2"), - name: "profile_2", - type: "profile_type_2", - }, - status: "draft", - subtitle: null, - tags: [ - { - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-tag_2"), - metadata: null, - updated_at: "randomString", - value: "123", - }, - ], - thumbnail: null, - title: "Test product", - type: { - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-type_2"), - metadata: null, - updated_at: "randomString", - value: "test-type", - }, - type_id: "test-type", - updated_at: "randomString", - variants: [ - { - allow_backorder: false, - barcode: "test-barcode", - calculated_price: null, - created_at: "randomString", - deleted_at: null, - ean: "test-ean", - height: null, - hs_code: null, - id: variantIds[1], - inventory_quantity: 10, - length: null, - manage_inventory: true, - material: null, - metadata: null, - mid_code: null, - options: [ - { - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-variant_option_2"), - metadata: null, - option_id: IdMap.getId("product-export-option_2"), - updated_at: "randomString", - value: "Option 1 value 1", - variant_id: variantIds[1], - }, - ], - origin_country: null, - original_price: null, - prices: [ - { - amount: 110, - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-price_2"), - max_quantity: null, - min_quantity: null, - price_list: null, - price_list_id: null, - region_id: IdMap.getId("product-export-region_2"), - region: { - id: IdMap.getId("product-export-region_2"), - name: "Denmark", - currency_code: "dkk", - }, - updated_at: "randomString", - variant_id: variantIds[1], - }, - ], - product_id: IdMap.getId("product-export-product_2"), - sku: "test-sku", - title: "Test variant", - upc: "test-upc", - updated_at: "randomString", - weight: null, - width: null, - }, - { - allow_backorder: false, - barcode: "test-barcode", - calculated_price: null, - created_at: "randomString", - deleted_at: null, - ean: "test-ean", - height: null, - hs_code: null, - id: variantIds[2], - inventory_quantity: 10, - length: null, - manage_inventory: true, - material: null, - metadata: null, - mid_code: null, - options: [ - { - created_at: "randomString", - deleted_at: null, - id: IdMap.getId("product-export-variant_option_2"), - metadata: null, - option_id: IdMap.getId("product-export-option_2"), - updated_at: "randomString", - value: "Option 1 Value 1", - variant_id: variantIds[2], - }, - ], - origin_country: null, - original_price: null, - prices: [ - { - amount: 120, - created_at: "randomString", - currency_code: "usd", - deleted_at: null, - id: IdMap.getId("product-export-price_2"), - max_quantity: null, - min_quantity: null, - price_list: null, - price_list_id: null, - region_id: IdMap.getId("product-export-region_1"), - updated_at: "randomString", - variant_id: variantIds[2], - }, - ], - product_id: productIds[1], - sku: "test-sku", - title: "Test variant", - upc: "test-upc", - updated_at: "randomString", - weight: null, - width: null, - }, - ], - weight: null, - width: null, - }, -] diff --git a/packages/medusa/src/strategies/__mocks__/cart-completion.js b/packages/medusa/src/strategies/__mocks__/cart-completion.js deleted file mode 100644 index a79c4a5be9..0000000000 --- a/packages/medusa/src/strategies/__mocks__/cart-completion.js +++ /dev/null @@ -1,14 +0,0 @@ -export const CompletionStrategyMock = { - complete: jest.fn(() => - Promise.resolve({ - response_code: 200, - response_body: {}, - }) - ), -} - -const mock = jest.fn().mockImplementation(() => { - return CompletionStrategyMock -}) - -export default mock diff --git a/packages/medusa/src/strategies/__tests__/batch-jobs/order/__snapshots__/order-export.ts.snap b/packages/medusa/src/strategies/__tests__/batch-jobs/order/__snapshots__/order-export.ts.snap deleted file mode 100644 index 6cc44b37c8..0000000000 --- a/packages/medusa/src/strategies/__tests__/batch-jobs/order/__snapshots__/order-export.ts.snap +++ /dev/null @@ -1,23 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Order export strategy should process the batch job and generate the appropriate output 1`] = ` -Array [ - "Order_ID;Display_ID;Order status;Date;Customer First name;Customer Last name;Customer Email;Customer ID;Shipping Address 1;Shipping Address 2;Shipping Country Code;Shipping City;Shipping Postal Code;Shipping Region ID;Fulfillment Status;Payment Status;Subtotal;Shipping Total;Discount Total;Gift Card Total;Refunded Total;Tax Total;Total;Currency Code -", - "order_1;123;pending;Tue, 01 Jan 2019 00:00:00 GMT;John;Doe;John@Doe.com;customer_1;123 Main St;;US;New York;10001;region_1;partially_fulfilled;captured;10;10;0;0;0;5;25;usd -", - "order_2;124;completed;Tue, 01 Jan 2019 00:00:00 GMT;Jane;Doe;Jane@Doe.com;customer_2;Hovedgaden 1;;DK;Copenhagen;1150;region_2;fulfilled;captured;125;10;0;0;0;0;135;eur -", -] -`; - -exports[`Order export strategy with sales channel should process the batch job and generate the appropriate output 1`] = ` -Array [ - "Order_ID;Display_ID;Order status;Date;Customer First name;Customer Last name;Customer Email;Customer ID;Shipping Address 1;Shipping Address 2;Shipping Country Code;Shipping City;Shipping Postal Code;Shipping Region ID;Fulfillment Status;Payment Status;Subtotal;Shipping Total;Discount Total;Gift Card Total;Refunded Total;Tax Total;Total;Currency Code;Sales channel name;Sales channel description -", - "order_1;123;pending;Tue, 01 Jan 2019 00:00:00 GMT;John;Doe;John@Doe.com;customer_1;123 Main St;;US;New York;10001;region_1;partially_fulfilled;captured;10;10;0;0;0;5;25;usd;SC 1;SC 1 -", - "order_2;124;completed;Tue, 01 Jan 2019 00:00:00 GMT;Jane;Doe;Jane@Doe.com;customer_2;Hovedgaden 1;;DK;Copenhagen;1150;region_2;fulfilled;captured;125;10;0;0;0;0;135;eur;SC 2;SC 2 -", -] -`; diff --git a/packages/medusa/src/strategies/__tests__/batch-jobs/order/order-export.ts b/packages/medusa/src/strategies/__tests__/batch-jobs/order/order-export.ts deleted file mode 100644 index ab0bbfa308..0000000000 --- a/packages/medusa/src/strategies/__tests__/batch-jobs/order/order-export.ts +++ /dev/null @@ -1,304 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { IdMap, MockManager } from "medusa-test-utils" -import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" -import { User } from "../../../../models" -import { BatchJobStatus } from "../../../../types/batch-job" -import { ordersToExport } from "../../../__fixtures__/order-export-data" -import OrderExportStrategy from "../../../batch-jobs/order/export" - -const orderServiceMock = { - withTransaction: function (): any { - return this - }, - listAndCount: jest - .fn() - .mockImplementation(() => - Promise.resolve([ordersToExport, ordersToExport.length]) - ), - list: jest.fn().mockImplementation(() => Promise.resolve(ordersToExport)), -} -const orderServiceWithoutDataMock = { - ...orderServiceMock, - listAndCount: jest - .fn() - .mockImplementation(() => - Promise.resolve([[], 0]) - ), - list: jest.fn().mockImplementation(() => Promise.resolve([])), -} - -describe("Order export strategy", () => { - const outputDataStorage: string[] = [] - - let fakeJob = { - id: IdMap.getId("order-export-job"), - type: "order-export", - context: { - params: {}, - list_config: { - select: [ - "id", - "display_id", - "status", - "created_at", - "fulfillment_status", - "payment_status", - "subtotal", - "shipping_total", - "discount_total", - "gift_card_total", - "refunded_total", - "tax_total", - "total", - "currency_code", - "region_id", - ], - relations: ["customer", "shipping_address"], - }, - }, - created_by: IdMap.getId("order-export-job-creator"), - created_by_user: {} as User, - result: {}, - dry_run: false, - status: BatchJobStatus.PROCESSING, - } - - const fileServiceMock = { - delete: jest.fn(), - withTransaction: function () { - return this - }, - getUploadStreamDescriptor: jest.fn().mockImplementation(() => { - return Promise.resolve({ - writeStream: { - write: (data: string) => { - outputDataStorage.push(data) - }, - end: () => void 0, - }, - promise: Promise.resolve(), - fileKey: "order-export.csv", - }) - }), - } - const batchJobServiceMock = { - withTransaction: function (): any { - return this - }, - update: jest.fn().mockImplementation(async (job, data) => { - fakeJob = { - ...fakeJob, - ...data, - context: { ...fakeJob?.context, ...data?.context }, - result: { ...fakeJob?.result, ...data?.result } - } - return Promise.resolve(fakeJob) - }), - complete: jest.fn().mockImplementation(async () => { - fakeJob.status = BatchJobStatus.COMPLETED - return fakeJob - }), - retrieve: jest.fn().mockImplementation(async () => { - return fakeJob - }), - } - - const orderExportStrategy = new OrderExportStrategy({ - batchJobService: batchJobServiceMock as any, - fileService: fileServiceMock as any, - orderService: orderServiceMock as any, - manager: MockManager, - featureFlagRouter: new FlagRouter({}), - }) - - it("Should generate header as template", async () => { - const template = await orderExportStrategy.buildTemplate() - expect(template.split(";")).toEqual([ - "Order_ID", - "Display_ID", - "Order status", - "Date", - "Customer First name", - "Customer Last name", - "Customer Email", - "Customer ID", - "Shipping Address 1", - "Shipping Address 2", - "Shipping Country Code", - "Shipping City", - "Shipping Postal Code", - "Shipping Region ID", - "Fulfillment Status", - "Payment Status", - "Subtotal", - "Shipping Total", - "Discount Total", - "Gift Card Total", - "Refunded Total", - "Tax Total", - "Total", - "Currency Code\r\n", - ]) - }) - - it("should process the batch job and generate the appropriate output", async () => { - await orderExportStrategy.processJob(fakeJob.id) - - expect(outputDataStorage).toMatchSnapshot() - expect((fakeJob.result as any).file_key).toBeDefined() - }) - - it("should always provide a file_key even with no data", async () => { - const orderExportStrategy = new OrderExportStrategy({ - batchJobService: batchJobServiceMock as any, - fileService: fileServiceMock as any, - orderService: orderServiceWithoutDataMock as any, - manager: MockManager, - featureFlagRouter: new FlagRouter({}), - }) - - await orderExportStrategy.processJob(fakeJob.id) - - expect((fakeJob.result as any).file_key).toBeDefined() - }) -}) - -describe("Order export strategy with sales channel", () => { - const outputDataStorage: string[] = [] - - let fakeJob = { - id: IdMap.getId("order-export-job"), - type: "order-export", - context: { - params: {}, - list_config: { - select: [ - "id", - "display_id", - "status", - "created_at", - "fulfillment_status", - "payment_status", - "subtotal", - "shipping_total", - "discount_total", - "gift_card_total", - "refunded_total", - "tax_total", - "total", - "currency_code", - "region_id", - ], - relations: ["customer", "shipping_address", "sales_channel"], - }, - }, - created_by: IdMap.getId("order-export-job-creator"), - created_by_user: {} as User, - result: {}, - dry_run: false, - status: BatchJobStatus.PROCESSING, - } - - const fileServiceMock = { - delete: jest.fn(), - withTransaction: function () { - return this - }, - getUploadStreamDescriptor: jest.fn().mockImplementation(() => { - return Promise.resolve({ - writeStream: { - write: (data: string) => { - outputDataStorage.push(data) - }, - end: () => void 0, - }, - promise: Promise.resolve(), - fileKey: "order-export.csv", - }) - }), - } - const batchJobServiceMock = { - withTransaction: function (): any { - return this - }, - update: jest.fn().mockImplementation(async (job, data) => { - fakeJob = { - ...fakeJob, - ...data, - context: { ...fakeJob?.context, ...data?.context }, - result: { ...fakeJob?.result, ...data?.result } - } - return Promise.resolve(fakeJob) - }), - complete: jest.fn().mockImplementation(async () => { - fakeJob.status = BatchJobStatus.COMPLETED - return fakeJob - }), - retrieve: jest.fn().mockImplementation(async () => { - return fakeJob - }), - } - - const orderExportStrategy = new OrderExportStrategy({ - batchJobService: batchJobServiceMock as any, - fileService: fileServiceMock as any, - orderService: orderServiceMock as any, - manager: MockManager, - featureFlagRouter: new FlagRouter({ - [SalesChannelFeatureFlag.key]: true, - }), - }) - - it("Should generate header as template", async () => { - const template = await orderExportStrategy.buildTemplate() - expect(template.split(";")).toEqual([ - "Order_ID", - "Display_ID", - "Order status", - "Date", - "Customer First name", - "Customer Last name", - "Customer Email", - "Customer ID", - "Shipping Address 1", - "Shipping Address 2", - "Shipping Country Code", - "Shipping City", - "Shipping Postal Code", - "Shipping Region ID", - "Fulfillment Status", - "Payment Status", - "Subtotal", - "Shipping Total", - "Discount Total", - "Gift Card Total", - "Refunded Total", - "Tax Total", - "Total", - "Currency Code", - "Sales channel name", - "Sales channel description\r\n", - ]) - }) - - it("should process the batch job and generate the appropriate output", async () => { - await orderExportStrategy.processJob(fakeJob.id) - - expect(outputDataStorage).toMatchSnapshot() - expect((fakeJob.result as any).file_key).toBeDefined() - }) - - it("should always provide a file_key even with no data", async () => { - const orderExportStrategy = new OrderExportStrategy({ - batchJobService: batchJobServiceMock as any, - fileService: fileServiceMock as any, - orderService: orderServiceWithoutDataMock as any, - manager: MockManager, - featureFlagRouter: new FlagRouter({}), - }) - - await orderExportStrategy.processJob(fakeJob.id) - - expect((fakeJob.result as any).file_key).toBeDefined() - }) -}) \ No newline at end of file diff --git a/packages/medusa/src/strategies/__tests__/batch-jobs/price-list/import.ts b/packages/medusa/src/strategies/__tests__/batch-jobs/price-list/import.ts deleted file mode 100644 index 11b3758776..0000000000 --- a/packages/medusa/src/strategies/__tests__/batch-jobs/price-list/import.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { Readable, PassThrough } from "stream" -import { EntityManager } from "typeorm" - -import { FileService } from "medusa-interfaces" -import { MockManager } from "medusa-test-utils" - -import { User } from "../../../../models" -import { BatchJobStatus } from "../../../../types/batch-job" -import PriceListImportStrategy from "../../../batch-jobs/price-list/import" -import { - PriceListService, - BatchJobService, - ProductVariantService, - RegionService, -} from "../../../../services" -import { InjectedProps } from "../../../batch-jobs/price-list/types" - -let fakeJob = { - id: "batch_plimport", - type: "price-list-import", - context: { - price_list_id: "pl_1234", - fileKey: "csv.key", - }, - results: { advancement_count: 0, count: 6 }, - created_by: "usr_tester", - created_by_user: {} as User, - result: {}, - dry_run: false, - status: BatchJobStatus.PROCESSING, -} - -async function* generateCSVDataForStream() { - yield "Product Variant ID,SKU,Price EUR,Price NA [USD]\n" - yield ",MEDUSA-SWEAT-SMALL,15,13.5\n" - yield "5VxiEkmnPV,,15,13.5\n" -} - -/* ******************** SERVICES MOCK ******************** */ - -const fileServiceMock = { - withTransaction: function () { - return this - }, - delete: jest.fn(), - getDownloadStream: jest.fn().mockImplementation(() => { - return Promise.resolve(Readable.from(generateCSVDataForStream())) - }), - getUploadStreamDescriptor: jest.fn().mockImplementation(() => ({ - writeStream: new PassThrough(), - promise: Promise.resolve(), - })), -} - -const priceListServiceMock = { - withTransaction: function () { - return this - }, - retrieve: jest.fn().mockImplementation(() => { - return Promise.resolve(fakeJob) - }), -} - -const batchJobServiceMock = { - withTransaction: function () { - return this - }, - update: jest.fn().mockImplementation((data) => { - fakeJob = { - ...fakeJob, - ...data, - } - return Promise.resolve(fakeJob) - }), - complete: jest.fn().mockImplementation(() => { - fakeJob.status = BatchJobStatus.COMPLETED - return Promise.resolve(fakeJob) - }), - confirmed: jest.fn().mockImplementation(() => { - fakeJob.status = BatchJobStatus.CONFIRMED - return Promise.resolve(fakeJob) - }), - retrieve: jest.fn().mockImplementation(() => { - return Promise.resolve(fakeJob) - }), -} - -const productVariantServiceMock = { - withTransaction: function () { - return this - }, - retrieve: jest.fn().mockImplementation(() => - Promise.resolve({ - id: "retrieved-by-id", - }) - ), - retrieveBySKU: jest.fn().mockImplementation(() => - Promise.resolve({ - id: "retrieved-by-sku", - }) - ), -} - -const regionServiceMock = { - withTransaction: function () { - return this - }, - retrieveByName: jest.fn().mockImplementation(() => - Promise.resolve({ - id: "reg_HMnixPlOicAs7aBlXuchAGxd", - name: "Denmark", - currency_code: "DKK", - currency: "DKK", - tax_rate: 0.25, - tax_code: null, - countries: [ - { - id: "1001", - iso_2: "DK", - iso_3: "DNK", - num_code: "208", - name: "denmark", - display_name: "Denmark", - }, - ], - }) - ), -} - -const managerMock = MockManager - -/* ******************** PRICE LIST IMPORT STRATEGY TESTS ******************** */ - -describe("Price List import strategy", () => { - afterAll(() => { - jest.clearAllMocks() - }) - - const priceListImportStrategy = new PriceListImportStrategy({ - manager: managerMock as EntityManager, - fileService: fileServiceMock as typeof FileService, - batchJobService: batchJobServiceMock as unknown as BatchJobService, - priceListService: priceListServiceMock as unknown as PriceListService, - productVariantService: - productVariantServiceMock as unknown as ProductVariantService, - regionService: regionServiceMock as unknown as RegionService, - } as unknown as InjectedProps) - - it("`preProcessBatchJob` should generate import ops and upload them to a bucket using the file service", async () => { - const getImportInstructionsSpy = jest.spyOn( - priceListImportStrategy, - "getImportInstructions" - ) - - await priceListImportStrategy.preProcessBatchJob(fakeJob.id) - - expect(getImportInstructionsSpy).toBeCalledTimes(1) - expect(fileServiceMock.getUploadStreamDescriptor).toBeCalledTimes(1) - expect(fileServiceMock.getUploadStreamDescriptor).toHaveBeenCalledWith({ - ext: "json", - name: `imports/price-lists/ops/${fakeJob.id}-PRICE_LIST_PRICE_CREATE`, - }) - - getImportInstructionsSpy.mockRestore() - }) -}) diff --git a/packages/medusa/src/strategies/__tests__/batch-jobs/product/__snapshots__/export.ts.snap b/packages/medusa/src/strategies/__tests__/batch-jobs/product/__snapshots__/export.ts.snap deleted file mode 100644 index 7d82ff7ca4..0000000000 --- a/packages/medusa/src/strategies/__tests__/batch-jobs/product/__snapshots__/export.ts.snap +++ /dev/null @@ -1,36 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Product export strategy should process the batch job and generate the appropriate output 1`] = ` -Array [ - "Product Id;Product Handle;Product Title;Product Subtitle;Product Description;Product Status;Product Thumbnail;Product Weight;Product Length;Product Width;Product Height;Product HS Code;Product Origin Country;Product MID Code;Product Material;Product Collection Title;Product Collection Handle;Product Type;Product Tags;Product Discountable;Product External Id;Product Profile Name;Product Profile Type;Variant Id;Variant Title;Variant SKU;Variant Barcode;Variant Inventory Quantity;Variant Allow Backorder;Variant Manage Inventory;Variant Weight;Variant Length;Variant Width;Variant Height;Variant HS Code;Variant Origin Country;Variant MID Code;Variant Material;Price france [USD];Price USD;Price denmark [DKK];Price Denmark [DKK];Option 1 Name;Option 1 Value;Option 2 Name;Option 2 Value;Image 1 Url -", - "product-export-strategy-product-1;test-product-product-1;Test product;;\\"test-product-description-1 -test-product-description-1 second line -test-product-description-1 third line -forth line\\";draft;;;;;;;;;;Test collection 1;test-collection1;test-type-1;123_1;true;;profile_1;profile_type_1;product-export-strategy-variant-1;Test variant;test-sku;test-barcode;10;false;true;;;;;;;;;1;1.1;1.3;;test-option-1;option 1 value 1;test-option-2;option 2 value 1;test-image.png -", - "product-export-strategy-product-2;test-product-product-2;Test product;;test-product-description;draft;;;;;;;;;;Test collection;test-collection2;test-type;123;true;;profile_2;profile_type_2;product-export-strategy-variant-2;Test variant;test-sku;test-barcode;10;false;true;;;;;;;;;;;;1.1;test-option;Option 1 value 1;;;test-image.png -", - "product-export-strategy-product-2;test-product-product-2;Test product;;test-product-description;draft;;;;;;;;;;Test collection;test-collection2;test-type;123;true;;profile_2;profile_type_2;product-export-strategy-variant-3;Test variant;test-sku;test-barcode;10;false;true;;;;;;;;;;1.2;;;test-option;Option 1 Value 1;;;test-image.png -", -] -`; - -exports[`Product export strategy with sales Channels should process the batch job and generate the appropriate output 1`] = ` -Array [ - "Product Id;Product Handle;Product Title;Product Subtitle;Product Description;Product Status;Product Thumbnail;Product Weight;Product Length;Product Width;Product Height;Product HS Code;Product Origin Country;Product MID Code;Product Material;Product Collection Title;Product Collection Handle;Product Type;Product Tags;Product Discountable;Product External Id;Product Profile Name;Product Profile Type;Variant Id;Variant Title;Variant SKU;Variant Barcode;Variant Inventory Quantity;Variant Allow Backorder;Variant Manage Inventory;Variant Weight;Variant Length;Variant Width;Variant Height;Variant HS Code;Variant Origin Country;Variant MID Code;Variant Material;Price france [USD];Price USD;Price denmark [DKK];Price Denmark [DKK];Option 1 Name;Option 1 Value;Option 2 Name;Option 2 Value;Image 1 Url;Sales Channel 1 Id;Sales Channel 1 Name;Sales Channel 1 Description;Sales Channel 2 Id;Sales Channel 2 Name;Sales Channel 2 Description -", - "product-export-strategy-product-1;test-product-product-1;Test product;;\\"test-product-description-1 -test-product-description-1 second line -test-product-description-1 third line -forth line\\";draft;;;;;;;;;;Test collection 1;test-collection1;test-type-1;123_1;true;;profile_1;profile_type_1;product-export-strategy-variant-1;Test variant;test-sku;test-barcode;10;false;true;;;;;;;;;1;1.1;1.3;;test-option-1;option 1 value 1;test-option-2;option 2 value 1;test-image.png;SC 1;SC 1;\\"SC 1 -SC 1 second line -SC 1 third line -SC 1 forth line\\";;; -", - "product-export-strategy-product-2;test-product-product-2;Test product;;test-product-description;draft;;;;;;;;;;Test collection;test-collection2;test-type;123;true;;profile_2;profile_type_2;product-export-strategy-variant-2;Test variant;test-sku;test-barcode;10;false;true;;;;;;;;;;;;1.1;test-option;Option 1 value 1;;;test-image.png;SC 1;SC 1;SC 1;SC 2;SC 2;SC 2 -", - "product-export-strategy-product-2;test-product-product-2;Test product;;test-product-description;draft;;;;;;;;;;Test collection;test-collection2;test-type;123;true;;profile_2;profile_type_2;product-export-strategy-variant-3;Test variant;test-sku;test-barcode;10;false;true;;;;;;;;;;1.2;;;test-option;Option 1 Value 1;;;test-image.png;SC 1;SC 1;SC 1;SC 2;SC 2;SC 2 -", -] -`; diff --git a/packages/medusa/src/strategies/__tests__/batch-jobs/product/export.ts b/packages/medusa/src/strategies/__tests__/batch-jobs/product/export.ts deleted file mode 100644 index f410c72278..0000000000 --- a/packages/medusa/src/strategies/__tests__/batch-jobs/product/export.ts +++ /dev/null @@ -1,473 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { Request } from "express" -import { IdMap, MockManager } from "medusa-test-utils" -import { - AdminPostBatchesReq, - defaultAdminProductRelations, -} from "../../../../api" -import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" -import { User } from "../../../../models" -import { BatchJobStatus } from "../../../../types/batch-job" -import { productsToExport } from "../../../__fixtures__/product-export-data" -import ProductExportStrategy from "../../../batch-jobs/product/export" -import { ProductExportBatchJob } from "../../../batch-jobs/product/types" - -const productServiceMock = { - withTransaction: function () { - return this - }, - list: jest.fn().mockImplementation(() => Promise.resolve(productsToExport)), - - count: jest - .fn() - .mockImplementation(() => Promise.resolve(productsToExport.length)), - listAndCount: jest.fn().mockImplementation(() => { - return Promise.resolve([productsToExport, productsToExport.length]) - }), -} -const productServiceWithNoDataMock = { - ...productServiceMock, - list: jest.fn().mockImplementation(() => Promise.resolve([])), - count: jest.fn().mockImplementation(() => Promise.resolve(0)), - listAndCount: jest.fn().mockImplementation(() => { - return Promise.resolve([[], 0]) - }), -} -const managerMock = MockManager - -describe("Product export strategy", () => { - const outputDataStorage: string[] = [] - const fileServiceMock = { - delete: jest.fn(), - getUploadStreamDescriptor: jest.fn().mockImplementation(() => { - return Promise.resolve({ - writeStream: { - write: (data: string) => { - outputDataStorage.push(data) - }, - end: () => void 0, - }, - promise: Promise.resolve(), - fileKey: "product-export.csv", - }) - }), - withTransaction: function () { - return this - }, - } - let fakeJob = { - id: IdMap.getId("product-export-job"), - type: "product-export", - created_by: IdMap.getId("product-export-job-creator"), - created_by_user: {} as User, - context: {}, - result: {}, - dry_run: false, - status: BatchJobStatus.PROCESSING as BatchJobStatus, - } as ProductExportBatchJob - - let canceledFakeJob = { - ...fakeJob, - id: "bj_failed", - status: BatchJobStatus.CANCELED, - } as ProductExportBatchJob - - const batchJobServiceMock = { - withTransaction: function () { - return this - }, - update: jest.fn().mockImplementation((jobOrId, data) => { - if ((jobOrId?.id ?? jobOrId) === "bj_failed") { - canceledFakeJob = { - ...canceledFakeJob, - ...data, - context: { ...canceledFakeJob?.context, ...data?.context }, - result: { ...canceledFakeJob?.result, ...data?.result }, - } - - return Promise.resolve(canceledFakeJob) - } - - fakeJob = { - ...fakeJob, - ...data, - context: { ...fakeJob?.context, ...data?.context }, - result: { ...fakeJob?.result, ...data?.result }, - } - - return Promise.resolve(fakeJob) - }), - updateStatus: jest.fn().mockImplementation((status) => { - fakeJob.status = status - return Promise.resolve(fakeJob) - }), - complete: jest.fn().mockImplementation(() => { - fakeJob.status = BatchJobStatus.COMPLETED - return Promise.resolve(fakeJob) - }), - retrieve: jest.fn().mockImplementation((id) => { - const targetFakeJob = id === "bj_failed" ? canceledFakeJob : fakeJob - return Promise.resolve(targetFakeJob) - }), - setFailed: jest.fn().mockImplementation((...args) => { - console.error(...args) - }), - } - - const productExportStrategy = new ProductExportStrategy({ - manager: managerMock, - fileService: fileServiceMock as any, - batchJobService: batchJobServiceMock as any, - productService: productServiceMock as any, - featureFlagRouter: new FlagRouter({}), - remoteQuery: (() => {}) as any, - }) - - it("should generate the appropriate template", async () => { - await productExportStrategy.prepareBatchJobForProcessing( - fakeJob, - {} as Request - ) - await productExportStrategy.preProcessBatchJob(fakeJob.id) - const template = await productExportStrategy.buildHeader(fakeJob) - expect(template).toMatch(/.*Product Id.*/) - expect(template).toMatch(/.*Product Handle.*/) - expect(template).toMatch(/.*Product Title.*/) - expect(template).toMatch(/.*Product Subtitle.*/) - expect(template).toMatch(/.*Product Description.*/) - expect(template).toMatch(/.*Product Status.*/) - expect(template).toMatch(/.*Product Thumbnail.*/) - expect(template).toMatch(/.*Product Weight.*/) - expect(template).toMatch(/.*Product Length.*/) - expect(template).toMatch(/.*Product Width.*/) - expect(template).toMatch(/.*Product Height.*/) - expect(template).toMatch(/.*Product HS Code.*/) - expect(template).toMatch(/.*Product Origin Country.*/) - expect(template).toMatch(/.*Product MID Code.*/) - expect(template).toMatch(/.*Product Material.*/) - expect(template).toMatch(/.*Product Collection Title.*/) - expect(template).toMatch(/.*Product Collection Handle.*/) - expect(template).toMatch(/.*Product Type.*/) - expect(template).toMatch(/.*Product Tags.*/) - expect(template).toMatch(/.*Product Discountable.*/) - expect(template).toMatch(/.*Product External Id.*/) - expect(template).toMatch(/.*Product Profile Name.*/) - expect(template).toMatch(/.*Product Profile Type.*/) - expect(template).toMatch(/.*Product Profile Type.*/) - - expect(template).toMatch(/.*Variant Id.*/) - expect(template).toMatch(/.*Variant Title.*/) - expect(template).toMatch(/.*Variant SKU.*/) - expect(template).toMatch(/.*Variant Barcode.*/) - expect(template).toMatch(/.*Variant Allow Backorder.*/) - expect(template).toMatch(/.*Variant Manage Inventory.*/) - expect(template).toMatch(/.*Variant Weight.*/) - expect(template).toMatch(/.*Variant Length.*/) - expect(template).toMatch(/.*Variant Width.*/) - expect(template).toMatch(/.*Variant Height.*/) - expect(template).toMatch(/.*Variant HS Code.*/) - expect(template).toMatch(/.*Variant Origin Country.*/) - expect(template).toMatch(/.*Variant MID Code.*/) - expect(template).toMatch(/.*Variant Material.*/) - - expect(template).toMatch(/.*Option 1 Name.*/) - expect(template).toMatch(/.*Option 1 Value.*/) - expect(template).toMatch(/.*Option 2 Name.*/) - expect(template).toMatch(/.*Option 2 Value.*/) - - expect(template).not.toMatch(/.*Sales Channel 1 Id.*/) - expect(template).not.toMatch(/.*Sales Channel 1 Name.*/) - expect(template).not.toMatch(/.*Sales Channel 1 Description.*/) - expect(template).not.toMatch(/.*Sales Channel 2 Id.*/) - expect(template).not.toMatch(/.*Sales Channel 2 Name.*/) - expect(template).not.toMatch(/.*Sales Channel 2 Description.*/) - - expect(template).toMatch(/.*Price USD.*/) - expect(template).toMatch(/.*Price france \[USD\].*/) - expect(template).toMatch(/.*Price denmark \[DKK\].*/) - expect(template).toMatch(/.*Price Denmark \[DKK\].*/) - - expect(template).toMatch(/.*Image 1 Url.*/) - }) - - it("should process the batch job and generate the appropriate output", async () => { - await productExportStrategy.prepareBatchJobForProcessing( - fakeJob, - {} as Request - ) - await productExportStrategy.preProcessBatchJob(fakeJob.id) - await productExportStrategy.processJob(fakeJob.id) - expect(outputDataStorage).toMatchSnapshot() - expect((fakeJob.result as any).file_key).toBeDefined() - }) - - it("should prepare the job to be pre processed", async () => { - const fakeJob1: AdminPostBatchesReq = { - type: "product-export", - context: { - limit: 10, - offset: 10, - expand: "variants", - fields: "title", - order: "-title", - filterable_fields: { title: "test" }, - }, - dry_run: false, - } - - const output1 = await productExportStrategy.prepareBatchJobForProcessing( - fakeJob1, - {} as Express.Request - ) - - expect(output1.context).toEqual( - expect.objectContaining({ - list_config: { - select: ["title", "created_at", "id"], - order: { title: "DESC" }, - relations: ["variants"], - skip: 10, - take: 10, - }, - filterable_fields: { title: "test" }, - }) - ) - - const fakeJob2: AdminPostBatchesReq = { - type: "product-export", - context: {}, - dry_run: false, - } - - const output2 = await productExportStrategy.prepareBatchJobForProcessing( - fakeJob2, - {} as Express.Request - ) - - expect(output2.context).toEqual( - expect.objectContaining({ - list_config: { - select: undefined, - order: { created_at: "DESC" }, - relations: [ - ...defaultAdminProductRelations, - "variants.prices.region", - ], - skip: 0, - take: 50, - }, - filterable_fields: undefined, - }) - ) - }) - - it("should always provide a file_key even with no data", async () => { - const productExportStrategy = new ProductExportStrategy({ - batchJobService: batchJobServiceMock as any, - fileService: fileServiceMock as any, - productService: productServiceWithNoDataMock as any, - manager: MockManager, - featureFlagRouter: new FlagRouter({}), - remoteQuery: (() => {}) as any, - }) - - await productExportStrategy.prepareBatchJobForProcessing( - fakeJob, - {} as Request - ) - await productExportStrategy.preProcessBatchJob(fakeJob.id) - await productExportStrategy.processJob(fakeJob.id) - - expect((fakeJob.result as any).file_key).toBeDefined() - }) - - it("should remove the file_key and file_size if the job is canceled", async () => { - const productExportStrategy = new ProductExportStrategy({ - batchJobService: batchJobServiceMock as any, - fileService: fileServiceMock as any, - productService: productServiceMock as any, - manager: MockManager, - featureFlagRouter: new FlagRouter({}), - remoteQuery: (() => {}) as any, - }) - - await productExportStrategy.prepareBatchJobForProcessing( - canceledFakeJob, - {} as Request - ) - await productExportStrategy.preProcessBatchJob(canceledFakeJob.id) - await productExportStrategy.processJob(canceledFakeJob.id) - - expect((canceledFakeJob.result as any).file_key).not.toBeDefined() - expect((canceledFakeJob.result as any).file_size).not.toBeDefined() - }) -}) - -describe("Product export strategy with sales Channels", () => { - const outputDataStorage: string[] = [] - const fileServiceMock = { - delete: jest.fn(), - getUploadStreamDescriptor: jest.fn().mockImplementation(() => { - return Promise.resolve({ - writeStream: { - write: (data: string) => { - outputDataStorage.push(data) - }, - end: () => void 0, - }, - promise: Promise.resolve(), - fileKey: "product-export.csv", - }) - }), - withTransaction: function () { - return this - }, - } - let fakeJob = { - id: IdMap.getId("product-export-job"), - type: "product-export", - created_by: IdMap.getId("product-export-job-creator"), - created_by_user: {} as User, - context: {}, - result: {}, - dry_run: false, - status: BatchJobStatus.PROCESSING as BatchJobStatus, - } as ProductExportBatchJob - - let canceledFakeJob = { - ...fakeJob, - id: "bj_failed", - status: BatchJobStatus.CANCELED, - } as ProductExportBatchJob - - const batchJobServiceMock = { - withTransaction: function () { - return this - }, - update: jest.fn().mockImplementation((jobOrId, data) => { - if ((jobOrId?.id ?? jobOrId) === "bj_failed") { - canceledFakeJob = { - ...canceledFakeJob, - ...data, - context: { ...canceledFakeJob?.context, ...data?.context }, - result: { ...canceledFakeJob?.result, ...data?.result }, - } - - return Promise.resolve(canceledFakeJob) - } - - fakeJob = { - ...fakeJob, - ...data, - context: { ...fakeJob?.context, ...data?.context }, - result: { ...fakeJob?.result, ...data?.result }, - } - - return Promise.resolve(fakeJob) - }), - updateStatus: jest.fn().mockImplementation((status) => { - fakeJob.status = status - return Promise.resolve(fakeJob) - }), - complete: jest.fn().mockImplementation(() => { - fakeJob.status = BatchJobStatus.COMPLETED - return Promise.resolve(fakeJob) - }), - retrieve: jest.fn().mockImplementation((id) => { - const targetFakeJob = id === "bj_failed" ? canceledFakeJob : fakeJob - return Promise.resolve(targetFakeJob) - }), - setFailed: jest.fn().mockImplementation((...args) => { - console.error(...args) - }), - } - - const productExportStrategy = new ProductExportStrategy({ - manager: managerMock, - fileService: fileServiceMock as any, - batchJobService: batchJobServiceMock as any, - productService: productServiceMock as any, - remoteQuery: (() => {}) as any, - featureFlagRouter: new FlagRouter({ - [SalesChannelFeatureFlag.key]: true, - }), - }) - - it("should generate the appropriate template", async () => { - await productExportStrategy.prepareBatchJobForProcessing( - fakeJob, - {} as Request - ) - await productExportStrategy.preProcessBatchJob(fakeJob.id) - const template = await productExportStrategy.buildHeader(fakeJob) - expect(template).toMatch(/.*Product Id.*/) - expect(template).toMatch(/.*Product Handle.*/) - expect(template).toMatch(/.*Product Title.*/) - expect(template).toMatch(/.*Product Subtitle.*/) - expect(template).toMatch(/.*Product Description.*/) - expect(template).toMatch(/.*Product Status.*/) - expect(template).toMatch(/.*Product Thumbnail.*/) - expect(template).toMatch(/.*Product Weight.*/) - expect(template).toMatch(/.*Product Length.*/) - expect(template).toMatch(/.*Product Width.*/) - expect(template).toMatch(/.*Product Height.*/) - expect(template).toMatch(/.*Product HS Code.*/) - expect(template).toMatch(/.*Product Origin Country.*/) - expect(template).toMatch(/.*Product MID Code.*/) - expect(template).toMatch(/.*Product Material.*/) - expect(template).toMatch(/.*Product Collection Title.*/) - expect(template).toMatch(/.*Product Collection Handle.*/) - expect(template).toMatch(/.*Product Type.*/) - expect(template).toMatch(/.*Product Tags.*/) - expect(template).toMatch(/.*Product Discountable.*/) - expect(template).toMatch(/.*Product External Id.*/) - expect(template).toMatch(/.*Product Profile Name.*/) - expect(template).toMatch(/.*Product Profile Type.*/) - expect(template).toMatch(/.*Product Profile Type.*/) - - expect(template).toMatch(/.*Variant Id.*/) - expect(template).toMatch(/.*Variant Title.*/) - expect(template).toMatch(/.*Variant SKU.*/) - expect(template).toMatch(/.*Variant Barcode.*/) - expect(template).toMatch(/.*Variant Allow Backorder.*/) - expect(template).toMatch(/.*Variant Manage Inventory.*/) - expect(template).toMatch(/.*Variant Weight.*/) - expect(template).toMatch(/.*Variant Length.*/) - expect(template).toMatch(/.*Variant Width.*/) - expect(template).toMatch(/.*Variant Height.*/) - expect(template).toMatch(/.*Variant HS Code.*/) - expect(template).toMatch(/.*Variant Origin Country.*/) - expect(template).toMatch(/.*Variant MID Code.*/) - expect(template).toMatch(/.*Variant Material.*/) - - expect(template).toMatch(/.*Option 1 Name.*/) - expect(template).toMatch(/.*Option 1 Value.*/) - expect(template).toMatch(/.*Option 2 Name.*/) - expect(template).toMatch(/.*Option 2 Value.*/) - - expect(template).toMatch(/.*Price USD.*/) - expect(template).toMatch(/.*Price france \[USD\].*/) - expect(template).toMatch(/.*Price denmark \[DKK\].*/) - expect(template).toMatch(/.*Price Denmark \[DKK\].*/) - - expect(template).toMatch(/.*Sales Channel 1 Id.*/) - expect(template).toMatch(/.*Sales Channel 1 Name.*/) - expect(template).toMatch(/.*Sales Channel 1 Description.*/) - expect(template).toMatch(/.*Sales Channel 2 Id.*/) - expect(template).toMatch(/.*Sales Channel 2 Name.*/) - expect(template).toMatch(/.*Sales Channel 2 Description.*/) - - expect(template).toMatch(/.*Image 1 Url.*/) - }) - - it("should process the batch job and generate the appropriate output", async () => { - await productExportStrategy.prepareBatchJobForProcessing( - fakeJob, - {} as Request - ) - await productExportStrategy.preProcessBatchJob(fakeJob.id) - await productExportStrategy.processJob(fakeJob.id) - expect(outputDataStorage).toMatchSnapshot() - expect((fakeJob.result as any).file_key).toBeDefined() - }) -}) diff --git a/packages/medusa/src/strategies/__tests__/batch-jobs/product/import.ts b/packages/medusa/src/strategies/__tests__/batch-jobs/product/import.ts deleted file mode 100644 index d325ac26e2..0000000000 --- a/packages/medusa/src/strategies/__tests__/batch-jobs/product/import.ts +++ /dev/null @@ -1,195 +0,0 @@ -import { PassThrough, Readable } from "stream" -import { EntityManager } from "typeorm" - -import { FileService } from "medusa-interfaces" -import { IdMap, MockManager } from "medusa-test-utils" - -import { FlagRouter } from "@medusajs/utils" -import { User } from "../../../../models" -import { - BatchJobService, - ProductService, - ProductVariantService, - RegionService, - ShippingProfileService, -} from "../../../../services" -import { BatchJobStatus } from "../../../../types/batch-job" -import ProductImportStrategy from "../../../batch-jobs/product/import" -import { ProductImportInjectedProps } from "../../../batch-jobs/product/types" - -let fakeJob = { - id: IdMap.getId("product-import-job"), - type: "product-import", - context: { - csvFileKey: "csv.key", - }, - results: { advancement_count: 0, count: 6 }, - created_by: IdMap.getId("product-import-creator"), - created_by_user: {} as User, - result: {}, - dry_run: false, - status: BatchJobStatus.PROCESSING, -} - -async function* generateCSVDataForStream() { - yield "Product Id,Product Handle,Product Title,Product Subtitle,Product Description,Product Status,Product Thumbnail,Product Weight,Product Length,Product Width,Product Height,Product HS Code,Product Origin Country,Product MID Code,Product Material,Product Collection Title,Product Collection Handle,Product Type,Product Tags,Product Discountable,Product External Id,Variant Id,Variant Title,Variant SKU,Variant Barcode,Variant Inventory Quantity,Variant Allow Backorder,Variant Manage Inventory,Variant Weight,Variant Length,Variant Width,Variant Height,Variant HS Code,Variant Origin Country,Variant MID Code,Variant Material,Price france [USD],Price USD,Price denmark [DKK],Price Denmark [DKK],Option 1 Name,Option 1 Value,Option 2 Name,Option 2 Value,Image 1 Url\n" - yield ",test-product-product-1,Test product,,test-product-description-1,draft,,,,,,,,,,Test collection 1,test-collection1,test-type-1,123_1,TRUE,,SebniWTDeC,Test variant,test-sku-1,test-barcode-1,10,FALSE,TRUE,,,,,,,,,100,110,130,,test-option-1,option 1 value red,test-option-2,option 2 value 1,test-image.png\n" - yield "5VxiEkmnPV,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,,Test variant,test-sku-2,test-barcode-2,10,FALSE,TRUE,,,,,,,,,,,,110,test-option,Option 1 value 1,,,test-image.png\n" - yield "5VxiEkmnPV,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,3SS1MHGDEJ,Test variant,test-sku-3,test-barcode-3,10,FALSE,TRUE,,,,,,,,,,120,,,test-option,Option 1 Value blue,,,test-image.png\n" -} - -/* ******************** SERVICES MOCK ******************** */ - -const fileServiceMock = { - withTransaction: function () { - return this - }, - delete: jest.fn(), - getDownloadStream: jest.fn().mockImplementation(() => { - return Promise.resolve(Readable.from(generateCSVDataForStream())) - }), - getUploadStreamDescriptor: jest.fn().mockImplementation(() => ({ - writeStream: new PassThrough(), - promise: Promise.resolve(), - })), -} - -const batchJobServiceMock = { - withTransaction: function () { - return this - }, - update: jest.fn().mockImplementation((data) => { - fakeJob = { - ...fakeJob, - ...data, - } - return Promise.resolve(fakeJob) - }), - complete: jest.fn().mockImplementation(() => { - fakeJob.status = BatchJobStatus.COMPLETED - return Promise.resolve(fakeJob) - }), - confirmed: jest.fn().mockImplementation(() => { - fakeJob.status = BatchJobStatus.CONFIRMED - return Promise.resolve(fakeJob) - }), - retrieve: jest.fn().mockImplementation(() => { - return Promise.resolve(fakeJob) - }), -} - -const productServiceMock = { - withTransaction: function () { - return this - }, - count: jest.fn().mockImplementation(() => Promise.resolve()), -} - -const shippingProfileServiceMock = { - withTransaction: function () { - return this - }, - retrieveDefault: jest.fn().mockImplementation((_data) => { - return Promise.resolve({ id: "default_shipping_profile" }) - }), -} - -const productVariantServiceMock = { - withTransaction: function () { - return this - }, - count: jest.fn().mockImplementation(() => Promise.resolve()), -} - -const regionServiceMock = { - withTransaction: function () { - return this - }, - retrieveByName: jest.fn().mockImplementation(() => - Promise.resolve({ - id: "reg_HMnixPlOicAs7aBlXuchAGxd", - name: "Denmark", - currency_code: "DKK", - currency: "DKK", - tax_rate: 0.25, - tax_code: null, - countries: [ - { - id: "1001", - iso_2: "DK", - iso_3: "DNK", - num_code: "208", - name: "denmark", - display_name: "Denmark", - }, - ], - }) - ), -} - -const managerMock = MockManager - -/* ******************** PRODUCT IMPORT STRATEGY TESTS ******************** */ - -describe("Product import strategy", () => { - afterAll(() => { - jest.clearAllMocks() - }) - - const productImportStrategy = new ProductImportStrategy({ - manager: managerMock as EntityManager, - fileService: fileServiceMock as typeof FileService, - batchJobService: batchJobServiceMock as unknown as BatchJobService, - productService: productServiceMock as unknown as ProductService, - shippingProfileService: - shippingProfileServiceMock as unknown as ShippingProfileService, - productVariantService: - productVariantServiceMock as unknown as ProductVariantService, - regionService: regionServiceMock as unknown as RegionService, - featureFlagRouter: new FlagRouter({}), - } as unknown as ProductImportInjectedProps) - - it("`preProcessBatchJob` should generate import ops and upload them to a bucket using the file service", async () => { - const getImportInstructionsSpy = jest.spyOn( - productImportStrategy, - "getImportInstructions" - ) - - await productImportStrategy.preProcessBatchJob(fakeJob.id) - - expect(getImportInstructionsSpy).toBeCalledTimes(1) - - expect(fileServiceMock.getUploadStreamDescriptor).toBeCalledTimes(4) - - expect(fileServiceMock.getUploadStreamDescriptor).toHaveBeenNthCalledWith( - 1, - { - ext: "json", - name: `imports/products/ops/${fakeJob.id}-PRODUCT_CREATE`, - } - ) - expect(fileServiceMock.getUploadStreamDescriptor).toHaveBeenNthCalledWith( - 2, - { - ext: "json", - name: `imports/products/ops/${fakeJob.id}-VARIANT_CREATE`, - } - ) - expect(fileServiceMock.getUploadStreamDescriptor).toHaveBeenNthCalledWith( - 3, - { - ext: "json", - name: `imports/products/ops/${fakeJob.id}-PRODUCT_UPDATE`, - } - ) - expect(fileServiceMock.getUploadStreamDescriptor).toHaveBeenNthCalledWith( - 4, - { - ext: "json", - name: `imports/products/ops/${fakeJob.id}-VARIANT_UPDATE`, // because row data has variant.id - } - ) - - getImportInstructionsSpy.mockRestore() - }) -}) diff --git a/packages/medusa/src/strategies/__tests__/cart-completion.js b/packages/medusa/src/strategies/__tests__/cart-completion.js deleted file mode 100644 index da12054993..0000000000 --- a/packages/medusa/src/strategies/__tests__/cart-completion.js +++ /dev/null @@ -1,244 +0,0 @@ -import { MockManager } from "medusa-test-utils" -import CartCompletionStrategy from "../cart-completion" -import { newTotalsServiceMock } from "../../services/__mocks__/new-totals" -import { ProductVariantInventoryServiceMock } from "../../services/__mocks__/product-variant-inventory" - -const IdempotencyKeyServiceMock = { - withTransaction: function () { - return this - }, - workStage: jest.fn().mockImplementation(async (key, fn) => { - const { recovery_point, response_code, response_body } = await fn( - MockManager - ) - - const data = { - recovery_point: recovery_point ?? "finished", - } - - if (!recovery_point) { - data.response_body = response_body - data.response_code = response_code - } - - return { - ...data, - idempotency_key: key, - } - }), - update: jest.fn().mockImplementation((key, data) => { - return data - }), -} - -const toTest = [ - [ - "succeeds", - { - cart: { - id: "test-cart", - items: [{ id: "item", tax_lines: [] }], - payment: { data: "some-data" }, - payment_session: { status: "authorized" }, - total: 1000, - region_id: "testRegion", - }, - idempotencyKey: { - id: "ikey", - idempotency_key: "ikey", - recovery_point: "started", - }, - validate: function (value, { cartServiceMock, orderServiceMock }) { - expect(value.response_code).toEqual(200) - expect(value.response_body).toEqual({ - data: expect.any(Object), - type: "order", - }) - - expect(cartServiceMock.createTaxLines).toHaveBeenCalledTimes(3) - expect(cartServiceMock.createTaxLines).toHaveBeenCalledWith( - expect.objectContaining({ id: "test-cart" }) - ) - - expect(cartServiceMock.authorizePayment).toHaveBeenCalledTimes(1) - expect(cartServiceMock.authorizePayment).toHaveBeenCalledWith( - "test-cart", - { - idempotency_key: { - idempotency_key: "ikey", - recovery_point: "tax_lines_created", - }, - } - ) - - expect(orderServiceMock.createFromCart).toHaveBeenCalledTimes(1) - expect(orderServiceMock.createFromCart).toHaveBeenCalledWith( - expect.objectContaining({ id: "test-cart" }) - ) - - expect(orderServiceMock.retrieveWithTotals).toHaveBeenCalledTimes(1) - expect(orderServiceMock.retrieveWithTotals).toHaveBeenCalledWith( - "test-cart", - { - relations: ["shipping_address", "items", "payments"], - } - ) - }, - }, - ], - [ - "succeeds", - { - cart: { - id: "test-cart", - items: [{ id: "item", tax_lines: [] }], - completed_at: "2021-01-02", - payment: { data: "some-data" }, - payment_session: { status: "authorized" }, - total: 1000, - region_id: "testRegion", - }, - idempotencyKey: { - id: "ikey", - idempotency_key: "ikey", - recovery_point: "started", - }, - validate: function (value, { orderServiceMock }) { - expect(value.response_code).toEqual(200) - expect( - orderServiceMock.retrieveByCartIdWithTotals - ).toHaveBeenCalledTimes(1) - expect( - orderServiceMock.retrieveByCartIdWithTotals - ).toHaveBeenCalledWith("test-cart", { - relations: ["shipping_address", "items", "payments"], - }) - }, - }, - ], - [ - "returns requires more", - { - cart: { - id: "test-cart", - items: [{ id: "item", tax_lines: [] }], - payment: { data: "some-data" }, - payment_session: { status: "requires_more" }, - total: 1000, - region_id: "testRegion", - }, - idempotencyKey: { - id: "ikey", - idempotency_key: "ikey", - recovery_point: "started", - }, - validate: function (value) { - expect(value.response_code).toEqual(200) - expect(value.response_body).toEqual({ - data: expect.any(Object), - payment_status: "requires_more", - type: "cart", - }) - }, - }, - ], - [ - "creates swap", - { - cart: { - id: "test-cart", - type: "swap", - items: [{ id: "item", tax_lines: [] }], - payment: { data: "some-data" }, - payment_session: { status: "authorized" }, - total: 1000, - region_id: "testRegion", - metadata: { swap_id: "testswap" }, - }, - idempotencyKey: { - id: "ikey", - idempotency_key: "ikey", - recovery_point: "started", - }, - validate: function (value, { swapServiceMock }) { - expect(value.response_code).toEqual(200) - expect(value.response_body).toEqual({ - data: expect.any(Object), - type: "swap", - }) - - expect(swapServiceMock.registerCartCompletion).toHaveBeenCalledTimes(1) - expect(swapServiceMock.registerCartCompletion).toHaveBeenCalledWith( - "testswap" - ) - }, - }, - ], -] - -describe("CartCompletionStrategy", () => { - describe("complete", () => { - test.each(toTest)( - "%s", - async (title, { cart, idempotencyKey, validate }) => { - const cartServiceMock = { - withTransaction: function () { - return this - }, - createTaxLines: jest.fn(() => { - cart.items[0].tax_lines = [ - { - id: "tax_lines", - }, - ] - return Promise.resolve(cart) - }), - deleteTaxLines: jest.fn(() => Promise.resolve(cart)), - authorizePayment: jest.fn(() => Promise.resolve(cart)), - retrieve: jest.fn(() => Promise.resolve(cart)), - retrieveWithTotals: jest.fn(() => Promise.resolve(cart)), - newTotalsService: newTotalsServiceMock, - } - const orderServiceMock = { - withTransaction: function () { - return this - }, - createFromCart: jest.fn(() => Promise.resolve(cart)), - retrieve: jest.fn(() => Promise.resolve({})), - retrieveWithTotals: jest.fn(() => Promise.resolve({})), - retrieveByCartIdWithTotals: jest.fn(() => Promise.resolve({})), - newTotalsService: newTotalsServiceMock, - } - const swapServiceMock = { - withTransaction: function () { - return this - }, - retrieveByCartId: jest.fn((id) => - Promise.resolve({ id, allow_backorder: true }) - ), - registerCartCompletion: jest.fn(() => Promise.resolve({})), - retrieve: jest.fn(() => Promise.resolve({})), - } - const idempotencyKeyServiceMock = IdempotencyKeyServiceMock - - const completionStrat = new CartCompletionStrategy({ - productVariantInventoryService: ProductVariantInventoryServiceMock, - cartService: cartServiceMock, - idempotencyKeyService: idempotencyKeyServiceMock, - orderService: orderServiceMock, - swapService: swapServiceMock, - manager: MockManager, - }) - - const val = await completionStrat.complete(cart.id, idempotencyKey, {}) - - validate(val, { - cartServiceMock, - orderServiceMock, - swapServiceMock, - idempotencyKeyServiceMock, - }) - } - ) - }) -}) diff --git a/packages/medusa/src/strategies/__tests__/price-selection.js b/packages/medusa/src/strategies/__tests__/price-selection.js deleted file mode 100644 index 899629d305..0000000000 --- a/packages/medusa/src/strategies/__tests__/price-selection.js +++ /dev/null @@ -1,890 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import PriceSelectionStrategy from "../price-selection" -import { cacheServiceMock } from "../../services/__mocks__/cache" -import TaxInclusivePricingFeatureFlag from "../../loaders/feature-flags/tax-inclusive-pricing" - -const executeTest = - (flagValue) => - async (title, { variant_id, context, validate, validateException }) => { - const mockMoneyAmountRepository = { - findManyForVariantsInRegion: jest - .fn() - .mockImplementation( - async ( - [variant_id], - region_id, - currency_code, - customer_id, - useDiscountPrices - ) => { - if (variant_id === "test-basic-variant") { - return [ - { - [variant_id]: [ - { - amount: 100, - region_id, - currency_code, - price_list_id: null, - max_quantity: null, - min_quantity: null, - }, - ], - }, - 1, - ] - } - if (variant_id === "test-basic-variant-tax-inclusive") { - return [ - { - [variant_id]: [ - { - amount: 100, - region_id, - price_list_id: null, - max_quantity: null, - min_quantity: null, - region: { - includes_tax: true, - }, - }, - { - amount: 120, - currency_code, - price_list_id: null, - max_quantity: null, - min_quantity: null, - currency: { - includes_tax: true, - }, - }, - ], - }, - 1, - ] - } - - if (variant_id === "test-basic-variant-tax-inclusive-currency") { - return [ - { - [variant_id]: [ - { - amount: 100, - region_id, - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - { - amount: 100, - currency_code, - price_list_id: null, - max_quantity: null, - min_quantity: null, - currency: { - includes_tax: true, - }, - }, - ], - }, - 1, - ] - } - - if (variant_id === "test-basic-variant-tax-inclusive-region") { - return [ - { - [variant_id]: [ - { - amount: 100, - region_id, - max_quantity: null, - min_quantity: null, - price_list_id: null, - region: { - includes_tax: true, - }, - }, - { - amount: 100, - currency_code, - price_list_id: null, - max_quantity: null, - min_quantity: null, - }, - ], - }, - 1, - ] - } - - if (variant_id === "test-basic-variant-mixed") { - return [ - { - [variant_id]: [ - { - amount: 100, - region_id, - max_quantity: null, - min_quantity: null, - price_list_id: null, - region: { - includes_tax: false, - }, - }, - { - amount: 95, - currency_code, - price_list_id: "pl_1", - max_quantity: null, - min_quantity: null, - price_list: { type: "sale" }, - }, - { - amount: 110, - currency_code, - price_list_id: "pl_2", - max_quantity: null, - min_quantity: null, - price_list: { type: "sale", includes_tax: true }, - }, - { - amount: 150, - currency_code, - price_list_id: "pl_3", - max_quantity: null, - min_quantity: null, - price_list: { type: "sale" }, - }, - ], - }, - 1, - ] - } - - if (customer_id === "test-customer-1") { - return [ - { - [variant_id]: [ - { - amount: 100, - region_id, - currency_code, - price_list_id: null, - max_quantity: null, - min_quantity: null, - }, - { - amount: 50, - region_id: region_id, - currency_code: currency_code, - price_list: { type: "sale" }, - max_quantity: null, - min_quantity: null, - }, - ], - }, - 2, - ] - } - if (customer_id === "test-customer-2") { - return [ - { - [variant_id]: [ - { - amount: 100, - region_id, - currency_code, - price_list_id: null, - max_quantity: null, - min_quantity: null, - }, - { - amount: 30, - min_quantity: 10, - max_quantity: 12, - price_list: { type: "sale" }, - region_id: region_id, - currency_code: currency_code, - }, - { - amount: 20, - min_quantity: 3, - max_quantity: 5, - price_list: { type: "sale" }, - region_id: region_id, - currency_code: currency_code, - }, - { - amount: 50, - min_quantity: 5, - max_quantity: 10, - price_list: { type: "sale" }, - region_id: region_id, - currency_code: currency_code, - }, - ], - }, - 4, - ] - } - - return [] - } - ), - } - - const mockEntityManager = { - withRepository: (repotype) => mockMoneyAmountRepository, - } - - const featureFlagRouter = new FlagRouter({ - tax_inclusive_pricing: flagValue, - }) - - const selectionStrategy = new PriceSelectionStrategy({ - manager: mockEntityManager, - moneyAmountRepository: mockMoneyAmountRepository, - featureFlagRouter, - cacheService: cacheServiceMock, - }) - - try { - const context_ = { ...context } - const quantity = context_.quantity - delete context_.quantity - - const val = await selectionStrategy.calculateVariantPrice( - [{ variantId: variant_id, quantity }], - context_ - ) - - validate(val, { mockMoneyAmountRepository, featureFlagRouter }) - } catch (error) { - if (typeof validateException === "function") { - validateException(error, { mockMoneyAmountRepository }) - } else { - throw error - } - } - } - -const toTest = [ - [ - "Variant with only default price", - { - variant_id: "test-basic-variant", - context: { - region_id: "test-region", - currency_code: "dkk", - }, - validate: (value, { mockMoneyAmountRepository, featureFlagRouter }) => { - let ffFields = {} - if (featureFlagRouter.isFeatureEnabled("tax_inclusive_pricing")) { - ffFields = { - originalPriceIncludesTax: false, - calculatedPriceIncludesTax: false, - } - } - - const variantId = "test-basic-variant" - - if ( - featureFlagRouter.isFeatureEnabled(TaxInclusivePricingFeatureFlag.key) - ) { - expect( - mockMoneyAmountRepository.findManyForVariantsInRegion - ).toHaveBeenCalledWith( - [variantId], - "test-region", - "dkk", - undefined, - undefined, - true - ) - } else { - expect( - mockMoneyAmountRepository.findManyForVariantsInRegion - ).toHaveBeenCalledWith( - [variantId], - "test-region", - "dkk", - undefined, - undefined - ) - } - - expect(value.get(variantId)).toEqual({ - ...ffFields, - originalPrice: 100, - calculatedPrice: 100, - calculatedPriceType: "default", - prices: [ - { - amount: 100, - region_id: "test-region", - currency_code: "dkk", - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - ], - }) - }, - }, - ], - [ - "findManyForVariantsInRegion is invoked with the correct customer", - { - variant_id: "test-variant", - context: { - region_id: "test-region", - currency_code: "dkk", - customer_id: "test-customer-1", - }, - validate: (value, { mockMoneyAmountRepository, featureFlagRouter }) => { - if ( - featureFlagRouter.isFeatureEnabled(TaxInclusivePricingFeatureFlag.key) - ) { - expect( - mockMoneyAmountRepository.findManyForVariantsInRegion - ).toHaveBeenCalledWith( - ["test-variant"], - "test-region", - "dkk", - "test-customer-1", - undefined, - true - ) - } else { - expect( - mockMoneyAmountRepository.findManyForVariantsInRegion - ).toHaveBeenCalledWith( - ["test-variant"], - "test-region", - "dkk", - "test-customer-1", - undefined - ) - } - }, - }, - ], - [ - "Lowest valid price is returned", - { - variant_id: "test-variant", - context: { - region_id: "test-region", - currency_code: "dkk", - customer_id: "test-customer-1", - }, - validate: (value, { mockMoneyAmountRepository, featureFlagRouter }) => { - let ffFields = {} - if (featureFlagRouter.isFeatureEnabled("tax_inclusive_pricing")) { - ffFields = { - originalPriceIncludesTax: false, - calculatedPriceIncludesTax: false, - } - } - expect(value.get("test-variant")).toEqual({ - ...ffFields, - originalPrice: 100, - calculatedPrice: 50, - calculatedPriceType: "sale", - prices: [ - { - amount: 100, - region_id: "test-region", - currency_code: "dkk", - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - { - amount: 50, - region_id: "test-region", - currency_code: "dkk", - price_list: { type: "sale" }, - max_quantity: null, - min_quantity: null, - }, - ], - }) - }, - }, - ], - [ - "Prices with quantity limits are ignored with no provided quantity", - { - variant_id: "test-variant", - context: { - region_id: "test-region", - currency_code: "dkk", - customer_id: "test-customer-2", - }, - validate: (value, { mockMoneyAmountRepository, featureFlagRouter }) => { - let ffFields = {} - if (featureFlagRouter.isFeatureEnabled("tax_inclusive_pricing")) { - ffFields = { - originalPriceIncludesTax: false, - calculatedPriceIncludesTax: false, - } - } - expect(value.get("test-variant")).toEqual({ - ...ffFields, - originalPrice: 100, - calculatedPrice: 100, - calculatedPriceType: "default", - prices: [ - { - amount: 100, - region_id: "test-region", - currency_code: "dkk", - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - { - amount: 30, - min_quantity: 10, - max_quantity: 12, - region_id: "test-region", - price_list: { type: "sale" }, - currency_code: "dkk", - }, - { - amount: 20, - min_quantity: 3, - max_quantity: 5, - price_list: { type: "sale" }, - region_id: "test-region", - currency_code: "dkk", - }, - { - amount: 50, - min_quantity: 5, - max_quantity: 10, - price_list: { type: "sale" }, - region_id: "test-region", - currency_code: "dkk", - }, - ], - }) - }, - }, - ], - [ - "Prices With quantity limits are applied correctly when a quantity is provided", - { - variant_id: "test-variant", - context: { - region_id: "test-region", - currency_code: "dkk", - customer_id: "test-customer-2", - quantity: 7, - }, - validate: (value, { mockMoneyAmountRepository, featureFlagRouter }) => { - let ffFields = {} - if (featureFlagRouter.isFeatureEnabled("tax_inclusive_pricing")) { - ffFields = { - originalPriceIncludesTax: false, - calculatedPriceIncludesTax: false, - } - } - expect(value.get("test-variant")).toEqual({ - ...ffFields, - originalPrice: 100, - calculatedPrice: 50, - calculatedPriceType: "sale", - prices: [ - { - amount: 100, - region_id: "test-region", - currency_code: "dkk", - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - { - amount: 30, - min_quantity: 10, - max_quantity: 12, - region_id: "test-region", - price_list: { type: "sale" }, - currency_code: "dkk", - }, - { - amount: 20, - min_quantity: 3, - max_quantity: 5, - price_list: { type: "sale" }, - region_id: "test-region", - currency_code: "dkk", - }, - { - amount: 50, - min_quantity: 5, - max_quantity: 10, - price_list: { type: "sale" }, - region_id: "test-region", - currency_code: "dkk", - }, - ], - }) - }, - }, - ], - [ - "Prices with quantity are in prices array with no quantity set", - { - variant_id: "test-variant", - context: { - region_id: "test-region", - currency_code: "dkk", - customer_id: "test-customer-2", - }, - validate: (value, { mockMoneyAmountRepository, featureFlagRouter }) => { - let ffFields = {} - if (featureFlagRouter.isFeatureEnabled("tax_inclusive_pricing")) { - ffFields = { - originalPriceIncludesTax: false, - calculatedPriceIncludesTax: false, - } - } - expect(value.get("test-variant")).toEqual({ - ...ffFields, - originalPrice: 100, - calculatedPrice: 100, - calculatedPriceType: "default", - prices: [ - { - amount: 100, - region_id: "test-region", - currency_code: "dkk", - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - { - amount: 30, - min_quantity: 10, - max_quantity: 12, - region_id: "test-region", - price_list: { type: "sale" }, - currency_code: "dkk", - }, - { - amount: 20, - min_quantity: 3, - max_quantity: 5, - region_id: "test-region", - price_list: { type: "sale" }, - currency_code: "dkk", - }, - { - amount: 50, - min_quantity: 5, - max_quantity: 10, - region_id: "test-region", - price_list: { type: "sale" }, - currency_code: "dkk", - }, - ], - }) - }, - }, - ], -] - -const taxInclusiveTesting = [ - [ - "Variant with tax inclusive prices", - { - variant_id: "test-basic-variant-tax-inclusive", - context: { - region_id: "test-region", - currency_code: "dkk", - }, - validate: (value, { mockMoneyAmountRepository, featureFlagRouter }) => { - const variantId = "test-basic-variant-tax-inclusive" - - expect( - mockMoneyAmountRepository.findManyForVariantsInRegion - ).toHaveBeenCalledWith( - [variantId], - "test-region", - "dkk", - undefined, - undefined, - true - ) - - expect(value.get(variantId)).toEqual({ - originalPrice: 100, - calculatedPrice: 100, - originalPriceIncludesTax: true, - calculatedPriceIncludesTax: true, - calculatedPriceType: "default", - prices: [ - { - amount: 100, - max_quantity: null, - min_quantity: null, - price_list_id: null, - region_id: "test-region", - }, - { - amount: 120, - currency_code: "dkk", - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - ], - }) - }, - }, - ], - [ - "Variant with mixed pricing tax inclusive prices currency", - { - variant_id: "test-basic-variant-tax-inclusive-currency", - context: { - region_id: "test-region", - currency_code: "dkk", - tax_rates: [{ rate: 25 }], - }, - validate: (value, { mockMoneyAmountRepository, featureFlagRouter }) => { - const variantId = "test-basic-variant-tax-inclusive-currency" - - expect( - mockMoneyAmountRepository.findManyForVariantsInRegion - ).toHaveBeenCalledWith( - [variantId], - "test-region", - "dkk", - undefined, - undefined, - true - ) - - expect(value.get(variantId)).toEqual({ - originalPrice: 100, - calculatedPrice: 100, - originalPriceIncludesTax: false, - calculatedPriceIncludesTax: true, - calculatedPriceType: "default", - prices: [ - { - amount: 100, - region_id: "test-region", - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - { - amount: 100, - currency_code: "dkk", - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - ], - }) - }, - }, - ], - [ - "Variant with mixed pricing tax inclusive prices region", - { - variant_id: "test-basic-variant-tax-inclusive-region", - context: { - region_id: "test-region", - currency_code: "dkk", - tax_rates: [{ rate: 25 }], - }, - validate: (value, { mockMoneyAmountRepository, featureFlagRouter }) => { - const variantId = "test-basic-variant-tax-inclusive-region" - - expect( - mockMoneyAmountRepository.findManyForVariantsInRegion - ).toHaveBeenCalledWith( - [variantId], - "test-region", - "dkk", - undefined, - undefined, - true - ) - expect(value.get(variantId)).toEqual({ - originalPrice: 100, - calculatedPrice: 100, - originalPriceIncludesTax: true, - calculatedPriceIncludesTax: true, - calculatedPriceType: "default", - prices: [ - { - amount: 100, - region_id: "test-region", - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - { - amount: 100, - currency_code: "dkk", - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - ], - }) - }, - }, - ], - [ - "Variant with mixed tax prices (favoring tax inclusive)", - { - variant_id: "test-basic-variant-mixed", - context: { - region_id: "test-region", - currency_code: "dkk", - tax_rates: [{ rate: 25 }], - }, - validate: (value, { mockMoneyAmountRepository }) => { - const variantId = "test-basic-variant-mixed" - - expect( - mockMoneyAmountRepository.findManyForVariantsInRegion - ).toHaveBeenCalledWith( - [variantId], - "test-region", - "dkk", - undefined, - undefined, - true - ) - expect(value.get(variantId)).toEqual({ - originalPrice: 100, - calculatedPrice: 110, - originalPriceIncludesTax: false, - calculatedPriceIncludesTax: true, - calculatedPriceType: "sale", - prices: [ - { - amount: 100, - region_id: "test-region", - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - { - amount: 95, - currency_code: "dkk", - price_list_id: "pl_1", - max_quantity: null, - min_quantity: null, - price_list: { type: "sale" }, - }, - { - amount: 110, - currency_code: "dkk", - price_list_id: "pl_2", - max_quantity: null, - min_quantity: null, - price_list: { type: "sale", includes_tax: true }, - }, - { - amount: 150, - currency_code: "dkk", - price_list_id: "pl_3", - max_quantity: null, - min_quantity: null, - price_list: { type: "sale" }, - }, - ], - }) - }, - }, - ], - [ - "Variant with mixed tax price (favoring tax exclusive)", - { - variant_id: "test-basic-variant-mixed", - context: { - region_id: "test-region", - currency_code: "dkk", - tax_rate: 0.05, - }, - validate: (value, { mockMoneyAmountRepository }) => { - const variantId = "test-basic-variant-mixed" - - expect( - mockMoneyAmountRepository.findManyForVariantsInRegion - ).toHaveBeenCalledWith( - [variantId], - "test-region", - "dkk", - undefined, - undefined, - true - ) - - expect(value.get(variantId)).toEqual({ - originalPrice: 100, - calculatedPrice: 95, - originalPriceIncludesTax: false, - calculatedPriceIncludesTax: false, - calculatedPriceType: "sale", - prices: [ - { - amount: 100, - region_id: "test-region", - max_quantity: null, - min_quantity: null, - price_list_id: null, - }, - { - amount: 95, - currency_code: "dkk", - price_list_id: "pl_1", - max_quantity: null, - min_quantity: null, - price_list: { type: "sale" }, - }, - { - amount: 110, - currency_code: "dkk", - price_list_id: "pl_2", - max_quantity: null, - min_quantity: null, - price_list: { type: "sale", includes_tax: true }, - }, - { - amount: 150, - currency_code: "dkk", - price_list_id: "pl_3", - max_quantity: null, - min_quantity: null, - price_list: { type: "sale" }, - }, - ], - }) - }, - }, - ], -] - -describe("PriceSelectionStrategy", () => { - describe("calculateVariantPrice", () => { - ;[true, false].forEach((flagValue) => { - describe(`with tax inclusive pricing ${flagValue}`, () => { - test.each(toTest)(`%s`, executeTest(flagValue)) - }) - }) - /* describe("tax inclusive testing", () => { - test.each(taxInclusiveTesting)(`%s`, executeTest(true)) - })*/ - }) -}) diff --git a/packages/medusa/src/strategies/__tests__/tax-calculation.js b/packages/medusa/src/strategies/__tests__/tax-calculation.js deleted file mode 100644 index 241c4b7ab1..0000000000 --- a/packages/medusa/src/strategies/__tests__/tax-calculation.js +++ /dev/null @@ -1,285 +0,0 @@ -import TaxCalculationStrategy from "../tax-calculation" -import TaxInclusivePricingFeatureFlag from "../../loaders/feature-flags/tax-inclusive-pricing" -import { FlagRouter } from "@medusajs/utils" - -const toTest = [ - [ - "calculates correctly without gift card", - { - /* - * Subtotal = 2 * 100 = 200 - * Taxable amount = 200 - 10 = 190 - * Taxline 1 = 190 * 0.0825 = 15.675 = 16 - * Taxline 2 = 190 * 0.125 = 13.75 = 14 - * Total tax = 40 - */ - expected: 40, - items: [ - { - id: "item_1", - unit_price: 100, - quantity: 2, - }, - ], - taxLines: [ - { - item_id: "item_1", - name: "Name 1", - rate: 8.25, - }, - { - item_id: "item_1", - name: "Name 2", - rate: 12.5, - }, - ], - context: { - shipping_address: null, - customer: { - email: "test@testson.com", - }, - shipping_methods: [], - region: { - gift_cards_taxable: false, - }, - allocation_map: { - item_1: { - discount: { - amount: 10, - unit_amount: 5, - }, - gift_card: { - amount: 10, - unit_amount: 5, - }, - }, - }, - }, - }, - ], - [ - "calculates correctly with gift card", - { - /* - * Subtotal = 2 * 100 = 200 - * Taxable amount = 200 - 10 = 180 - * Taxline 1 = 180 * 0.0825 = 15 - * Taxline 2 = 180 * 0.125 = 23 - * Total tax = 38 - */ - expected: 40, - items: [ - { - id: "item_1", - unit_price: 100, - quantity: 2, - }, - ], - taxLines: [ - { - item_id: "item_1", - name: "Name 1", - rate: 8.25, - }, - { - item_id: "item_1", - name: "Name 2", - rate: 12.5, - }, - ], - context: { - shipping_address: null, - customer: { - email: "test@testson.com", - }, - region: { - gift_cards_taxable: true, - }, - shipping_methods: [], - allocation_map: { - item_1: { - discount: { - amount: 10, - unit_amount: 5, - }, - gift_card: { - amount: 10, - unit_amount: 5, - }, - }, - }, - }, - }, - ], - [ - "calculates correctly with tax inclusive pricing", - { - /* - * Subtotal = 3 * 100 = 100 - * Taxable amount = 300 - * Taxline 1 = 100 * 0.2 * 2 = 40 - * Taxline 2 = 100 * 0.2 * 1 = 20 - * Total tax = 60 - */ - expected: 60, - flags: { [TaxInclusivePricingFeatureFlag.key]: true }, - items: [ - { - id: "item_1", - unit_price: 120, - quantity: 2, - includes_tax: true, - }, - { - id: "item_2", - unit_price: 100, - quantity: 1, - includes_tax: false, - }, - ], - taxLines: [ - { - item_id: "item_1", - name: "Name 1", - rate: 20, - }, - { - item_id: "item_2", - name: "Name 2", - rate: 20, - }, - ], - context: { - shipping_address: null, - customer: { - email: "test@testson.com", - }, - region: { - gift_cards_taxable: true, - }, - shipping_methods: [], - allocation_map: {}, - }, - }, - ], - [ - "calculates correctly with tax inclusive shipping", - { - expected: 40, - flags: { [TaxInclusivePricingFeatureFlag.key]: true }, - items: [ - { - id: "item_1", - unit_price: 120, - quantity: 1, - includes_tax: true, - }, - ], - taxLines: [ - { - shipping_method_id: "shipping_method_1", - name: "Name 1", - rate: 15, - }, - { - shipping_method_id: "shipping_method_2", - name: "Name 2", - rate: 5, - }, - { - item_id: "item_1", - name: "Name 1", - rate: 20, - }, - ], - context: { - shipping_address: null, - customer: { - email: "test@testson.com", - }, - region: { - gift_cards_taxable: true, - }, - shipping_methods: [ - { id: "shipping_method_1", price: 115, includes_tax: true }, - { id: "shipping_method_2", price: 105, includes_tax: true }, - ], - allocation_map: {}, - }, - }, - ], - [ - "calculates correctly with tax inclusive pricing and shipping", - { - expected: 85, - flags: { [TaxInclusivePricingFeatureFlag.key]: true }, - items: [ - { - id: "item_1", - unit_price: 120, - quantity: 2, - includes_tax: true, - }, - { - id: "item_2", - unit_price: 100, - quantity: 1, - includes_tax: false, - }, - ], - taxLines: [ - { - shipping_method_id: "shipping_method_1", - name: "Name 1", - rate: 15, - }, - { - shipping_method_id: "shipping_method_2", - name: "Name 2", - rate: 10, - }, - { - item_id: "item_1", - name: "Name 1", - rate: 20, - }, - { - item_id: "item_2", - name: "Name 2", - rate: 20, - }, - ], - context: { - shipping_address: null, - customer: { - email: "test@testson.com", - }, - region: { - gift_cards_taxable: true, - }, - shipping_methods: [ - { id: "shipping_method_1", price: 115, includes_tax: true }, - { id: "shipping_method_2", price: 100, includes_tax: false }, - ], - allocation_map: {}, - }, - }, - ], -] - -describe("TaxCalculationStrategy", () => { - describe("calculate", () => { - test.each(toTest)( - "%s", - async (title, { items, taxLines, context, expected, flags }) => { - const featureFlagRouter = new FlagRouter(flags ?? {}) - const calcStrat = new TaxCalculationStrategy({ - featureFlagRouter, - }) - - const val = await calcStrat.calculate(items, taxLines, context) - expect(val).toEqual(expected) - } - ) - }) -}) diff --git a/packages/medusa/src/strategies/batch-jobs/order/export.ts b/packages/medusa/src/strategies/batch-jobs/order/export.ts deleted file mode 100644 index 809958f163..0000000000 --- a/packages/medusa/src/strategies/batch-jobs/order/export.ts +++ /dev/null @@ -1,329 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { EntityManager } from "typeorm" -import { - OrderDescriptor, - OrderExportBatchJob, - OrderExportBatchJobContext, - orderExportPropertiesDescriptors, -} from "." -import { AdminPostBatchesReq } from "../../../api" -import { AbstractBatchJobStrategy, IFileService } from "../../../interfaces" -import SalesChannelFeatureFlag from "../../../loaders/feature-flags/sales-channels" -import { Order } from "../../../models" -import { OrderService } from "../../../services" -import BatchJobService from "../../../services/batch-job" -import { BatchJobStatus } from "../../../types/batch-job" -import { FindConfig } from "../../../types/common" -import { prepareListQuery } from "../../../utils/get-query-config" - -type InjectedDependencies = { - fileService: IFileService - orderService: OrderService - batchJobService: BatchJobService - manager: EntityManager - featureFlagRouter: FlagRouter -} - -class OrderExportStrategy extends AbstractBatchJobStrategy { - public static identifier = "order-export-strategy" - public static batchType = "order-export" - - public defaultMaxRetry = 3 - - protected readonly DEFAULT_LIMIT = 100 - protected readonly NEWLINE = "\r\n" - protected readonly DELIMITER = ";" - - protected manager_: EntityManager - protected transactionManager_: EntityManager | undefined - protected readonly fileService_: IFileService - protected readonly batchJobService_: BatchJobService - protected readonly orderService_: OrderService - protected readonly featureFlagRouter_: FlagRouter - - protected readonly orderExportPropertiesDescriptors = [ - ...orderExportPropertiesDescriptors, - ] - - protected readonly defaultRelations_ = ["customer", "shipping_address"] - protected readonly defaultFields_ = [ - "id", - "display_id", - "status", - "created_at", - "fulfillment_status", - "payment_status", - "subtotal", - "shipping_total", - "discount_total", - "gift_card_total", - "refunded_total", - "tax_total", - "total", - "currency_code", - "region_id", - ] - - constructor({ - fileService, - batchJobService, - orderService, - manager, - featureFlagRouter, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.manager_ = manager - this.fileService_ = fileService - this.batchJobService_ = batchJobService - this.orderService_ = orderService - this.featureFlagRouter_ = featureFlagRouter - - if (featureFlagRouter.isFeatureEnabled(SalesChannelFeatureFlag.key)) { - this.defaultRelations_.push("sales_channel") - this.addSalesChannelColumns() - } - } - - async prepareBatchJobForProcessing( - batchJob: AdminPostBatchesReq, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - req: Express.Request - ): Promise { - const { - limit, - offset, - order, - fields, - expand, - filterable_fields, - ...context - } = batchJob.context as OrderExportBatchJobContext - - const { listConfig } = prepareListQuery( - { - limit, - offset, - order, - fields, - expand, - }, - { - isList: true, - defaultRelations: this.defaultRelations_, - defaultFields: this.defaultFields_, - } - ) - - batchJob.context = { - ...(context ?? {}), - list_config: listConfig, - filterable_fields, - } - - return batchJob - } - - async preProcessBatchJob(batchJobId: string): Promise { - return await this.atomicPhase_(async (transactionManager) => { - const batchJob = (await this.batchJobService_ - .withTransaction(transactionManager) - .retrieve(batchJobId)) as OrderExportBatchJob - - const offset = batchJob.context?.list_config?.skip ?? 0 - const limit = batchJob.context?.list_config?.take ?? this.DEFAULT_LIMIT - - const { list_config = {}, filterable_fields = {} } = batchJob.context - - let count = batchJob.context?.batch_size - - if (!count) { - const [, orderCount] = await this.orderService_ - .withTransaction(transactionManager) - .listAndCount(filterable_fields, { - ...(list_config ?? {}), - skip: offset as number, - order: { created_at: "DESC" }, - take: Math.min(batchJob.context.batch_size ?? Infinity, limit), - } as FindConfig) - count = orderCount - } - - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJob, { - result: { - stat_descriptors: [ - { - key: "order-export-count", - name: "Order count to export", - message: `There will be ${count} orders exported by this action`, - }, - ], - }, - }) - }) - } - - async processJob(batchJobId: string): Promise { - let offset = 0 - let limit = this.DEFAULT_LIMIT - let advancementCount = 0 - let orderCount = 0 - let approximateFileSize = 0 - - return await this.atomicPhase_( - async (transactionManager) => { - let batchJob = (await this.batchJobService_ - .withTransaction(transactionManager) - .retrieve(batchJobId)) as OrderExportBatchJob - - const { writeStream, fileKey, promise } = await this.fileService_ - .withTransaction(transactionManager) - .getUploadStreamDescriptor({ - name: `exports/orders/order-export-${Date.now()}`, - ext: "csv", - }) - - advancementCount = - batchJob.result?.advancement_count ?? advancementCount - offset = (batchJob.context?.list_config?.skip ?? 0) + advancementCount - limit = batchJob.context?.list_config?.take ?? limit - - const { list_config = {}, filterable_fields = {} } = batchJob.context - const [, count] = await this.orderService_.listAndCount( - filterable_fields, - { - ...list_config, - order: { created_at: "DESC" }, - skip: offset, - take: Math.min(batchJob.context.batch_size ?? Infinity, limit), - } as FindConfig - ) - - orderCount = batchJob.context?.batch_size ?? count - let orders: Order[] = [] - - const lineDescriptor = this.getLineDescriptor( - list_config.select as string[], - list_config.relations as string[] - ) - - const header = this.buildHeader(lineDescriptor) - writeStream.write(header) - approximateFileSize += Buffer.from(header).byteLength - - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJobId, { - result: { - file_key: fileKey, - file_size: approximateFileSize, - }, - }) - - while (offset < orderCount) { - orders = await this.orderService_ - .withTransaction(transactionManager) - .list(filterable_fields, { - ...list_config, - skip: offset, - take: Math.min(orderCount - offset, limit), - } as FindConfig) - - orders.forEach((order) => { - const line = this.buildCSVLine(order, lineDescriptor) - approximateFileSize += Buffer.from(line).byteLength - writeStream.write(line) - }) - - advancementCount += orders.length - offset += orders.length - - batchJob = (await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJobId, { - result: { - file_size: approximateFileSize, - count: orderCount, - advancement_count: advancementCount, - progress: advancementCount / orderCount, - }, - })) as OrderExportBatchJob - - if (batchJob.status === BatchJobStatus.CANCELED) { - writeStream.end() - - await this.fileService_ - .withTransaction(transactionManager) - .delete({ fileKey: fileKey }) - - return - } - } - - writeStream.end() - - await promise - }, - "REPEATABLE READ", - async (err: Error) => - this.handleProcessingError(batchJobId, err, { - offset, - count: orderCount, - progress: offset / orderCount, - }) - ) - } - - public async buildTemplate(): Promise { - return this.buildHeader( - this.getLineDescriptor(this.defaultFields_, this.defaultRelations_) - ) - } - - private buildHeader( - lineDescriptor: OrderDescriptor[] = this.orderExportPropertiesDescriptors - ): string { - return ( - [...lineDescriptor.map(({ title }) => title)].join(this.DELIMITER) + - this.NEWLINE - ) - } - - private buildCSVLine( - order: Order, - lineDescriptor: OrderDescriptor[] - ): string { - return ( - [...lineDescriptor.map(({ accessor }) => accessor(order))].join( - this.DELIMITER - ) + this.NEWLINE - ) - } - - private getLineDescriptor( - fields: string[], - relations: string[] - ): OrderDescriptor[] { - return this.orderExportPropertiesDescriptors.filter( - ({ fieldName }) => - fields.indexOf(fieldName) !== -1 || relations.indexOf(fieldName) !== -1 - ) - } - - private addSalesChannelColumns(): void { - this.orderExportPropertiesDescriptors.push({ - fieldName: "sales_channel", - title: ["Sales channel name", "Sales channel description"].join(";"), - accessor: (order: Order): string => - [ - order.sales_channel?.name || "", - order.sales_channel?.description || "", - ].join(";"), - }) - } -} - -export default OrderExportStrategy diff --git a/packages/medusa/src/strategies/batch-jobs/order/index.ts b/packages/medusa/src/strategies/batch-jobs/order/index.ts deleted file mode 100644 index 2106a6e750..0000000000 --- a/packages/medusa/src/strategies/batch-jobs/order/index.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { BatchJob, Order } from "../../../models" -import { Selector } from "../../../types/common" - -export type OrderExportBatchJobContext = { - offset?: number - limit?: number - order?: string - fields?: string - expand?: string - - list_config?: { - select?: string[] - relations?: string[] - skip?: number - take?: number - order?: Record - } - filterable_fields?: Selector - - retry_count?: number - max_retry?: number - batch_size?: number -} - -export type OrderExportBatchJob = BatchJob & { - context: OrderExportBatchJobContext -} - -export type OrderDescriptor = { - fieldName: string - title: string - accessor: (entity: Order) => string -} - -export const orderExportPropertiesDescriptors: OrderDescriptor[] = [ - { - fieldName: "id", - title: "Order_ID", - accessor: (order: Order): string => order.id, - }, - { - fieldName: "display_id", - title: "Display_ID", - accessor: (order: Order): string => order.display_id.toString(), - }, - { - fieldName: "status", - title: "Order status", - accessor: (order: Order): string => order.status.toString(), - }, - - { - fieldName: "created_at", - title: "Date", - accessor: (order: Order): string => order.created_at.toUTCString(), - }, - - { - fieldName: "customer", - title: [ - "Customer First name", - "Customer Last name", - "Customer Email", - "Customer ID", - ].join(";"), - accessor: (order: Order): string => - [ - order.customer.first_name, - order.customer.last_name, - order.customer.email, - order.customer.id, - ].join(";"), - }, - - { - fieldName: "shipping_address", - title: [ - "Shipping Address 1", - "Shipping Address 2", - "Shipping Country Code", - "Shipping City", - "Shipping Postal Code", - "Shipping Region ID", - ].join(";"), - accessor: (order: Order): string => - [ - order.shipping_address?.address_1, - order.shipping_address?.address_2, - order.shipping_address?.country_code, - order.shipping_address?.city, - order.shipping_address?.postal_code, - order.region_id, - ].join(";"), - }, - - { - fieldName: "fulfillment_status", - title: "Fulfillment Status", - accessor: (order: Order): string => order.fulfillment_status, - }, - - { - fieldName: "payment_status", - title: "Payment Status", - accessor: (order: Order): string => order.payment_status, - }, - - { - fieldName: "subtotal", - title: "Subtotal", - accessor: (order: Order): string => order.subtotal.toString(), - }, - - { - fieldName: "shipping_total", - title: "Shipping Total", - accessor: (order: Order): string => order.shipping_total.toString(), - }, - - { - fieldName: "discount_total", - title: "Discount Total", - accessor: (order: Order): string => order.discount_total.toString(), - }, - - { - fieldName: "gift_card_total", - title: "Gift Card Total", - accessor: (order: Order): string => order.gift_card_total.toString(), - }, - - { - fieldName: "refunded_total", - title: "Refunded Total", - accessor: (order: Order): string => order.refunded_total.toString(), - }, - { - fieldName: "tax_total", - title: "Tax Total", - accessor: (order: Order): string => order.tax_total?.toString() ?? "", - }, - { - fieldName: "total", - title: "Total", - accessor: (order: Order): string => order.total.toString(), - }, - - { - fieldName: "currency_code", - title: "Currency Code", - accessor: (order: Order): string => order.currency_code, - }, -] diff --git a/packages/medusa/src/strategies/batch-jobs/price-list/import.ts b/packages/medusa/src/strategies/batch-jobs/price-list/import.ts deleted file mode 100644 index e6a78a20e5..0000000000 --- a/packages/medusa/src/strategies/batch-jobs/price-list/import.ts +++ /dev/null @@ -1,529 +0,0 @@ -import { AbstractBatchJobStrategy, IFileService } from "../../../interfaces" -import { - BatchJobService, - PriceListService, - ProductVariantService, - RegionService, -} from "../../../services" -import { - InjectedProps, - OperationType, - ParsedPriceListImportPrice, - PriceListImportBatchJob, - PriceListImportCsvSchema, - PriceListImportOperation, - PriceListImportOperationPrice, - TBuiltPriceListImportLine, - TParsedPriceListImportRowData, -} from "./types" -import { computerizeAmount, MedusaError } from "medusa-core-utils" - -import { BatchJob } from "../../../models" -import { CreateBatchJobInput } from "../../../types/batch-job" -import CsvParser from "../../../services/csv-parser" -import { EntityManager } from "typeorm" -import { PriceListPriceCreateInput } from "../../../types/price-list" -import { TParsedProductImportRowData } from "../product/types" -import { promiseAll } from "@medusajs/utils" - -/* - * Default strategy class used for a batch import of products/variants. - */ -class PriceListImportStrategy extends AbstractBatchJobStrategy { - static identifier = "price-list-import-strategy" - - static batchType = "price-list-import" - - private processedCounter: Record = {} - - protected manager_: EntityManager - protected transactionManager_: EntityManager | undefined - - protected readonly fileService_: IFileService - - protected readonly regionService_: RegionService - protected readonly priceListService_: PriceListService - protected readonly batchJobService_: BatchJobService - protected readonly productVariantService_: ProductVariantService - - protected readonly csvParser_: CsvParser< - PriceListImportCsvSchema, - Record, - Record - > - - constructor({ - batchJobService, - productVariantService, - priceListService, - regionService, - fileService, - manager, - }: InjectedProps) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.csvParser_ = new CsvParser(CSVSchema) - - this.manager_ = manager - this.fileService_ = fileService - this.batchJobService_ = batchJobService - this.priceListService_ = priceListService - this.productVariantService_ = productVariantService - this.regionService_ = regionService - } - - async buildTemplate(): Promise { - throw new Error("Not implemented!") - } - - /** - * Create a description of a row on which the error occurred and throw a Medusa error. - * - * @param row - Parsed CSV row data - * @param errorDescription - Concrete error - */ - protected static throwDescriptiveError( - row: TParsedPriceListImportRowData, - errorDescription?: string - ): never { - const message = `Error while processing row with: - variant ID: ${row[PriceListRowKeys.VARIANT_ID]}, - variant SKU: ${row[PriceListRowKeys.VARIANT_SKU]}, - ${errorDescription}` - - throw new MedusaError(MedusaError.Types.INVALID_DATA, message) - } - - async prepareBatchJobForProcessing( - batchJob: CreateBatchJobInput, - reqContext: any - ): Promise { - const manager = this.transactionManager_ ?? this.manager_ - - if (!batchJob.context?.price_list_id) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Price list id is required" - ) - } - - // Validate that PriceList exists - const priceListId = batchJob.context.price_list_id as string - await this.priceListService_.withTransaction(manager).retrieve(priceListId) - - return batchJob - } - - /** - * Generate instructions for creation of prices from parsed CSV rows. - * - * @param priceListId - the ID of the price list where the prices will be created - * @param csvData - An array of parsed CSV rows. - */ - async getImportInstructions( - priceListId: string, - csvData: TParsedPriceListImportRowData[] - ): Promise> { - // Validate that PriceList exists - const manager = this.transactionManager_ ?? this.manager_ - await this.priceListService_.withTransaction(manager).retrieve(priceListId) - - const pricesToCreate: PriceListImportOperation[] = [] - - for (const row of csvData) { - let variantId = row[PriceListRowKeys.VARIANT_ID] - - if (!variantId) { - if (!row[PriceListRowKeys.VARIANT_SKU]) { - PriceListImportStrategy.throwDescriptiveError( - row, - "SKU or ID is required" - ) - } - - const variant = await this.productVariantService_.retrieveBySKU( - `${row[PriceListRowKeys.VARIANT_SKU]}`, - { - select: ["id"], - } - ) - variantId = variant.id - } else { - // Validate that product exists - await this.productVariantService_.retrieve(`${variantId}`, { - select: ["id"], - }) - } - - const pricesOperationData = await this.prepareVariantPrices( - row[PriceListRowKeys.PRICES] as ParsedPriceListImportPrice[] - ) - - pricesToCreate.push({ - variant_id: `${variantId}`, - prices: pricesOperationData, - }) - } - - return { - [OperationType.PricesCreate]: pricesToCreate, - } - } - - /** - * Prepare prices records for insert - find and append region ids to records that contain a region name. - * - * @param prices - the parsed prices to prepare - * @returns the prepared prices. All prices have amount in DB format, currency_code and if applicable region_id. - */ - protected async prepareVariantPrices( - prices: ParsedPriceListImportPrice[] - ): Promise { - const transactionManager = this.transactionManager_ ?? this.manager_ - - const operationalPrices: PriceListImportOperationPrice[] = [] - - for (const price of prices) { - const record: Partial = { - amount: price.amount, - } - - if ("region_name" in price) { - try { - const region = await this.regionService_ - .withTransaction(transactionManager) - .retrieveByName(price.region_name) - - record.region_id = region.id - record.currency_code = region.currency_code - } catch (e) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Trying to set a price for a region ${price.region_name} that doesn't exist` - ) - } - } else { - // TODO: Verify that currency is activated for store - record.currency_code = price.currency_code - } - - record.amount = computerizeAmount( - record.amount as number, - record.currency_code - ) - - operationalPrices.push(record as PriceListImportOperationPrice) - } - - return operationalPrices - } - - /** - * A worker method called after a batch job has been created. - * The method parses a CSV file, generates sets of instructions - * for processing and stores these instructions to a JSON file - * which is uploaded to a bucket. - * - * @param batchJobId - An id of a job that is being preprocessed. - */ - async preProcessBatchJob(batchJobId: string): Promise { - const transactionManager = this.transactionManager_ ?? this.manager_ - const batchJob = (await this.batchJobService_ - .withTransaction(transactionManager) - .retrieve(batchJobId)) as PriceListImportBatchJob - - const csvFileKey = batchJob.context.fileKey - const priceListId = batchJob.context.price_list_id - const csvStream = await this.fileService_.getDownloadStream({ - fileKey: csvFileKey, - }) - - let builtData: Record[] - try { - const parsedData = await this.csvParser_.parse(csvStream) - builtData = await this.csvParser_.buildData(parsedData) - } catch (e) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "The csv file parsing failed due to: " + e.message - ) - } - - const ops = await this.getImportInstructions(priceListId, builtData) - - await this.uploadImportOpsFile(batchJobId, ops) - - let totalOperationCount = 0 - const operationsCounts = {} - Object.keys(ops).forEach((key) => { - operationsCounts[key] = ops[key].length - totalOperationCount += ops[key].length - }) - - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJobId, { - result: { - advancement_count: 0, - // number of update/create operations to execute - count: totalOperationCount, - operations: operationsCounts, - stat_descriptors: [ - { - key: "price-list-import-count", - name: "PriceList to import", - message: `${ - ops[OperationType.PricesCreate].length - } prices will be added`, - }, - ], - }, - }) - } - - /** - * The main processing method called after a batch job - * is ready/confirmed for processing. - * - * @param batchJobId - An id of a batch job that is being processed. - */ - async processJob(batchJobId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const batchJob = (await this.batchJobService_ - .withTransaction(manager) - .retrieve(batchJobId)) as PriceListImportBatchJob - - const priceListId = batchJob.context.price_list_id - const txPriceListService = this.priceListService_.withTransaction(manager) - - // Delete Existing prices for price list - await txPriceListService.clearPrices(priceListId) - - // Upload new prices for price list - const priceImportOperations = await this.downloadImportOpsFile( - batchJob, - OperationType.PricesCreate - ) - - for (const op of priceImportOperations) { - try { - await txPriceListService.addPrices( - priceListId, - (op.prices as PriceListPriceCreateInput[]).map( - (p: PriceListPriceCreateInput) => { - return { - ...p, - variant_id: op.variant_id as string, - } - } - ) - ) - } catch (e) { - PriceListImportStrategy.throwDescriptiveError(op, e.message) - } - } - - await this.finalize(batchJob) - }) - } - - /** - * Store import ops JSON file to a bucket. - * - * @param batchJobId - An id of the current batch job being processed. - * @param results - An object containing parsed CSV data. - */ - protected async uploadImportOpsFile( - batchJobId: string, - results: Record - ): Promise { - const uploadPromises: Promise[] = [] - const transactionManager = this.transactionManager_ ?? this.manager_ - - const files: Record = {} - - for (const op in results) { - if (results[op]?.length) { - const { writeStream, fileKey, promise } = await this.fileService_ - .withTransaction(transactionManager) - .getUploadStreamDescriptor({ - name: PriceListImportStrategy.buildFilename(batchJobId, op), - ext: "json", - }) - - uploadPromises.push(promise) - - files[op] = fileKey - writeStream.write(JSON.stringify(results[op])) - writeStream.end() - } - } - - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJobId, { - result: { files }, - }) - - await promiseAll(uploadPromises) - } - - /** - * Download parsed ops JSON file. - * - * @param batchJob - the current batch job being processed - * @param op - Type of import operation. - */ - protected async downloadImportOpsFile( - batchJob: BatchJob, - op: OperationType - ): Promise { - let data = "" - const transactionManager = this.transactionManager_ ?? this.manager_ - - const readableStream = await this.fileService_ - .withTransaction(transactionManager) - .getDownloadStream({ - fileKey: batchJob.result.files![op], - }) - - return await new Promise((resolve) => { - readableStream.on("data", (chunk) => { - data += chunk - }) - readableStream.on("end", () => { - resolve(JSON.parse(data)) - }) - readableStream.on("error", () => { - // TODO: maybe should throw - resolve([] as TParsedPriceListImportRowData[]) - }) - }) - } - - /** - * Delete parsed CSV ops files. - * - * @param batchJob - the current batch job being processed - */ - protected async deleteOpsFiles(batchJob: BatchJob): Promise { - const transactionManager = this.transactionManager_ ?? this.manager_ - - const fileServiceTx = this.fileService_.withTransaction(transactionManager) - for (const fileName of Object.values(batchJob.result.files!)) { - try { - await fileServiceTx.delete({ - fileKey: fileName, - }) - } catch (e) { - // noop - } - } - } - - /** - * Update count of processed data in the batch job `result` column - * and cleanup temp JSON files. - * - * @param batchJob - The current batch job being processed. - */ - private async finalize(batchJob: PriceListImportBatchJob): Promise { - const transactionManager = this.transactionManager_ ?? this.manager_ - - delete this.processedCounter[batchJob.id] - - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJob.id, { - result: { advancement_count: batchJob.result.count }, - }) - - const { fileKey } = batchJob.context - - await this.fileService_ - .withTransaction(transactionManager) - .delete({ fileKey }) - - await this.deleteOpsFiles(batchJob) - } - - private static buildFilename( - batchJobId: string, - operation: string, - { appendExt }: { appendExt?: string } = { appendExt: undefined } - ): string { - const filename = `imports/price-lists/ops/${batchJobId}-${operation}` - return appendExt ? filename + appendExt : filename - } -} - -export default PriceListImportStrategy - -enum PriceListRowKeys { - VARIANT_ID = "id", - VARIANT_SKU = "sku", - PRICES = "prices", -} - -/** - * Schema definition for the CSV parser. - */ -const CSVSchema: PriceListImportCsvSchema = { - columns: [ - { - name: "Product Variant ID", - mapTo: PriceListRowKeys.VARIANT_ID, - }, - { name: "SKU", mapTo: PriceListRowKeys.VARIANT_SKU }, - { - name: "Price Region", - match: /Price (.*) \[([A-Z]{3})\]/, - reducer: ( - builtLine: TBuiltPriceListImportLine, - key: string, - value: string - ): TBuiltPriceListImportLine => { - builtLine[PriceListRowKeys.PRICES] = - builtLine[PriceListRowKeys.PRICES] || [] - - if (typeof value === "undefined" || value === null) { - return builtLine - } - - const [, regionName] = - key.trim().match(/Price (.*) \[([A-Z]{3})\]/) || [] - builtLine[PriceListRowKeys.PRICES].push({ - amount: parseFloat(value), - region_name: regionName, - }) - - return builtLine - }, - }, - { - name: "Price Currency", - match: /Price [A-Z]{3}/, - reducer: ( - builtLine: TBuiltPriceListImportLine, - key: string, - value: string - ): TBuiltPriceListImportLine => { - builtLine[PriceListRowKeys.PRICES] = - builtLine[PriceListRowKeys.PRICES] || [] - - if (typeof value === "undefined" || value === null) { - return builtLine - } - - const currency = key.trim().split(" ")[1] - builtLine[PriceListRowKeys.PRICES].push({ - amount: parseFloat(value), - currency_code: currency.toLowerCase(), - }) - - return builtLine - }, - }, - ], -} diff --git a/packages/medusa/src/strategies/batch-jobs/price-list/types.ts b/packages/medusa/src/strategies/batch-jobs/price-list/types.ts deleted file mode 100644 index 62e7003e6a..0000000000 --- a/packages/medusa/src/strategies/batch-jobs/price-list/types.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { EntityManager } from "typeorm" -import { FileService } from "medusa-interfaces" - -import { - BatchJobService, - PriceListService, - ProductVariantService, - RegionService, -} from "../../../services" -import { CsvSchema } from "../../../interfaces/csv-parser" -import { BatchJob } from "../../../models" - -export type PriceListImportBatchJob = BatchJob & { - context: PriceListImportJobContext - result: Pick & { - operations: { - [K in keyof typeof OperationType]: number - } - } -} - -/** - * DI props for the Product import strategy - */ -export type InjectedProps = { - priceListService: PriceListService - batchJobService: BatchJobService - productVariantService: ProductVariantService - regionService: RegionService - fileService: typeof FileService - manager: EntityManager -} - -/** - * Data shape returned by the CSVParser. - */ -export type TParsedPriceListImportRowData = Record< - string, - string | number | (string | number | object)[] -> - -export type PriceListImportOperationPrice = { - region_id?: string - currency_code: string - amount: number -} - -export type PriceListImportOperation = { - variant_id: string - prices: PriceListImportOperationPrice[] -} - -export type ParsedPriceListImportPrice = - | { - amount: number - currency_code: string - } - | { - amount: number - region_name: string - } - -/** - * CSV parser's row reducer result data shape. - */ -export type TBuiltPriceListImportLine = Record - -/** - * Schema definition of for an import CSV file. - */ -export type PriceListImportCsvSchema = CsvSchema< - TParsedPriceListImportRowData, - TBuiltPriceListImportLine -> - -/** - * Import Batch job context column type. - */ -export type PriceListImportJobContext = { - price_list_id: string - fileKey: string -} - -/** - * Supported batch job import ops. - */ -export enum OperationType { - PricesCreate = "PRICE_LIST_PRICE_CREATE", -} diff --git a/packages/medusa/src/strategies/batch-jobs/product/export.ts b/packages/medusa/src/strategies/batch-jobs/product/export.ts deleted file mode 100644 index a0357e2a10..0000000000 --- a/packages/medusa/src/strategies/batch-jobs/product/export.ts +++ /dev/null @@ -1,754 +0,0 @@ -import { MedusaContainer } from "@medusajs/types" -import { createContainerLike, FlagRouter, MedusaV2Flag } from "@medusajs/utils" -import { humanizeAmount } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { defaultAdminProductRelations } from "../../../api" -import { AbstractBatchJobStrategy, IFileService } from "../../../interfaces" -import ProductCategoryFeatureFlag from "../../../loaders/feature-flags/product-categories" -import SalesChannelFeatureFlag from "../../../loaders/feature-flags/sales-channels" -import { Product, ProductVariant } from "../../../models" -import { BatchJobService, ProductService } from "../../../services" -import { BatchJobStatus, CreateBatchJobInput } from "../../../types/batch-job" -import { FindProductConfig } from "../../../types/product" -import { csvCellContentFormatter, listProducts } from "../../../utils" -import { prepareListQuery } from "../../../utils/get-query-config" -import { - DynamicProductExportDescriptor, - ProductExportBatchJob, - ProductExportBatchJobContext, - ProductExportInjectedDependencies, - ProductExportPriceData, -} from "./types" -import { - productCategoriesColumnsDefinition, - productColumnsDefinition, - productSalesChannelColumnsDefinition, -} from "./types/columns-definition" - -export default class ProductExportStrategy extends AbstractBatchJobStrategy { - public static identifier = "product-export-strategy" - public static batchType = "product-export" - - protected manager_: EntityManager - protected transactionManager_: EntityManager | undefined - - protected readonly batchJobService_: BatchJobService - protected readonly productService_: ProductService - protected readonly fileService_: IFileService - protected readonly featureFlagRouter_: FlagRouter - protected readonly remoteQuery_: any - - protected readonly defaultRelations_ = [ - ...defaultAdminProductRelations, - "variants.prices.region", - ] - /* - * - * The dynamic columns corresponding to the lowest level of relations are built later on. - * You can have a look at the buildHeader method that take care of appending the other - * column descriptors to this map. - * - */ - protected readonly columnsDefinition = { ...productColumnsDefinition } - protected readonly salesChannelsColumnsDefinition = { - ...productSalesChannelColumnsDefinition, - } - - protected readonly productCategoriesColumnDefinitions = { - ...productCategoriesColumnsDefinition, - } - - private readonly NEWLINE_ = "\r\n" - private readonly DELIMITER_ = ";" - private readonly DEFAULT_LIMIT = 50 - - constructor({ - manager, - batchJobService, - productService, - fileService, - featureFlagRouter, - remoteQuery, - }: ProductExportInjectedDependencies) { - super({ - manager, - batchJobService, - productService, - fileService, - featureFlagRouter, - remoteQuery, - }) - - this.remoteQuery_ = remoteQuery - this.manager_ = manager - this.batchJobService_ = batchJobService - this.productService_ = productService - this.fileService_ = fileService - this.featureFlagRouter_ = featureFlagRouter - - if (featureFlagRouter.isFeatureEnabled(SalesChannelFeatureFlag.key)) { - this.defaultRelations_.push("sales_channels") - } - - if (featureFlagRouter.isFeatureEnabled(ProductCategoryFeatureFlag.key)) { - this.defaultRelations_.push("categories") - } - } - - async buildTemplate(): Promise { - return "" - } - - async prepareBatchJobForProcessing( - batchJob: CreateBatchJobInput, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - req: Express.Request - ): Promise { - const { - limit, - offset, - order, - fields, - expand, - filterable_fields, - ...context - } = (batchJob?.context ?? {}) as ProductExportBatchJobContext - - const { listConfig } = prepareListQuery( - { - limit, - offset, - order, - fields, - expand, - }, - { - isList: true, - defaultRelations: this.defaultRelations_, - } - ) - - batchJob.context = { - ...(context ?? {}), - list_config: listConfig, - filterable_fields, - } - - return batchJob - } - - async preProcessBatchJob(batchJobId: string): Promise { - const isMedusaV2Enabled = this.featureFlagRouter_.isFeatureEnabled( - MedusaV2Flag.key - ) - - return await this.atomicPhase_(async (transactionManager) => { - const batchJob = (await this.batchJobService_ - .withTransaction(transactionManager) - .retrieve(batchJobId)) as ProductExportBatchJob - - let offset = batchJob.context?.list_config?.skip ?? 0 - const limit = batchJob.context?.list_config?.take ?? this.DEFAULT_LIMIT - - const { list_config = {}, filterable_fields = {} } = batchJob.context - let productList: Product[] = [] - let count = 0 - const container = createContainerLike( - this.__container__ - ) as MedusaContainer - - if (isMedusaV2Enabled) { - ;[productList, count] = await listProducts( - container, - filterable_fields, - { - ...list_config, - take: null, - } - ) - } else { - ;[productList, count] = await this.productService_ - .withTransaction(transactionManager) - .listAndCount(filterable_fields, { - ...(list_config ?? {}), - take: Math.min(batchJob.context.batch_size ?? Infinity, limit), - } as FindProductConfig) - } - - const productCount = batchJob.context?.batch_size ?? count - let products: Product[] = productList - - let dynamicOptionColumnCount = 0 - let dynamicImageColumnCount = 0 - let dynamicSalesChannelsColumnCount = 0 - let dynamicProductCategoriesColumnCount = 0 - let pricesData = new Set() - - while (offset < productCount) { - if (!products?.length) { - if (isMedusaV2Enabled) { - ;[productList, count] = await listProducts( - container, - filterable_fields, - { - ...list_config, - skip: offset, - take: Math.min(productCount - offset, limit), - } - ) - } else { - products = await this.productService_ - .withTransaction(transactionManager) - .list(filterable_fields, { - ...list_config, - skip: offset, - take: Math.min(productCount - offset, limit), - } as FindProductConfig) - } - } - - const shapeData = this.getProductRelationsDynamicColumnsShape(products) - dynamicImageColumnCount = Math.max( - shapeData.imageColumnCount, - dynamicImageColumnCount - ) - dynamicOptionColumnCount = Math.max( - shapeData.optionColumnCount, - dynamicOptionColumnCount - ) - dynamicSalesChannelsColumnCount = Math.max( - shapeData.salesChannelsColumnCount, - dynamicSalesChannelsColumnCount - ) - dynamicProductCategoriesColumnCount = Math.max( - shapeData.productCategoriesColumnCount, - dynamicProductCategoriesColumnCount - ) - pricesData = new Set([...pricesData, ...shapeData.pricesData]) - - offset += products.length - products = [] - } - - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJob, { - context: { - shape: { - dynamicImageColumnCount, - dynamicOptionColumnCount, - dynamicSalesChannelsColumnCount, - dynamicProductCategoriesColumnCount, - prices: [...pricesData].map((stringifyData) => - JSON.parse(stringifyData) - ), - }, - }, - result: { - stat_descriptors: [ - { - key: "product-export-count", - name: "Product count to export", - message: `There will be ${productCount} products exported by this action`, - }, - ], - }, - }) - }) - } - - async processJob(batchJobId: string): Promise { - let offset = 0 - let limit = this.DEFAULT_LIMIT - let advancementCount = 0 - let productCount = 0 - let approximateFileSize = 0 - - return await this.atomicPhase_( - async (transactionManager) => { - const productServiceTx = - this.productService_.withTransaction(transactionManager) - const batchJobServiceTx = - this.batchJobService_.withTransaction(transactionManager) - const fileServiceTx = - this.fileService_.withTransaction(transactionManager) - - let batchJob = (await batchJobServiceTx.retrieve( - batchJobId - )) as ProductExportBatchJob - - const { writeStream, fileKey, promise } = - await fileServiceTx.getUploadStreamDescriptor({ - name: `exports/products/product-export-${Date.now()}`, - ext: "csv", - }) - - const header = await this.buildHeader(batchJob) - writeStream.write(header) - approximateFileSize += Buffer.from(header).byteLength - - await batchJobServiceTx.update(batchJobId, { - result: { - file_key: fileKey, - file_size: approximateFileSize, - }, - }) - - advancementCount = - batchJob.result?.advancement_count ?? advancementCount - offset = (batchJob.context?.list_config?.skip ?? 0) + advancementCount - limit = batchJob.context?.list_config?.take ?? limit - - const { list_config = {}, filterable_fields = {} } = batchJob.context - const [productList, count] = await productServiceTx.listAndCount( - filterable_fields, - { - ...list_config, - skip: offset, - take: Math.min(batchJob.context.batch_size ?? Infinity, limit), - } as FindProductConfig - ) - - productCount = batchJob.context?.batch_size ?? count - let products: Product[] = productList - - while (offset < productCount) { - if (!products?.length) { - products = await productServiceTx.list(filterable_fields, { - ...list_config, - skip: offset, - take: Math.min(productCount - offset, limit), - } as FindProductConfig) - } - - products.forEach((product: Product) => { - const lines = this.buildProductVariantLines(product) - lines.forEach((line) => { - approximateFileSize += Buffer.from(line).byteLength - writeStream.write(line) - }) - }) - - advancementCount += products.length - offset += products.length - products = [] - - batchJob = (await batchJobServiceTx.update(batchJobId, { - result: { - file_size: approximateFileSize, - count: productCount, - advancement_count: advancementCount, - progress: advancementCount / productCount, - }, - })) as ProductExportBatchJob - - if (batchJob.status === BatchJobStatus.CANCELED) { - writeStream.end() - await this.onProcessCanceled(batchJobId, fileKey) - return - } - } - - writeStream.end() - - return await promise - }, - "REPEATABLE READ", - async (err) => - this.handleProcessingError(batchJobId, err, { - count: productCount, - advancement_count: advancementCount, - progress: advancementCount / productCount, - }) - ) - } - - public async buildHeader(batchJob: ProductExportBatchJob): Promise { - const { - prices = [], - dynamicImageColumnCount, - dynamicOptionColumnCount, - dynamicSalesChannelsColumnCount, - dynamicProductCategoriesColumnCount, - } = batchJob?.context?.shape ?? {} - - this.appendMoneyAmountDescriptors(prices) - this.appendOptionsDescriptors(dynamicOptionColumnCount) - this.appendImagesDescriptors(dynamicImageColumnCount) - this.appendSalesChannelsDescriptors(dynamicSalesChannelsColumnCount) - this.appendProductCategoriesDescriptors(dynamicProductCategoriesColumnCount) - - const exportedColumns = Object.values(this.columnsDefinition) - .map( - (descriptor) => - descriptor.exportDescriptor && - !("isDynamic" in descriptor.exportDescriptor) && - descriptor.name - ) - .filter((name): name is string => !!name) - - return exportedColumns.join(this.DELIMITER_) + this.NEWLINE_ - } - - private appendImagesDescriptors(maxImagesCount: number): void { - const columnNameBuilder = (this.columnsDefinition["Image Url"]! - .exportDescriptor as DynamicProductExportDescriptor)! - .buildDynamicColumnName - - for (let i = 0; i < maxImagesCount; ++i) { - const columnName = columnNameBuilder(i) - - this.columnsDefinition[columnName] = { - name: columnName, - exportDescriptor: { - accessor: (product: Product) => product?.images[i]?.url ?? "", - entityName: "product", - }, - } - } - } - - private appendSalesChannelsDescriptors(maxScCount: number): void { - const columnNameIdBuilder = (this.salesChannelsColumnsDefinition[ - "Sales Channel Id" - ]!.exportDescriptor as DynamicProductExportDescriptor)! - .buildDynamicColumnName - - const columnNameNameBuilder = (this.salesChannelsColumnsDefinition[ - "Sales Channel Name" - ]!.exportDescriptor as DynamicProductExportDescriptor)! - .buildDynamicColumnName - - const columnNameDescriptionBuilder = (this.salesChannelsColumnsDefinition[ - "Sales Channel Description" - ]!.exportDescriptor as DynamicProductExportDescriptor)! - .buildDynamicColumnName - - for (let i = 0; i < maxScCount; ++i) { - const columnNameId = columnNameIdBuilder(i) - - this.columnsDefinition[columnNameId] = { - name: columnNameId, - exportDescriptor: { - accessor: (product: Product) => - product?.sales_channels[i]?.name ?? "", - entityName: "product", - }, - } - - const columnNameName = columnNameNameBuilder(i) - - this.columnsDefinition[columnNameName] = { - name: columnNameName, - exportDescriptor: { - accessor: (product: Product) => - product?.sales_channels[i]?.name ?? "", - entityName: "product", - }, - } - - const columnNameDescription = columnNameDescriptionBuilder(i) - - this.columnsDefinition[columnNameDescription] = { - name: columnNameDescription, - exportDescriptor: { - accessor: (product: Product) => - product?.sales_channels[i]?.description ?? "", - entityName: "product", - }, - } - } - } - - private appendProductCategoriesDescriptors(maxCategoriesCount): void { - const columnNameHandleBuilder = (this.productCategoriesColumnDefinitions[ - "Product Category Handle" - ]!.exportDescriptor as DynamicProductExportDescriptor)! - .buildDynamicColumnName - - const columnNameNameBuilder = (this.productCategoriesColumnDefinitions[ - "Product Category Name" - ]!.exportDescriptor as DynamicProductExportDescriptor)! - .buildDynamicColumnName - - const columnNameDescriptionBuilder = (this - .productCategoriesColumnDefinitions["Product Category Description"]! - .exportDescriptor as DynamicProductExportDescriptor)! - .buildDynamicColumnName - - for (let i = 0; i < maxCategoriesCount; ++i) { - let columnNameId = columnNameHandleBuilder(i) - - this.columnsDefinition[columnNameId] = { - name: columnNameId, - exportDescriptor: { - accessor: (product: Product) => product?.categories[i]?.handle ?? "", - entityName: "product", - }, - } - - columnNameId = columnNameNameBuilder(i) - - this.columnsDefinition[columnNameId] = { - name: columnNameId, - exportDescriptor: { - accessor: (product: Product) => product?.categories[i]?.name ?? "", - entityName: "product", - }, - } - - columnNameId = columnNameDescriptionBuilder(i) - - this.columnsDefinition[columnNameId] = { - name: columnNameId, - exportDescriptor: { - accessor: (product: Product) => - product?.categories[i]?.description ?? "", - entityName: "product", - }, - } - } - } - - private appendOptionsDescriptors(maxOptionsCount: number): void { - for (let i = 0; i < maxOptionsCount; ++i) { - const columnNameNameBuilder = (this.columnsDefinition["Option Name"]! - .exportDescriptor as DynamicProductExportDescriptor)! - .buildDynamicColumnName - - const columnNameName = columnNameNameBuilder(i) - - this.columnsDefinition[columnNameName] = { - name: columnNameName, - exportDescriptor: { - accessor: (productOption: Product) => - productOption?.options[i]?.title ?? "", - entityName: "product", - }, - } - - const columnNameValueBuilder = (this.columnsDefinition["Option Value"]! - .exportDescriptor as DynamicProductExportDescriptor)! - .buildDynamicColumnName - - const columnNameNameValue = columnNameValueBuilder(i) - - // option values are not guaranteed to keep the same order as options on product. Pick them in the same order as product options - this.columnsDefinition[columnNameNameValue] = { - name: columnNameNameValue, - exportDescriptor: { - accessor: ( - variant: ProductVariant, - context?: { product?: Product } - ) => - variant?.options.find( - (ov) => ov.option_id === context!.product!.options[i]?.id - )?.value ?? "", - entityName: "variant", - }, - } - } - } - - private appendMoneyAmountDescriptors( - pricesData: ProductExportPriceData[] - ): void { - const columnNameBuilder = (this.columnsDefinition["Price Currency"]! - .exportDescriptor as DynamicProductExportDescriptor)! - .buildDynamicColumnName - - for (const priceData of pricesData) { - if (priceData.currency_code) { - const columnName = columnNameBuilder(priceData) - - this.columnsDefinition[columnName] = { - name: columnName, - exportDescriptor: { - accessor: (variant: ProductVariant) => { - const price = variant.prices.find((variantPrice) => { - return ( - variantPrice.currency_code && - priceData.currency_code && - variantPrice.currency_code.toLowerCase() === - priceData.currency_code.toLowerCase() - ) - }) - return price?.amount - ? humanizeAmount( - price?.amount, - priceData.currency_code! - ).toString() - : "" - }, - entityName: "variant", - }, - } - } - - if (priceData.region) { - const columnNameBuilder = (this.columnsDefinition["Price Region"]! - .exportDescriptor as DynamicProductExportDescriptor)! - .buildDynamicColumnName - const columnName = columnNameBuilder(priceData) - - this.columnsDefinition[columnName] = { - name: columnName, - exportDescriptor: { - accessor: (variant: ProductVariant) => { - const price = variant.prices.find((variantPrice) => { - return ( - variantPrice.region && - priceData.region && - variantPrice.region?.name?.toLowerCase() === - priceData.region?.name?.toLowerCase() && - variantPrice.region?.id?.toLowerCase() === - priceData.region?.id?.toLowerCase() - ) - }) - return price?.amount - ? humanizeAmount( - price?.amount, - priceData.region!.currency_code! - ).toString() - : "" - }, - entityName: "variant", - }, - } - } - } - } - - private buildProductVariantLines(product: Product): string[] { - const outputLineData: string[] = [] - - for (const variant of product.variants) { - const variantLineData: string[] = [] - for (const [, { exportDescriptor: columnSchema }] of Object.entries( - this.columnsDefinition - )) { - if (!columnSchema || "isDynamic" in columnSchema) { - continue - } - - if (columnSchema.entityName === "product") { - const formattedContent = csvCellContentFormatter( - columnSchema.accessor(product) - ) - variantLineData.push(formattedContent) - } - if (columnSchema.entityName === "variant") { - const formattedContent = csvCellContentFormatter( - columnSchema.accessor(variant, { product: product }) - ) - variantLineData.push(formattedContent) - } - } - outputLineData.push(variantLineData.join(this.DELIMITER_) + this.NEWLINE_) - } - - return outputLineData - } - - private async onProcessCanceled( - batchJobId: string, - fileKey: string - ): Promise { - const transactionManager = this.transactionManager_ ?? this.manager_ - await this.fileService_ - .withTransaction(transactionManager) - .delete({ fileKey }) - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJobId, { - result: { - file_key: undefined, - file_size: undefined, - }, - }) - } - - /** - * Return the maximum number of each relation that must appears in the export. - * The number of item of a relation can vary between 0-Infinity and therefore the number of columns - * that will be added to the export correspond to that number - * @param products - The main entity to get the relation shape from - * @return ({ - * optionColumnCount: number - * imageColumnCount: number - * salesChannelsColumnCount: number - * pricesData: Set - * }) - * @private - */ - private getProductRelationsDynamicColumnsShape(products: Product[]): { - optionColumnCount: number - imageColumnCount: number - salesChannelsColumnCount: number - productCategoriesColumnCount: number - pricesData: Set - } { - let optionColumnCount = 0 - let imageColumnCount = 0 - let salesChannelsColumnCount = 0 - let productCategoriesColumnCount = 0 - const pricesData = new Set() - - // Retrieve the highest count of each object to build the dynamic columns later - for (const product of products) { - const optionsCount = product?.options?.length ?? 0 - optionColumnCount = Math.max(optionColumnCount, optionsCount) - - const imageCount = product?.images?.length ?? 0 - imageColumnCount = Math.max(imageColumnCount, imageCount) - - if ( - this.featureFlagRouter_.isFeatureEnabled(SalesChannelFeatureFlag.key) - ) { - const salesChannelCount = - (product as Product)?.sales_channels?.length ?? 0 - salesChannelsColumnCount = Math.max( - salesChannelsColumnCount, - salesChannelCount - ) - } - - if ( - this.featureFlagRouter_.isFeatureEnabled(ProductCategoryFeatureFlag.key) - ) { - const categoriesCount = product?.categories?.length ?? 0 - productCategoriesColumnCount = Math.max( - productCategoriesColumnCount, - categoriesCount - ) - } - - for (const variant of product?.variants ?? []) { - if (variant.prices?.length) { - variant.prices.forEach((price) => { - pricesData.add( - JSON.stringify({ - currency_code: price.currency_code, - region: price.region - ? { - currency_code: price.region.currency_code, - name: price.region.name, - id: price.region.id, - } - : null, - }) - ) - }) - } - } - } - - return { - optionColumnCount, - imageColumnCount, - salesChannelsColumnCount, - productCategoriesColumnCount, - pricesData, - } - } -} diff --git a/packages/medusa/src/strategies/batch-jobs/product/import.ts b/packages/medusa/src/strategies/batch-jobs/product/import.ts deleted file mode 100644 index 30f0189c80..0000000000 --- a/packages/medusa/src/strategies/batch-jobs/product/import.ts +++ /dev/null @@ -1,935 +0,0 @@ -/* eslint-disable valid-jsdoc */ -import { - CreateProductVariants, - UpdateProductVariants, - createProducts, - updateProducts, -} from "@medusajs/core-flows" -import { ProductWorkflow } from "@medusajs/types" -import { FlagRouter, MedusaV2Flag, promiseAll } from "@medusajs/utils" -import { MedusaError, computerizeAmount } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import { AbstractBatchJobStrategy, IFileService } from "../../../interfaces" -import ProductCategoryFeatureFlag from "../../../loaders/feature-flags/product-categories" -import SalesChannelFeatureFlag from "../../../loaders/feature-flags/sales-channels" -import { BatchJob, SalesChannel } from "../../../models" -import { - BatchJobService, - ProductCategoryService, - ProductCollectionService, - ProductService, - ProductVariantService, - RegionService, - SalesChannelService, - ShippingProfileService, -} from "../../../services" -import CsvParser from "../../../services/csv-parser" -import { CreateProductInput } from "../../../types/product" -import { CreateProductVariantInput } from "../../../types/product-variant" -import { - OperationType, - ProductImportBatchJob, - ProductImportCsvSchema, - ProductImportInjectedProps, - ProductImportJobContext, - TParsedProductImportRowData, -} from "./types" -import { - productImportColumnsDefinition, - productImportProductCategoriesColumnsDefinition, - productImportSalesChannelsColumnsDefinition, -} from "./types/columns-definition" -import { transformProductData, transformVariantData } from "./utils" - -/** - * Process this many variant rows before reporting progress. - */ -const BATCH_SIZE = 100 - -/** - * Default strategy class used for a batch import of products/variants. - */ -class ProductImportStrategy extends AbstractBatchJobStrategy { - static identifier = "product-import-strategy" - - static batchType = "product-import" - - private processedCounter: Record = {} - - protected readonly featureFlagRouter_: FlagRouter - - protected manager_: EntityManager - protected transactionManager_: EntityManager | undefined - - protected readonly fileService_: IFileService - - protected readonly regionService_: RegionService - protected readonly productService_: ProductService - protected readonly batchJobService_: BatchJobService - protected readonly productCollectionService_: ProductCollectionService - protected readonly salesChannelService_: SalesChannelService - protected readonly productVariantService_: ProductVariantService - protected readonly shippingProfileService_: ShippingProfileService - protected readonly productCategoryService_: ProductCategoryService - - protected readonly csvParser_: CsvParser< - ProductImportCsvSchema, - Record, - Record - > - - constructor({ - batchJobService, - productService, - salesChannelService, - productVariantService, - shippingProfileService, - regionService, - fileService, - productCollectionService, - productCategoryService, - manager, - featureFlagRouter, - }: ProductImportInjectedProps) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - const isSalesChannelsFeatureOn = featureFlagRouter.isFeatureEnabled( - SalesChannelFeatureFlag.key - ) - - const isProductCategoriesFeatureOn = featureFlagRouter.isFeatureEnabled( - ProductCategoryFeatureFlag.key - ) - - this.csvParser_ = new CsvParser({ - columns: [ - ...productImportColumnsDefinition.columns, - ...(isSalesChannelsFeatureOn - ? productImportSalesChannelsColumnsDefinition.columns - : []), - ...(isProductCategoriesFeatureOn - ? productImportProductCategoriesColumnsDefinition.columns - : []), - ], - }) - - this.featureFlagRouter_ = featureFlagRouter - this.manager_ = manager - this.fileService_ = fileService - this.batchJobService_ = batchJobService - this.productService_ = productService - this.salesChannelService_ = salesChannelService - this.productVariantService_ = productVariantService - this.shippingProfileService_ = shippingProfileService - this.regionService_ = regionService - this.productCollectionService_ = productCollectionService - this.productCategoryService_ = productCategoryService - } - - async buildTemplate(): Promise { - throw new Error("Not implemented!") - } - - /** - * Create a description of a row on which the error occurred and throw a Medusa error. - * - * @param row - Parsed CSV row data - * @param errorDescription - Concrete error - */ - protected static throwDescriptiveError( - row: TParsedProductImportRowData, - errorDescription?: string - ): never { - const message = `Error while processing row with - [(product id: ${row["product.id"]}), - (product handle: ${row["product.handle"]}), - (variant id: ${row["variant.id"]}), - (variant sku: ${row["variant.sku"]})]: - ${errorDescription}` - - throw new MedusaError(MedusaError.Types.INVALID_DATA, message) - } - - /** - * Generate instructions for update/create of products/variants from parsed CSV rows. - * - * @param csvData - An array of parsed CSV rows. - */ - async getImportInstructions( - csvData: TParsedProductImportRowData[] - ): Promise> { - const transactionManager = this.transactionManager_ ?? this.manager_ - const shippingProfile = await this.shippingProfileService_ - .withTransaction(transactionManager) - .retrieveDefault() - - const seenProducts = {} - - const productsCreate: TParsedProductImportRowData[] = [] - const productsUpdate: TParsedProductImportRowData[] = [] - - const variantsCreate: TParsedProductImportRowData[] = [] - const variantsUpdate: TParsedProductImportRowData[] = [] - - for (const row of csvData) { - if ((row["variant.prices"] as Record[])?.length) { - await this.prepareVariantPrices(row) - } - - if (row["variant.id"]) { - variantsUpdate.push(row) - } else { - variantsCreate.push(row) - } - - // save only first occurrence - if (!seenProducts[row["product.handle"] as string]) { - row["product.profile_id"] = shippingProfile!.id - if (row["product.id"]) { - productsUpdate.push(row) - } else { - productsCreate.push(row) - } - - seenProducts[row["product.handle"] as string] = true - } - } - - return { - [OperationType.ProductCreate]: productsCreate, - [OperationType.VariantCreate]: variantsCreate, - [OperationType.ProductUpdate]: productsUpdate, - [OperationType.VariantUpdate]: variantsUpdate, - } - } - - /** - * Prepare prices records for insert - find and append region ids to records that contain a region name. - * - * @param row - An object containing parsed row data. - */ - protected async prepareVariantPrices(row): Promise { - const transactionManager = this.transactionManager_ ?? this.manager_ - - const prices: Record[] = [] - - for (const price of row["variant.prices"]) { - const record: Record = { - amount: price.amount, - } - - if (price.regionName) { - try { - const region = await this.regionService_ - .withTransaction(transactionManager) - .retrieveByName(price.regionName) - - record.region_id = region.id - record.currency_code = region.currency_code - } catch (e) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Trying to set a price for a region ${price.regionName} that doesn't exist` - ) - } - } else { - record.currency_code = price.currency_code - } - - record.amount = computerizeAmount( - Number(record.amount), - record.currency_code as string - ) - prices.push(record) - } - - row["variant.prices"] = prices - } - - /** - * A worker method called after a batch job has been created. - * The method parses a CSV file, generates sets of instructions - * for processing and stores these instructions to a JSON file - * which is uploaded to a bucket. - * - * @param batchJobId - An id of a job that is being preprocessed. - */ - async preProcessBatchJob(batchJobId: string): Promise { - const transactionManager = this.transactionManager_ ?? this.manager_ - const batchJob = await this.batchJobService_ - .withTransaction(transactionManager) - .retrieve(batchJobId) - - const csvFileKey = (batchJob.context as ProductImportJobContext).fileKey - const csvStream = await this.fileService_.getDownloadStream({ - fileKey: csvFileKey, - }) - - let builtData: Record[] - try { - const parsedData = await this.csvParser_.parse(csvStream) - builtData = await this.csvParser_.buildData(parsedData) - } catch (e) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "The csv file parsing failed due to: " + e.message - ) - } - - const ops = await this.getImportInstructions(builtData) - - await this.uploadImportOpsFile(batchJobId, ops) - - let totalOperationCount = 0 - const operationsCounts = {} - - Object.keys(ops).forEach((key) => { - operationsCounts[key] = ops[key].length - totalOperationCount += ops[key].length - }) - - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJobId, { - result: { - advancement_count: 0, - // number of update/create operations to execute - count: totalOperationCount, - operations: operationsCounts, - stat_descriptors: [ - { - key: "product-import-count", - name: "Products/variants to import", - message: `There will be ${ - ops[OperationType.ProductCreate].length - } products created (${ - ops[OperationType.ProductUpdate].length - } updated). - ${ - ops[OperationType.VariantCreate].length - } variants will be created and ${ - ops[OperationType.VariantUpdate].length - } updated`, - }, - ], - }, - }) - } - - /** - * The main processing method called after a batch job - * is ready/confirmed for processing. - * - * @param batchJobId - An id of a batch job that is being processed. - */ - async processJob(batchJobId: string): Promise { - return await this.atomicPhase_(async (manager) => { - const batchJob = (await this.batchJobService_ - .withTransaction(manager) - .retrieve(batchJobId)) as ProductImportBatchJob - - await this.createProducts(batchJob) - await this.updateProducts(batchJob) - await this.createVariants(batchJob) - await this.updateVariants(batchJob) - await this.finalize(batchJob) - }) - } - - /** - * Create, or retrieve by name, sales channels from the input data. - * - * NOTE: Sales channel names provided in the CSV must exist in the DB. - * New sales channels will not be created. - * - * @param data an array of sales channels partials - * @return an array of sales channels created or retrieved by name - */ - private async processSalesChannels( - data: Pick[] - ): Promise { - const transactionManager = this.transactionManager_ ?? this.manager_ - const salesChannelServiceTx = - this.salesChannelService_.withTransaction(transactionManager) - - const salesChannels: SalesChannel[] = [] - - for (const input of data) { - let channel: SalesChannel | null = null - - if (input.id) { - try { - channel = await salesChannelServiceTx.retrieve(input.id, { - select: ["id"], - }) - } catch (e) { - // noop - check if the channel exists with provided name - } - } - - if (!channel) { - try { - channel = (await salesChannelServiceTx.retrieveByName(input.name, { - select: ["id"], - })) as SalesChannel - } catch (e) { - // noop - } - } - - if (channel) { - salesChannels.push(channel) - } - } - - return salesChannels - } - - /** - * Method retrieves product categories from handles provided in the CSV. - * - * @param data array of product category handles - */ - private async processCategories( - data: { handle: string }[] - ): Promise<{ id: string }[]> { - const retIds: { id: string }[] = [] - const transactionManager = this.transactionManager_ ?? this.manager_ - const productCategoryService = - this.productCategoryService_.withTransaction(transactionManager) - - for (const category of data) { - const categoryPartial = (await productCategoryService.retrieveByHandle( - category.handle, - { - select: ["id"], - } - )) as { id: string } - - retIds.push(categoryPartial) - } - - return retIds - } - - /** - * Method creates products using `ProductService` and parsed data from a CSV row. - * - * @param batchJob - The current batch job being processed. - */ - private async createProducts(batchJob: ProductImportBatchJob): Promise { - if (!batchJob.result.operations[OperationType.ProductCreate]) { - return - } - - const isMedusaV2Enabled = this.featureFlagRouter_.isFeatureEnabled( - MedusaV2Flag.key - ) - - const transactionManager = this.transactionManager_ ?? this.manager_ - - const productOps = await this.downloadImportOpsFile( - batchJob, - OperationType.ProductCreate - ) - - const productServiceTx = - this.productService_.withTransaction(transactionManager) - const productCollectionServiceTx = - this.productCollectionService_.withTransaction(transactionManager) - - const isSalesChannelsFeatureOn = this.featureFlagRouter_.isFeatureEnabled( - SalesChannelFeatureFlag.key - ) - - const isProductCategoriesFeatureOn = - this.featureFlagRouter_.isFeatureEnabled(ProductCategoryFeatureFlag.key) - - for (const productOp of productOps) { - const productData = transformProductData(productOp) - - try { - if (isSalesChannelsFeatureOn && productOp["product.sales_channels"]) { - productData["sales_channels"] = await this.processSalesChannels( - productOp["product.sales_channels"] as Pick< - SalesChannel, - "name" | "id" | "description" - >[] - ) - } - - if ( - productOp["product.collection.handle"] != null && - productOp["product.collection.handle"] !== "" - ) { - productData.collection_id = ( - await productCollectionServiceTx.retrieveByHandle( - productOp["product.collection.handle"] as string, - { select: ["id"] } - ) - ).id - delete productData.collection - } - - if (isProductCategoriesFeatureOn && productOp["product.categories"]) { - productData["categories"] = await this.processCategories( - productOp["product.categories"] as { handle: string }[] - ) - } - - if (isMedusaV2Enabled) { - const createProductWorkflow = createProducts(this.__container__) - - const input = { - products: [ - productData, - ] as unknown as ProductWorkflow.CreateProductInputDTO[], - } - - await createProductWorkflow.run({ - input, - context: { - manager: transactionManager, - }, - }) - } else { - // TODO: we should only pass the expected data and should not have to cast the entire object. Here we are passing everything contained in productData - await productServiceTx.create( - productData as unknown as CreateProductInput - ) - } - } catch (e) { - ProductImportStrategy.throwDescriptiveError(productOp, e.message) - } - - await this.updateProgress(batchJob.id) - } - } - - /** - * Method updates existing products in the DB using a CSV row data. - * - * @param batchJob - The current batch job being processed. - */ - private async updateProducts(batchJob: ProductImportBatchJob): Promise { - if (!batchJob.result.operations[OperationType.ProductUpdate]) { - return - } - - const isMedusaV2Enabled = this.featureFlagRouter_.isFeatureEnabled( - MedusaV2Flag.key - ) - - const transactionManager = this.transactionManager_ ?? this.manager_ - const productOps = await this.downloadImportOpsFile( - batchJob, - OperationType.ProductUpdate - ) - - const productServiceTx = - this.productService_.withTransaction(transactionManager) - const productCollectionServiceTx = - this.productCollectionService_.withTransaction(transactionManager) - - const isSalesChannelsFeatureOn = this.featureFlagRouter_.isFeatureEnabled( - SalesChannelFeatureFlag.key - ) - - const isProductCategoriesFeatureOn = - this.featureFlagRouter_.isFeatureEnabled(ProductCategoryFeatureFlag.key) - - for (const productOp of productOps) { - const productData = transformProductData(productOp) - try { - if (isSalesChannelsFeatureOn && productOp["product.sales_channels"]) { - productData["sales_channels"] = await this.processSalesChannels( - productOp["product.sales_channels"] as Pick< - SalesChannel, - "name" | "id" | "description" - >[] - ) - } - - delete productData.options // for now not supported in the update method - - if ( - productOp["product.collection.handle"] != null && - productOp["product.collection.handle"] !== "" - ) { - productData.collection_id = ( - await productCollectionServiceTx.retrieveByHandle( - productOp["product.collection.handle"] as string, - { select: ["id"] } - ) - ).id - delete productData.collection - } - - if (isProductCategoriesFeatureOn && productOp["product.categories"]) { - productData["categories"] = await this.processCategories( - productOp["product.categories"] as { handle: string }[] - ) - } - - if (isMedusaV2Enabled) { - const updateProductWorkflow = updateProducts(this.__container__) - - const input = { - products: [ - { - id: productOp["product.id"] as string, - ...productData, - }, - ], - } - - await updateProductWorkflow.run({ - input, - context: { - manager: transactionManager, - }, - }) - } else { - // TODO: we should only pass the expected data. Here we are passing everything contained in productData - await productServiceTx.update( - productOp["product.id"] as string, - productData - ) - } - } catch (e) { - ProductImportStrategy.throwDescriptiveError(productOp, e.message) - } - - await this.updateProgress(batchJob.id) - } - } - - /** - * Method creates product variants from a CSV data. - * Method also handles processing of variant options. - * - * @param batchJob - The current batch job being processed. - */ - private async createVariants(batchJob: ProductImportBatchJob): Promise { - if (!batchJob.result.operations[OperationType.VariantCreate]) { - return - } - - const isMedusaV2Enabled = this.featureFlagRouter_.isFeatureEnabled( - MedusaV2Flag.key - ) - - const transactionManager = this.transactionManager_ ?? this.manager_ - - const variantOps = await this.downloadImportOpsFile( - batchJob, - OperationType.VariantCreate - ) - - for (const variantOp of variantOps) { - try { - const variant = transformVariantData(variantOp) - - const product = await this.productService_ - .withTransaction(transactionManager) - .retrieveByHandle(variantOp["product.handle"] as string, { - relations: ["variants", "variants.options", "options"], - }) - - const optionIds = - (variantOp["product.options"] as Record[])?.map( - (variantOption) => - product!.options.find( - (createdProductOption) => - createdProductOption.title === variantOption.title - )?.id - ) || [] - - variant.options = - (variant.options as Record[])?.map((o, index) => ({ - ...o, - option_id: optionIds[index], - })) || [] - - delete variant.id - delete variant.product - - if (isMedusaV2Enabled) { - const createProductVariantsWorkflow = - CreateProductVariants.createProductVariants(this.__container__) - - const input: ProductWorkflow.CreateProductVariantsWorkflowInputDTO = { - productVariants: [ - { - ...variant, - product_id: product.id, - }, - ], - } - - await createProductVariantsWorkflow.run({ - input, - context: { - manager: transactionManager, - }, - }) - } else { - await this.productVariantService_ - .withTransaction(transactionManager) - .create(product!, variant as unknown as CreateProductVariantInput) - } - - await this.updateProgress(batchJob.id) - } catch (e) { - ProductImportStrategy.throwDescriptiveError(variantOp, e.message) - } - } - } - - /** - * Method updates product variants from a CSV data. - * - * @param batchJob - The current batch job being processed. - */ - private async updateVariants(batchJob: ProductImportBatchJob): Promise { - if (!batchJob.result.operations[OperationType.VariantUpdate]) { - return - } - - const isMedusaV2Enabled = this.featureFlagRouter_.isFeatureEnabled( - MedusaV2Flag.key - ) - - const transactionManager = this.transactionManager_ ?? this.manager_ - - const variantOps = await this.downloadImportOpsFile( - batchJob, - OperationType.VariantUpdate - ) - - const productServiceTx = - this.productService_.withTransaction(transactionManager) - - for (const variantOp of variantOps) { - try { - const product = await productServiceTx.retrieveByHandle( - variantOp["product.handle"] as string - ) - - await this.prepareVariantOptions(variantOp, product.id!) - - const updateData = transformVariantData(variantOp) - delete updateData.product - delete updateData["product.handle"] - - if (isMedusaV2Enabled) { - const updateProductVariantsWorkflow = - UpdateProductVariants.updateProductVariants(this.__container__) - - const input: ProductWorkflow.UpdateProductVariantsWorkflowInputDTO = { - productVariants: [ - { - id: variantOp["variant.id"] as string, - ...updateData, - }, - ], - } - - await updateProductVariantsWorkflow.run({ - input, - context: { - manager: transactionManager, - }, - }) - } else { - await this.productVariantService_ - .withTransaction(transactionManager) - .update(variantOp["variant.id"] as string, updateData) - } - } catch (e) { - ProductImportStrategy.throwDescriptiveError(variantOp, e.message) - } - - await this.updateProgress(batchJob.id) - } - } - - /** - * Extend records used for creating variant options with corresponding product option ids. - * - * @param variantOp - Parsed row data form CSV - * @param productId - id of variant's product - */ - protected async prepareVariantOptions( - variantOp, - productId: string - ): Promise { - const transactionManager = this.transactionManager_ ?? this.manager_ - const productOptions = variantOp["variant.options"] || [] - - const productServiceTx = - this.productService_.withTransaction(transactionManager) - for (const o of productOptions) { - const option = await productServiceTx.retrieveOptionByTitle( - o._title, - productId - ) - o.option_id = option?.id - } - } - - /** - * Store import ops JSON file to a bucket. - * - * @param batchJobId - An id of the current batch job being processed. - * @param results - An object containing parsed CSV data. - */ - protected async uploadImportOpsFile( - batchJobId: string, - results: Record - ): Promise { - const uploadPromises: Promise[] = [] - const transactionManager = this.transactionManager_ ?? this.manager_ - - const files: Record = {} - - for (const op in results) { - if (results[op]?.length) { - const { writeStream, fileKey, promise } = await this.fileService_ - .withTransaction(transactionManager) - .getUploadStreamDescriptor({ - name: ProductImportStrategy.buildFilename(batchJobId, op), - ext: "json", - }) - - uploadPromises.push(promise) - - files[op] = fileKey - writeStream.write(JSON.stringify(results[op])) - writeStream.end() - } - } - - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJobId, { - result: { files }, - }) - - await promiseAll(uploadPromises) - } - - /** - * Download parsed ops JSON file. - * - * @param batchJob - the current batch job being processed - * @param op - Type of import operation. - */ - protected async downloadImportOpsFile( - batchJob: BatchJob, - op: OperationType - ): Promise { - let data = "" - const transactionManager = this.transactionManager_ ?? this.manager_ - - const readableStream = await this.fileService_ - .withTransaction(transactionManager) - .getDownloadStream({ - fileKey: batchJob.result.files![op], - }) - - return await new Promise((resolve) => { - readableStream.on("data", (chunk) => { - data += chunk - }) - readableStream.on("end", () => { - resolve(JSON.parse(data)) - }) - readableStream.on("error", () => { - // TODO: maybe should throw - resolve([] as TParsedProductImportRowData[]) - }) - }) - } - - /** - * Delete parsed CSV ops files. - * - * @param batchJob - the current batch job being processed - */ - protected async deleteOpsFiles(batchJob: BatchJob): Promise { - const transactionManager = this.transactionManager_ ?? this.manager_ - - const fileServiceTx = this.fileService_.withTransaction(transactionManager) - for (const fileName of Object.values(batchJob.result.files!)) { - try { - await fileServiceTx.delete({ - fileKey: fileName, - }) - } catch (e) { - // noop - } - } - } - - /** - * Update count of processed data in the batch job `result` column - * and cleanup temp JSON files. - * - * @param batchJob - The current batch job being processed. - */ - private async finalize(batchJob: BatchJob): Promise { - const transactionManager = this.transactionManager_ ?? this.manager_ - - delete this.processedCounter[batchJob.id] - - await this.batchJobService_ - .withTransaction(transactionManager) - .update(batchJob.id, { - result: { advancement_count: batchJob.result.count }, - }) - - const { fileKey } = batchJob.context as ProductImportJobContext - - await this.fileService_ - .withTransaction(transactionManager) - .delete({ fileKey }) - - await this.deleteOpsFiles(batchJob) - } - - /** - * Store the progress in the batch job `result` column. - * Method is called after every update/create operation, - * but after every `BATCH_SIZE` processed rows info is written to the DB. - * - * @param batchJobId - An id of the current batch job being processed. - */ - private async updateProgress(batchJobId: string): Promise { - const newCount = (this.processedCounter[batchJobId] || 0) + 1 - this.processedCounter[batchJobId] = newCount - if (newCount % BATCH_SIZE !== 0) { - return - } - - await this.batchJobService_ - .withTransaction(this.transactionManager_ ?? this.manager_) - .update(batchJobId, { - result: { - advancement_count: newCount, - }, - }) - } - - private static buildFilename( - batchJobId: string, - operation: string, - { appendExt }: { appendExt?: string } = { appendExt: undefined } - ): string { - const filename = `imports/products/ops/${batchJobId}-${operation}` - return appendExt ? filename + appendExt : filename - } -} - -export default ProductImportStrategy diff --git a/packages/medusa/src/strategies/batch-jobs/product/types/columns-definition.ts b/packages/medusa/src/strategies/batch-jobs/product/types/columns-definition.ts deleted file mode 100644 index 8eb717f61a..0000000000 --- a/packages/medusa/src/strategies/batch-jobs/product/types/columns-definition.ts +++ /dev/null @@ -1,834 +0,0 @@ -import { Product, ProductVariant } from "../../../../models" -import { - ProductColumnDefinition, - ProductExportPriceData, - TBuiltProductImportLine, - TParsedProductImportRowData, -} from "./index" -import { CsvSchema, CsvSchemaColumn } from "../../../../interfaces/csv-parser" - -export const productColumnsDefinition: ProductColumnDefinition = { - "Product Id": { - name: "Product Id", - importDescriptor: { - mapTo: "product.id", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.id ?? "", - entityName: "product", - }, - }, - "Product Handle": { - name: "Product Handle", - importDescriptor: { - mapTo: "product.handle", - required: true, - }, - exportDescriptor: { - accessor: (product: Product): string => product?.handle ?? "", - entityName: "product", - }, - }, - "Product Title": { - name: "Product Title", - importDescriptor: { - mapTo: "product.title", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.title ?? "", - entityName: "product", - }, - }, - "Product Subtitle": { - name: "Product Subtitle", - importDescriptor: { - mapTo: "product.subtitle", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.subtitle ?? "", - entityName: "product", - }, - }, - "Product Description": { - name: "Product Description", - importDescriptor: { - mapTo: "product.description", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.description ?? "", - entityName: "product", - }, - }, - "Product Status": { - name: "Product Status", - importDescriptor: { - mapTo: "product.status", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.status ?? "", - entityName: "product", - }, - }, - "Product Thumbnail": { - name: "Product Thumbnail", - importDescriptor: { - mapTo: "product.thumbnail", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.thumbnail ?? "", - entityName: "product", - }, - }, - "Product Weight": { - name: "Product Weight", - importDescriptor: { - mapTo: "product.weight", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.weight?.toString() ?? "", - entityName: "product", - }, - }, - "Product Length": { - name: "Product Length", - importDescriptor: { - mapTo: "product.length", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.length?.toString() ?? "", - entityName: "product", - }, - }, - "Product Width": { - name: "Product Width", - importDescriptor: { - mapTo: "product.width", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.width?.toString() ?? "", - entityName: "product", - }, - }, - "Product Height": { - name: "Product Height", - importDescriptor: { - mapTo: "product.height", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.height?.toString() ?? "", - entityName: "product", - }, - }, - "Product HS Code": { - name: "Product HS Code", - importDescriptor: { - mapTo: "product.hs_code", - }, - exportDescriptor: { - accessor: (product: Product): string => - product?.hs_code?.toString() ?? "", - entityName: "product", - }, - }, - "Product Origin Country": { - name: "Product Origin Country", - importDescriptor: { - mapTo: "product.origin_country", - }, - exportDescriptor: { - accessor: (product: Product): string => - product?.origin_country?.toString() ?? "", - entityName: "product", - }, - }, - "Product MID Code": { - name: "Product MID Code", - importDescriptor: { - mapTo: "product.mid_code", - }, - exportDescriptor: { - accessor: (product: Product): string => - product?.mid_code?.toString() ?? "", - entityName: "product", - }, - }, - "Product Material": { - name: "Product Material", - importDescriptor: { - mapTo: "product.material", - }, - exportDescriptor: { - accessor: (product: Product): string => - product?.material?.toString() ?? "", - entityName: "product", - }, - }, - - // PRODUCT-COLLECTION - - "Product Collection Title": { - name: "Product Collection Title", - importDescriptor: { - mapTo: "product.collection.title", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.collection?.title ?? "", - entityName: "product", - }, - }, - "Product Collection Handle": { - name: "Product Collection Handle", - importDescriptor: { - mapTo: "product.collection.handle", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.collection?.handle ?? "", - entityName: "product", - }, - }, - - // PRODUCT-TYPE - - "Product Type": { - name: "Product Type", - importDescriptor: { - match: /Product Type/, - reducer: ( - builtLine: TParsedProductImportRowData, - key, - value - ): TBuiltProductImportLine => { - if (typeof value === "undefined" || value === null) { - builtLine["product.type"] = undefined - } else { - builtLine["product.type.value"] = value - } - - return builtLine - }, - }, - exportDescriptor: { - accessor: (product: Product): string => product?.type?.value ?? "", - entityName: "product", - }, - }, - - // PRODUCT-TAGS - - "Product Tags": { - name: "Product Tags", - importDescriptor: { - mapTo: "product.tags", - transform: (value: string) => { - return value && `${value}`.split(",").map((v) => ({ value: v })) - }, - }, - exportDescriptor: { - accessor: (product: Product): string => - (product.tags.map((t) => t.value) ?? []).join(","), - entityName: "product", - }, - }, - - // - - "Product Discountable": { - name: "Product Discountable", - importDescriptor: { - mapTo: "product.discountable", - }, - exportDescriptor: { - accessor: (product: Product): string => - product?.discountable?.toString() ?? "", - entityName: "product", - }, - }, - "Product External Id": { - name: "Product External Id", - importDescriptor: { - mapTo: "product.external_id", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.external_id ?? "", - entityName: "product", - }, - }, - - // PRODUCT-PROFILE - - "Product Profile Name": { - name: "Product Profile Name", - importDescriptor: { - mapTo: "__not_supported__", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.profile?.name ?? "", - entityName: "product", - }, - }, - - "Product Profile Type": { - name: "Product Profile Type", - importDescriptor: { - mapTo: "__not_supported__", - }, - exportDescriptor: { - accessor: (product: Product): string => product?.profile?.type ?? "", - entityName: "product", - }, - }, - - // VARIANTS - - "Variant Id": { - name: "Variant Id", - importDescriptor: { - mapTo: "variant.id", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => variant?.id ?? "", - entityName: "variant", - }, - }, - "Variant Title": { - name: "Variant Title", - - importDescriptor: { - mapTo: "variant.title", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => variant?.title ?? "", - entityName: "variant", - }, - }, - "Variant SKU": { - name: "Variant SKU", - - importDescriptor: { - mapTo: "variant.sku", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => variant?.sku ?? "", - entityName: "variant", - }, - }, - "Variant Barcode": { - name: "Variant Barcode", - - importDescriptor: { - mapTo: "variant.barcode", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => variant?.barcode ?? "", - entityName: "variant", - }, - }, - "Variant Inventory Quantity": { - name: "Variant Inventory Quantity", - - importDescriptor: { - mapTo: "variant.inventory_quantity", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => - variant?.inventory_quantity?.toString() ?? "", - entityName: "variant", - }, - }, - "Variant Allow Backorder": { - name: "Variant Allow Backorder", - - importDescriptor: { - mapTo: "variant.allow_backorder", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => - variant?.allow_backorder?.toString() ?? "", - entityName: "variant", - }, - }, - "Variant Manage Inventory": { - name: "Variant Manage Inventory", - importDescriptor: { - mapTo: "variant.manage_inventory", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => - variant?.manage_inventory?.toString() ?? "", - entityName: "variant", - }, - }, - "Variant Weight": { - name: "Variant Weight", - - importDescriptor: { - mapTo: "variant.weight", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => - variant?.weight?.toString() ?? "", - entityName: "variant", - }, - }, - "Variant Length": { - name: "Variant Length", - - importDescriptor: { - mapTo: "variant.length", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => - variant?.length?.toString() ?? "", - entityName: "variant", - }, - }, - "Variant Width": { - name: "Variant Width", - importDescriptor: { - mapTo: "variant.width", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => - variant?.width?.toString() ?? "", - entityName: "variant", - }, - }, - "Variant Height": { - name: "Variant Height", - importDescriptor: { - mapTo: "variant.height", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => - variant?.height?.toString() ?? "", - entityName: "variant", - }, - }, - "Variant HS Code": { - name: "Variant HS Code", - importDescriptor: { - mapTo: "variant.hs_code", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => - variant?.hs_code?.toString() ?? "", - entityName: "variant", - }, - }, - "Variant Origin Country": { - name: "Variant Origin Country", - importDescriptor: { - mapTo: "variant.origin_country", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => - variant?.origin_country?.toString() ?? "", - entityName: "variant", - }, - }, - "Variant MID Code": { - name: "Variant MID Code", - importDescriptor: { - mapTo: "variant.mid_code", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => - variant?.mid_code?.toString() ?? "", - entityName: "variant", - }, - }, - "Variant Material": { - name: "Variant Material", - importDescriptor: { - mapTo: "variant.material", - }, - exportDescriptor: { - accessor: (variant: ProductVariant): string => - variant?.material?.toString() ?? "", - entityName: "variant", - }, - }, - - // ==== DYNAMIC FIELDS ==== - - // PRODUCT_OPTIONS - - "Option Name": { - name: "Option Name", - importDescriptor: { - match: /Option \d+ Name/, - reducer: (builtLine, key, value): TBuiltProductImportLine => { - builtLine["product.options"] = builtLine["product.options"] || [] - - if (typeof value === "undefined" || value === null) { - return builtLine - } - - const options = builtLine["product.options"] as Record< - string, - string | number - >[] - - options.push({ title: value }) - - return builtLine - }, - }, - exportDescriptor: { - isDynamic: true, - buildDynamicColumnName: (index: number) => { - return `Option ${index + 1} Name` - }, - }, - }, - "Option Value": { - name: "Option Value", - importDescriptor: { - match: /Option \d+ Value/, - reducer: ( - builtLine: TParsedProductImportRowData, - key: string, - value: string, - context: any - ): TBuiltProductImportLine => { - builtLine["variant.options"] = builtLine["variant.options"] || [] - - if (typeof value === "undefined" || value === null) { - return builtLine - } - - const options = builtLine["variant.options"] as Record< - string, - string | number - >[] - - options.push({ - value, - _title: context.line[key.slice(0, -6) + " Name"], - }) - - return builtLine - }, - }, - exportDescriptor: { - isDynamic: true, - buildDynamicColumnName: (index: number) => { - return `Option ${index + 1} Value` - }, - }, - }, - - // PRICES - - "Price Region": { - name: "Price Region", - importDescriptor: { - match: /Price (.*) \[([A-Z]{3})\]/, - reducer: ( - builtLine: TParsedProductImportRowData, - key, - value - ): TBuiltProductImportLine => { - builtLine["variant.prices"] = builtLine["variant.prices"] || [] - - if (typeof value === "undefined" || value === null) { - return builtLine - } - - const [, regionName] = - key.trim().match(/Price (.*) \[([A-Z]{3})\]/) || [] - ;( - builtLine["variant.prices"] as Record[] - ).push({ - amount: parseFloat(value), - regionName, - }) - - return builtLine - }, - }, - exportDescriptor: { - isDynamic: true, - buildDynamicColumnName: (data: ProductExportPriceData) => { - return `Price ${data.region?.name} ${ - data.region?.currency_code - ? "[" + data.region?.currency_code.toUpperCase() + "]" - : "" - }` - }, - }, - }, - "Price Currency": { - name: "Price Currency", - importDescriptor: { - match: /Price [A-Z]{3}/, - reducer: ( - builtLine: TParsedProductImportRowData, - key, - value - ): TBuiltProductImportLine => { - builtLine["variant.prices"] = builtLine["variant.prices"] || [] - - if (typeof value === "undefined" || value === null) { - return builtLine - } - - const currency = key.trim().split(" ")[1] - - ;( - builtLine["variant.prices"] as Record[] - ).push({ - amount: parseFloat(value), - currency_code: currency, - }) - - return builtLine - }, - }, - exportDescriptor: { - isDynamic: true, - buildDynamicColumnName: (data: ProductExportPriceData) => { - return `Price ${data.currency_code?.toUpperCase()}` - }, - }, - }, - // IMAGES - "Image Url": { - name: "Image Url", - importDescriptor: { - match: /Image \d+ Url/, - reducer: (builtLine: any, key, value): TBuiltProductImportLine => { - builtLine["product.images"] = builtLine["product.images"] || [] - - if (typeof value === "undefined" || value === null) { - return builtLine - } - - builtLine["product.images"].push(value) - - return builtLine - }, - }, - exportDescriptor: { - isDynamic: true, - buildDynamicColumnName: (index: number) => { - return `Image ${index + 1} Url` - }, - }, - }, -} - -export const productSalesChannelColumnsDefinition: ProductColumnDefinition = { - "Sales Channel Name": { - name: "Sales Channel Name", - importDescriptor: { - match: /Sales Channel \d+ Name/, - reducer: (builtLine, key, value): TBuiltProductImportLine => { - builtLine["product.sales_channels"] = - builtLine["product.sales_channels"] || [] - - if (typeof value === "undefined" || value === null) { - return builtLine - } - - const channels = builtLine["product.sales_channels"] as Record< - string, - string | number - >[] - - channels.push({ - name: value, - }) - - return builtLine - }, - }, - exportDescriptor: { - isDynamic: true, - buildDynamicColumnName: (index: number) => { - return `Sales Channel ${index + 1} Name` - }, - }, - }, - "Sales Channel Description": { - name: "Sales Channel Description", - importDescriptor: { - match: /Sales Channel \d+ Description/, - reducer: (builtLine, key, value): TBuiltProductImportLine => { - builtLine["product.sales_channels"] = - builtLine["product.sales_channels"] || [] - - if (typeof value === "undefined" || value === null) { - return builtLine - } - - const channels = builtLine["product.sales_channels"] as Record< - string, - string | number - >[] - - channels.push({ - description: value, - }) - - return builtLine - }, - }, - exportDescriptor: { - isDynamic: true, - buildDynamicColumnName: (index: number) => { - return `Sales Channel ${index + 1} Description` - }, - }, - }, - "Sales Channel Id": { - name: "Sales Channel Id", - importDescriptor: { - match: /Sales Channel \d+ Id/, - reducer: (builtLine, key, value): TBuiltProductImportLine => { - builtLine["product.sales_channels"] = - builtLine["product.sales_channels"] || [] - - if (typeof value === "undefined" || value === null) { - return builtLine - } - - const channels = builtLine["product.sales_channels"] as Record< - string, - string | number - >[] - - channels.push({ - id: value, - }) - - return builtLine - }, - }, - exportDescriptor: { - isDynamic: true, - buildDynamicColumnName: (index: number) => { - return `Sales Channel ${index + 1} Id` - }, - }, - }, -} - -export const productCategoriesColumnsDefinition: ProductColumnDefinition = { - "Product Category Handle": { - name: "Product Category Handle", - importDescriptor: { - match: /Product Category \d+ Handle/, - reducer: (builtLine, key, value): TBuiltProductImportLine => { - builtLine["product.categories"] = builtLine["product.categories"] || [] - - if (typeof value === "undefined" || value === null) { - return builtLine - } - - const categories = builtLine["product.categories"] as Record< - string, - string | number - >[] - - categories.push({ - handle: value, - }) - - return builtLine - }, - }, - exportDescriptor: { - isDynamic: true, - buildDynamicColumnName: (index: number) => { - return `Product Category ${index + 1} Handle` - }, - }, - }, - "Product Category Name": { - name: "Product Category Name", - importDescriptor: { - match: /Product Category \d+ Name/, - reducer: (builtLine) => builtLine, - }, - exportDescriptor: { - isDynamic: true, - buildDynamicColumnName: (index: number) => { - return `Product Category ${index + 1} Name` - }, - }, - }, - "Product Category Description": { - name: "Product Category Description", - importDescriptor: { - match: /Product Category \d+ Description/, - reducer: (builtLine) => builtLine, - }, - exportDescriptor: { - isDynamic: true, - buildDynamicColumnName: (index: number) => { - return `Product Category ${index + 1} Description` - }, - }, - }, -} - -export const productImportColumnsDefinition: CsvSchema< - TParsedProductImportRowData, - TBuiltProductImportLine -> = { - columns: Object.entries(productColumnsDefinition) - .map(([name, def]) => { - return def.importDescriptor && { name, ...def.importDescriptor } - }) - .filter( - ( - v - ): v is CsvSchemaColumn< - TParsedProductImportRowData, - TBuiltProductImportLine - > => { - return !!v - } - ), -} - -export const productImportSalesChannelsColumnsDefinition: CsvSchema< - TParsedProductImportRowData, - TBuiltProductImportLine -> = { - columns: Object.entries(productSalesChannelColumnsDefinition) - .map(([name, def]) => { - return def.importDescriptor && { name, ...def.importDescriptor } - }) - .filter( - ( - v - ): v is CsvSchemaColumn< - TParsedProductImportRowData, - TBuiltProductImportLine - > => { - return !!v - } - ), -} - -export const productImportProductCategoriesColumnsDefinition: CsvSchema< - TParsedProductImportRowData, - TBuiltProductImportLine -> = { - columns: Object.entries(productCategoriesColumnsDefinition) - .map(([name, def]) => { - return def.importDescriptor && { name, ...def.importDescriptor } - }) - .filter( - ( - v - ): v is CsvSchemaColumn< - TParsedProductImportRowData, - TBuiltProductImportLine - > => { - return !!v - } - ), -} diff --git a/packages/medusa/src/strategies/batch-jobs/product/types/index.ts b/packages/medusa/src/strategies/batch-jobs/product/types/index.ts deleted file mode 100644 index 09aa1fdb67..0000000000 --- a/packages/medusa/src/strategies/batch-jobs/product/types/index.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { RemoteQueryFunction } from "@medusajs/types" -import { FlagRouter } from "@medusajs/utils" -import { FileService } from "medusa-interfaces" -import { EntityManager } from "typeorm" -import { IFileService } from "../../../../interfaces" -import { CsvSchema, CsvSchemaColumn } from "../../../../interfaces/csv-parser" -import { BatchJob, Product, ProductVariant } from "../../../../models" -import { - BatchJobService, - ProductCategoryService, - ProductCollectionService, - ProductService, - ProductVariantService, - RegionService, - SalesChannelService, - ShippingProfileService, -} from "../../../../services" -import { Selector } from "../../../../types/common" - -export type ProductExportInjectedDependencies = { - manager: EntityManager - batchJobService: BatchJobService - productService: ProductService - fileService: IFileService - featureFlagRouter: FlagRouter - remoteQuery: RemoteQueryFunction -} - -export type ProductExportBatchJobContext = { - retry_count?: number - max_retry?: number - offset?: number - limit?: number - batch_size?: number - order?: string - fields?: string - expand?: string - shape: { - prices: ProductExportPriceData[] - dynamicOptionColumnCount: number - dynamicImageColumnCount: number - dynamicSalesChannelsColumnCount: number - dynamicProductCategoriesColumnCount: number - } - list_config?: { - select?: string[] - relations?: string[] - skip?: number - take?: number - order?: Record - } - filterable_fields?: Selector -} - -export type ProductExportBatchJob = BatchJob & { - context: ProductExportBatchJobContext -} - -export type ProductExportPriceData = { - currency_code?: string - region?: { name: string; currency_code: string; id: string } -} - -export type ProductExportColumnSchemaEntity = "product" | "variant" - -export type DynamicProductExportDescriptor = { - isDynamic: true - buildDynamicColumnName: (dataOrIndex: any) => string -} - -export type ProductExportDescriptor = - | { - accessor: (product: Product) => string - entityName: Extract - } - | { - accessor: ( - variant: ProductVariant, - context?: { product?: Product } - ) => string - entityName: Extract - } - -export type ProductImportInjectedProps = { - batchJobService: BatchJobService - productService: ProductService - productVariantService: ProductVariantService - shippingProfileService: ShippingProfileService - salesChannelService: SalesChannelService - regionService: RegionService - productCollectionService: ProductCollectionService - productCategoryService: ProductCategoryService - fileService: typeof FileService - - featureFlagRouter: FlagRouter - manager: EntityManager -} - -/** - * Import Batch job context column type. - */ -export type ProductImportJobContext = { - total: number - fileKey: string -} - -export type ProductImportBatchJob = BatchJob & { - result: Pick & { - operations: { - [K in keyof typeof OperationType]: number - } - } -} - -/** - * Schema definition of for an import CSV file. - */ -export type ProductImportCsvSchema = CsvSchema< - TParsedProductImportRowData, - TBuiltProductImportLine -> - -/** - * Supported batch job import ops. - */ -export enum OperationType { - ProductCreate = "PRODUCT_CREATE", - ProductUpdate = "PRODUCT_UPDATE", - VariantCreate = "VARIANT_CREATE", - VariantUpdate = "VARIANT_UPDATE", -} - -/** - * Data shape returned by the CSVParser. - */ -export type TParsedProductImportRowData = Record< - string, - string | number | object | undefined | (string | number | object)[] -> - -/** - * CSV parser's row reducer result data shape. - */ -export type TBuiltProductImportLine = Record - -export type ProductImportDescriptor = CsvSchemaColumn< - TParsedProductImportRowData, - TBuiltProductImportLine, - true -> - -export type ProductColumnDefinition = { - [key: string]: { - name: string - importDescriptor?: ProductImportDescriptor - exportDescriptor?: ProductExportDescriptor | DynamicProductExportDescriptor - } -} diff --git a/packages/medusa/src/strategies/batch-jobs/product/utils.ts b/packages/medusa/src/strategies/batch-jobs/product/utils.ts deleted file mode 100644 index dfc5b7c6d0..0000000000 --- a/packages/medusa/src/strategies/batch-jobs/product/utils.ts +++ /dev/null @@ -1,66 +0,0 @@ -import set from "lodash/set" - -import { TParsedProductImportRowData } from "./types" -import { csvRevertCellContentFormatter } from "../../../utils" - -/** - * Pick keys for a new object by regex. - * @param data - Initial data object - * @param regex - A regex used to pick which keys are going to be copied in the new object - */ -export function pickObjectPropsByRegex( - data: TParsedProductImportRowData, - regex: RegExp -): TParsedProductImportRowData { - const variantKeyPredicate = (key: string): boolean => regex.test(key) - const ret = {} - - for (const k in data) { - if (variantKeyPredicate(k)) { - ret[k] = - typeof data[k] === "string" - ? csvRevertCellContentFormatter(data[k] as string) - : data[k] - } - } - - return ret -} - -/** - * Pick data from parsed CSV object relevant for product create/update and remove prefixes from keys. - */ -export function transformProductData( - data: TParsedProductImportRowData -): TParsedProductImportRowData { - const ret = {} - const productData = pickObjectPropsByRegex(data, /product\./) - - Object.keys(productData).forEach((k) => { - const key = k.split("product.")[1] - set(ret, key, productData[k]) - }) - - return ret -} - -/** - * Pick data from parsed CSV object relevant for variant create/update and remove prefixes from keys. - */ -export function transformVariantData( - data: TParsedProductImportRowData -): TParsedProductImportRowData { - const ret = {} - const productData = pickObjectPropsByRegex(data, /variant\./) - - Object.keys(productData).forEach((k) => { - const key = k.split("variant.")[1] - set(ret, key, productData[k]) - }) - - // include product handle to keep track of associated product - ret["product.handle"] = data["product.handle"] - set(ret, "product.options", data["product.options"]) - - return ret -} diff --git a/packages/medusa/src/strategies/cart-completion.ts b/packages/medusa/src/strategies/cart-completion.ts deleted file mode 100644 index 6e4aa57545..0000000000 --- a/packages/medusa/src/strategies/cart-completion.ts +++ /dev/null @@ -1,503 +0,0 @@ -import { - IEventBusService, - IInventoryService, - ReservationItemDTO, -} from "@medusajs/types" -import { - AbstractCartCompletionStrategy, - CartCompletionResponse, -} from "../interfaces" -import { IdempotencyKey, Order } from "../models" -import { - PaymentProviderService, - ProductVariantInventoryService, -} from "../services" -import OrderService, { - ORDER_CART_ALREADY_EXISTS_ERROR, -} from "../services/order" - -import { promiseAll } from "@medusajs/utils" -import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import CartService from "../services/cart" -import IdempotencyKeyService from "../services/idempotency-key" -import SwapService from "../services/swap" -import { RequestContext } from "../types/request" - -type InjectedDependencies = { - productVariantInventoryService: ProductVariantInventoryService - paymentProviderService: PaymentProviderService - idempotencyKeyService: IdempotencyKeyService - cartService: CartService - orderService: OrderService - swapService: SwapService - manager: EntityManager - inventoryService: IInventoryService - eventBusService: IEventBusService -} - -class CartCompletionStrategy extends AbstractCartCompletionStrategy { - // eslint-disable-next-line max-len - protected readonly productVariantInventoryService_: ProductVariantInventoryService - protected readonly paymentProviderService_: PaymentProviderService - protected readonly idempotencyKeyService_: IdempotencyKeyService - protected readonly cartService_: CartService - protected readonly orderService_: OrderService - protected readonly swapService_: SwapService - protected readonly inventoryService_: IInventoryService - protected readonly eventBusService_: IEventBusService - - constructor({ - productVariantInventoryService, - paymentProviderService, - idempotencyKeyService, - cartService, - orderService, - swapService, - inventoryService, - eventBusService, - }: InjectedDependencies) { - // eslint-disable-next-line prefer-rest-params - super(arguments[0]) - - this.paymentProviderService_ = paymentProviderService - this.productVariantInventoryService_ = productVariantInventoryService - this.idempotencyKeyService_ = idempotencyKeyService - this.cartService_ = cartService - this.orderService_ = orderService - this.swapService_ = swapService - this.inventoryService_ = inventoryService - this.eventBusService_ = eventBusService - } - - async complete( - id: string, - ikey: IdempotencyKey, - context: RequestContext - ): Promise { - let idempotencyKey: IdempotencyKey = ikey - - let inProgress = true - let err: unknown = false - - while (inProgress) { - switch (idempotencyKey.recovery_point) { - case "started": { - await this.activeManager_ - .transaction(async (transactionManager) => { - idempotencyKey = await this.idempotencyKeyService_ - .withTransaction(transactionManager) - .workStage( - idempotencyKey.idempotency_key, - async (manager) => - await this.handleCreateTaxLines(id, { manager }) - ) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - case "tax_lines_created": { - await this.activeManager_ - .transaction(async (transactionManager) => { - idempotencyKey = await this.idempotencyKeyService_ - .withTransaction(transactionManager) - .workStage( - idempotencyKey.idempotency_key, - async (manager) => - await this.handleTaxLineCreated(id, idempotencyKey, { - context, - manager, - }) - ) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "payment_authorized": { - await this.activeManager_ - .transaction(async (transactionManager) => { - idempotencyKey = await this.idempotencyKeyService_ - .withTransaction(transactionManager) - .workStage( - idempotencyKey.idempotency_key, - async (manager) => - await this.handlePaymentAuthorized(id, { manager }) - ) - }) - .catch((e) => { - inProgress = false - err = e - }) - break - } - - case "finished": { - inProgress = false - break - } - - default: - await this.activeManager_.transaction(async (transactionManager) => { - idempotencyKey = await this.idempotencyKeyService_ - .withTransaction(transactionManager) - .update(idempotencyKey.idempotency_key, { - recovery_point: "finished", - response_code: 500, - response_body: { message: "Unknown recovery point" }, - }) - }) - break - } - } - - if (err) { - if (idempotencyKey.recovery_point !== "started") { - await this.activeManager_.transaction(async (transactionManager) => { - try { - await this.orderService_ - .withTransaction(transactionManager) - .retrieveByCartId(id) - } catch (error) { - await this.cartService_ - .withTransaction(transactionManager) - .deleteTaxLines(id) - } - }) - } - throw err - } - - return { - response_body: idempotencyKey.response_body, - response_code: idempotencyKey.response_code, - } - } - - protected async handleCreateTaxLines( - id: string, - { manager }: { manager: EntityManager } - ) { - const cart = await this.cartService_.withTransaction(manager).retrieve(id, { - relations: [ - "customer", - "discounts", - "discounts.rule", - "gift_cards", - "items.variant.product.profiles", - "items.adjustments", - "region", - "region.tax_rates", - "shipping_address", - "shipping_methods", - "shipping_methods.shipping_option", - ], - }) - - if (cart.completed_at) { - if (cart.type === "swap") { - const swapId = cart.metadata?.swap_id as string - const swapServiceTx = this.swapService_.withTransaction(manager) - - const swap = await swapServiceTx.retrieve(swapId, { - relations: ["shipping_address"], - }) - - return { - response_code: 200, - response_body: { data: swap, type: "swap" }, - } - } - - const order = await this.orderService_ - .withTransaction(manager) - .retrieveByCartIdWithTotals(id, { - relations: ["shipping_address", "items", "payments"], - }) - - return { - response_code: 200, - response_body: { data: order, type: "order" }, - } - } - - await this.cartService_.withTransaction(manager).createTaxLines(cart) - - return { - recovery_point: "tax_lines_created", - } - } - - protected async handleTaxLineCreated( - id: string, - idempotencyKey: IdempotencyKey, - { context, manager }: { context: any; manager: EntityManager } - ) { - const res = await this.handleCreateTaxLines(id, { manager }) - if (res.response_code) { - return res - } - - const txCartService = this.cartService_.withTransaction(manager) - - const cart = await txCartService.authorizePayment(id, { - ...context, - idempotency_key: idempotencyKey, - }) - - if (cart.payment_session) { - if ( - cart.payment_session.status === "requires_more" || - cart.payment_session.status === "pending" - ) { - await txCartService.deleteTaxLines(id) - - return { - response_code: 200, - response_body: { - data: cart, - payment_status: cart.payment_session.status, - type: "cart", - }, - } - } - } - - return { - recovery_point: "payment_authorized", - } - } - - protected async removeReservations(reservations) { - if (this.inventoryService_) { - await promiseAll( - reservations.map(async ([reservations]) => { - if (reservations) { - return reservations.map(async (reservation) => { - return await this.inventoryService_.deleteReservationItem( - reservation.id - ) - }) - } - return Promise.resolve() - }) - ) - } - } - - protected async handlePaymentAuthorized( - id: string, - { manager }: { manager: EntityManager } - ) { - const res = await this.handleCreateTaxLines(id, { manager }) - if (res.response_code) { - return res - } - - const orderServiceTx = this.orderService_.withTransaction(manager) - const swapServiceTx = this.swapService_.withTransaction(manager) - const cartServiceTx = this.cartService_.withTransaction(manager) - - const cart = await cartServiceTx.retrieveWithTotals(id, { - relations: [ - "region", - "payment", - "payment_sessions", - "items.variant.product.profiles", - ], - }) - - let allowBackorder = false - - if (cart.type === "swap") { - const swap = await swapServiceTx.retrieveByCartId(id) - allowBackorder = swap.allow_backorder - } - - let reservations: [ - ReservationItemDTO[] | void | undefined, - MedusaError | undefined - ][] = [] - if (!allowBackorder) { - const productVariantInventoryServiceTx = - this.productVariantInventoryService_.withTransaction(manager) - - reservations = await promiseAll( - cart.items.map(async (item) => { - if (item.variant_id) { - try { - const inventoryConfirmed = - await productVariantInventoryServiceTx.confirmInventory( - item.variant_id, - item.quantity, - { salesChannelId: cart.sales_channel_id } - ) - - if (!inventoryConfirmed) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - `Variant with id: ${item.variant_id} does not have the required inventory`, - MedusaError.Codes.INSUFFICIENT_INVENTORY - ) - } - - return [ - await productVariantInventoryServiceTx.reserveQuantity( - item.variant_id, - item.quantity, - { - lineItemId: item.id, - salesChannelId: cart.sales_channel_id, - } - ), - undefined, - ] - } catch (error) { - return [undefined, error] - } - } - return [undefined, undefined] - }) - ) - - if (reservations.some(([_, error]) => error)) { - await this.removeReservations(reservations) - - const errors = reservations.reduce((acc, [_, error]) => { - if (error) { - acc.push(error) - } - return acc - }, [] as MedusaError[]) - - const error = errors[0] - - if ( - errors.some( - (error) => error.code === MedusaError.Codes.INSUFFICIENT_INVENTORY - ) - ) { - if (cart.payment) { - await this.paymentProviderService_ - .withTransaction(manager) - .cancelPayment(cart.payment) - } - await cartServiceTx.update(cart.id, { - payment_authorized_at: null, - }) - - return { - response_code: 409, - response_body: { - errors: errors.map((error) => { - return { - message: error.message, - type: error.type, - code: error.code, - } - }), - }, - } - } else { - throw error - } - } else if (this.inventoryService_) { - await this.eventBusService_.emit("reservation-items.bulk-created", { - ids: reservations - .filter(([reservation]) => !!reservation) - .flatMap(([reservationItemArr]) => - reservationItemArr!.map((item) => item.id) - ), - }) - } - } - - // If cart is part of swap, we register swap as complete - if (cart.type === "swap") { - try { - const swapId = cart.metadata?.swap_id - let swap = await swapServiceTx.registerCartCompletion(swapId as string) - - swap = await swapServiceTx.retrieve(swap.id, { - relations: ["shipping_address"], - }) - - return { - response_code: 200, - response_body: { data: swap, type: "swap" }, - } - } catch (error) { - await this.removeReservations(reservations) - - if (error && error.code === MedusaError.Codes.INSUFFICIENT_INVENTORY) { - return { - response_code: 409, - response_body: { - message: error.message, - type: error.type, - code: error.code, - }, - } - } else { - throw error - } - } - } - - if (!cart.payment && cart.total! > 0) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Cart payment not authorized` - ) - } - - let order: Order - try { - order = await orderServiceTx.createFromCart(cart) - } catch (error) { - await this.removeReservations(reservations) - - if (error && error.message === ORDER_CART_ALREADY_EXISTS_ERROR) { - order = await orderServiceTx.retrieveByCartIdWithTotals(id, { - relations: ["shipping_address", "items", "payments"], - }) - - return { - response_code: 200, - response_body: { data: order, type: "order" }, - } - } else if ( - error && - error.code === MedusaError.Codes.INSUFFICIENT_INVENTORY - ) { - return { - response_code: 409, - response_body: { - message: error.message, - type: error.type, - code: error.code, - }, - } - } else { - throw error - } - } - - order = await orderServiceTx.retrieveWithTotals(order.id, { - relations: ["shipping_address", "items", "payments"], - }) - - return { - response_code: 200, - response_body: { data: order, type: "order" }, - } - } -} - -export default CartCompletionStrategy diff --git a/packages/medusa/src/strategies/price-selection.ts b/packages/medusa/src/strategies/price-selection.ts deleted file mode 100644 index 0a1663e36c..0000000000 --- a/packages/medusa/src/strategies/price-selection.ts +++ /dev/null @@ -1,347 +0,0 @@ -import { - AbstractPriceSelectionStrategy, - PriceSelectionContext, - PriceSelectionResult, - PriceType, -} from "../interfaces" - -import { ICacheService } from "@medusajs/types" -import { FlagRouter, promiseAll } from "@medusajs/utils" -import { isDefined } from "medusa-core-utils" -import { EntityManager } from "typeorm" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { MoneyAmountRepository } from "../repositories/money-amount" -import { TaxServiceRate } from "../types/tax-service" - -class PriceSelectionStrategy extends AbstractPriceSelectionStrategy { - protected manager_: EntityManager - protected readonly featureFlagRouter_: FlagRouter - protected moneyAmountRepository_: typeof MoneyAmountRepository - protected cacheService_: ICacheService - - constructor({ - manager, - featureFlagRouter, - moneyAmountRepository, - cacheService, - }) { - // @ts-ignore - // eslint-disable-next-line prefer-rest-params - super(...arguments) - this.manager_ = manager - this.moneyAmountRepository_ = moneyAmountRepository - this.featureFlagRouter_ = featureFlagRouter - this.cacheService_ = cacheService - } - - async calculateVariantPrice( - data: { - variantId: string - quantity?: number - }[], - context: PriceSelectionContext - ): Promise> { - const dataMap = new Map(data.map((d) => [d.variantId, d])) - - const cacheKeysMap = new Map( - data.map(({ variantId, quantity }) => [ - variantId, - this.getCacheKey(variantId, { ...context, quantity }), - ]) - ) - - const nonCachedData: { - variantId: string - quantity?: number - }[] = [] - - const variantPricesMap = new Map() - - if (!context.ignore_cache) { - const cacheHits = await promiseAll( - [...cacheKeysMap].map(async ([, cacheKey]) => { - return await this.cacheService_.get(cacheKey) - }) - ) - - if (!cacheHits.length) { - nonCachedData.push(...dataMap.values()) - } - - for (const [index, cacheHit] of cacheHits.entries()) { - const variantId = data[index].variantId - if (cacheHit) { - variantPricesMap.set(variantId, cacheHit) - continue - } - - nonCachedData.push(dataMap.get(variantId)!) - } - } else { - nonCachedData.push(...dataMap.values()) - } - - let results: Map = new Map() - - if ( - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) - ) { - results = await this.calculateVariantPrice_new(nonCachedData, context) - } else { - results = await this.calculateVariantPrice_old(nonCachedData, context) - } - - await promiseAll( - [...results].map(async ([variantId, prices]) => { - variantPricesMap.set(variantId, prices) - if (!context.ignore_cache) { - await this.cacheService_.set(cacheKeysMap.get(variantId)!, prices) - } - }) - ) - - return variantPricesMap - } - - private async calculateVariantPrice_new( - data: { - variantId: string - quantity?: number - }[], - context: PriceSelectionContext - ): Promise> { - const moneyRepo = this.activeManager_.withRepository( - this.moneyAmountRepository_ - ) - - const [variantsPrices] = await moneyRepo.findManyForVariantsInRegion( - data.map((d) => d.variantId), - context.region_id, - context.currency_code, - context.customer_id, - context.include_discount_prices, - true - ) - - const variantPricesMap = new Map() - - for (const [variantId, prices] of Object.entries(variantsPrices)) { - const dataItem = data.find((d) => d.variantId === variantId)! - - const result: PriceSelectionResult = { - originalPrice: null, - calculatedPrice: null, - prices, - originalPriceIncludesTax: null, - calculatedPriceIncludesTax: null, - } - - if (!prices.length || !context) { - variantPricesMap.set(variantId, result) - } - - const taxRate = context.tax_rates?.reduce( - (accRate: number, nextTaxRate: TaxServiceRate) => { - return accRate + (nextTaxRate.rate || 0) / 100 - }, - 0 - ) - - for (const ma of prices) { - let isTaxInclusive = ma.currency?.includes_tax || false - - if (ma.price_list?.includes_tax) { - // PriceList specific price so use the PriceList tax setting - isTaxInclusive = ma.price_list.includes_tax - } else if (ma.region?.includes_tax) { - // Region specific price so use the Region tax setting - isTaxInclusive = ma.region.includes_tax - } - - delete ma.currency - delete ma.region - - if ( - context.region_id && - ma.region_id === context.region_id && - ma.price_list_id === null && - ma.min_quantity === null && - ma.max_quantity === null - ) { - result.originalPriceIncludesTax = isTaxInclusive - result.originalPrice = ma.amount - } - - if ( - context.currency_code && - ma.currency_code === context.currency_code && - ma.price_list_id === null && - ma.min_quantity === null && - ma.max_quantity === null && - result.originalPrice === null // region prices take precedence - ) { - result.originalPriceIncludesTax = isTaxInclusive - result.originalPrice = ma.amount - } - - if ( - isValidQuantity(ma, dataItem.quantity) && - isValidAmount(ma.amount, result, isTaxInclusive, taxRate) && - ((context.currency_code && - ma.currency_code === context.currency_code) || - (context.region_id && ma.region_id === context.region_id)) - ) { - result.calculatedPrice = ma.amount - result.calculatedPriceType = ma.price_list?.type || PriceType.DEFAULT - result.calculatedPriceIncludesTax = isTaxInclusive - } - } - - variantPricesMap.set(variantId, result) - } - - return variantPricesMap - } - - private async calculateVariantPrice_old( - data: { - variantId: string - quantity?: number - }[], - context: PriceSelectionContext - ): Promise> { - const moneyRepo = this.activeManager_.withRepository( - this.moneyAmountRepository_ - ) - - const [variantsPrices] = await moneyRepo.findManyForVariantsInRegion( - data.map((d) => d.variantId), - context.region_id, - context.currency_code, - context.customer_id, - context.include_discount_prices - ) - - const variantPricesMap = new Map() - - for (const [variantId, prices] of Object.entries(variantsPrices)) { - const dataItem = data.find((d) => d.variantId === variantId)! - - const result: PriceSelectionResult = { - originalPrice: null, - calculatedPrice: null, - prices, - } - - if (!prices.length || !context) { - variantPricesMap.set(variantId, result) - } - - for (const ma of prices) { - delete ma.currency - delete ma.region - - if ( - context.region_id && - ma.region_id === context.region_id && - ma.price_list_id === null && - ma.min_quantity === null && - ma.max_quantity === null - ) { - result.originalPrice = ma.amount - } - - if ( - context.currency_code && - ma.currency_code === context.currency_code && - ma.price_list_id === null && - ma.min_quantity === null && - ma.max_quantity === null && - result.originalPrice === null // region prices take precedence - ) { - result.originalPrice = ma.amount - } - - if ( - isValidQuantity(ma, dataItem.quantity) && - (result.calculatedPrice === null || - ma.amount < result.calculatedPrice) && - ((context.currency_code && - ma.currency_code === context.currency_code) || - (context.region_id && ma.region_id === context.region_id)) - ) { - result.calculatedPrice = ma.amount - result.calculatedPriceType = ma.price_list?.type || PriceType.DEFAULT - } - } - - variantPricesMap.set(variantId, result) - } - - return variantPricesMap - } - - public async onVariantsPricesUpdate(variantIds: string[]): Promise { - await promiseAll( - variantIds.map( - async (id: string) => await this.cacheService_.invalidate(`ps:${id}:*`) - ) - ) - } - - private getCacheKey( - variantId: string, - context: PriceSelectionContext - ): string { - const taxRate = - context.tax_rates?.reduce( - (accRate: number, nextTaxRate: TaxServiceRate) => { - return accRate + (nextTaxRate.rate || 0) / 100 - }, - 0 - ) || 0 - - return `ps:${variantId}:${context.region_id}:${context.currency_code}:${context.customer_id}:${context.quantity}:${context.include_discount_prices}:${taxRate}` - } -} - -const isValidAmount = ( - amount: number, - result: PriceSelectionResult, - isTaxInclusive: boolean, - taxRate?: number -): boolean => { - if (result.calculatedPrice === null) { - return true - } - - if (isTaxInclusive === result.calculatedPriceIncludesTax) { - // if both or neither are tax inclusive compare equally - return amount < result.calculatedPrice - } - - if (typeof taxRate !== "undefined") { - return isTaxInclusive - ? amount < (1 + taxRate) * result.calculatedPrice - : (1 + taxRate) * amount < result.calculatedPrice - } - - // if we dont have a taxrate we can't compare mixed prices - return false -} - -const isValidQuantity = (price, quantity?: number): boolean => - (isDefined(quantity) && isValidPriceWithQuantity(price, quantity)) || - (typeof quantity === "undefined" && isValidPriceWithoutQuantity(price)) - -const isValidPriceWithoutQuantity = (price): boolean => - (!price.max_quantity && !price.min_quantity) || - ((!price.min_quantity || price.min_quantity === 0) && price.max_quantity) - -const isValidPriceWithQuantity = (price, quantity): boolean => - (!price.min_quantity || price.min_quantity <= quantity) && - (!price.max_quantity || price.max_quantity >= quantity) - -export default PriceSelectionStrategy diff --git a/packages/medusa/src/strategies/tax-calculation.ts b/packages/medusa/src/strategies/tax-calculation.ts deleted file mode 100644 index bb7765f939..0000000000 --- a/packages/medusa/src/strategies/tax-calculation.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { FlagRouter } from "@medusajs/utils" -import { ITaxCalculationStrategy, TaxCalculationContext } from "../interfaces" -import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" -import { - LineItem, - LineItemTaxLine, - ShippingMethod, - ShippingMethodTaxLine, -} from "../models" -import { calculatePriceTaxAmount } from "../utils" - -class TaxCalculationStrategy implements ITaxCalculationStrategy { - protected readonly featureFlagRouter_: FlagRouter - - constructor({ featureFlagRouter }) { - this.featureFlagRouter_ = featureFlagRouter - } - - async calculate( - items: LineItem[], - taxLines: (ShippingMethodTaxLine | LineItemTaxLine)[], - calculationContext: TaxCalculationContext - ): Promise { - const lineItemsTaxLines = taxLines.filter( - (tl) => "item_id" in tl - ) as LineItemTaxLine[] - const shippingMethodsTaxLines = taxLines.filter( - (tl) => "shipping_method_id" in tl - ) as ShippingMethodTaxLine[] - - const lineItemsTax = this.calculateLineItemsTax( - items, - lineItemsTaxLines, - calculationContext - ) - - const shippingMethodsTax = this.calculateShippingMethodsTax( - calculationContext.shipping_methods, - shippingMethodsTaxLines - ) - - return Math.round(lineItemsTax + shippingMethodsTax) - } - - private calculateLineItemsTax( - items: LineItem[], - taxLines: LineItemTaxLine[], - context: TaxCalculationContext - ): number { - let taxTotal = 0 - - for (const item of items) { - const allocations = context.allocation_map[item.id] || {} - - const filteredTaxLines = taxLines.filter((tl) => tl.item_id === item.id) - const includesTax = - this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) && item.includes_tax - - let taxableAmount - if (includesTax) { - const taxRate = filteredTaxLines.reduce( - (accRate: number, nextLineItemTaxLine: LineItemTaxLine) => { - return accRate + (nextLineItemTaxLine.rate || 0) / 100 - }, - 0 - ) - const taxIncludedInPrice = Math.round( - calculatePriceTaxAmount({ - price: item.unit_price, - taxRate, - includesTax, - }) - ) - taxableAmount = (item.unit_price - taxIncludedInPrice) * item.quantity - } else { - taxableAmount = item.unit_price * item.quantity - } - - taxableAmount -= allocations.discount?.amount ?? 0 - - for (const filteredTaxLine of filteredTaxLines) { - taxTotal += Math.round( - calculatePriceTaxAmount({ - price: taxableAmount, - taxRate: filteredTaxLine.rate / 100, - }) - ) - } - } - return taxTotal - } - - private calculateShippingMethodsTax( - shipping_methods: ShippingMethod[], - taxLines: ShippingMethodTaxLine[] - ): number { - const taxInclusiveEnabled = this.featureFlagRouter_.isFeatureEnabled( - TaxInclusivePricingFeatureFlag.key - ) - - let taxTotal = 0 - for (const sm of shipping_methods) { - const lineRates = taxLines.filter((tl) => tl.shipping_method_id === sm.id) - for (const lineRate of lineRates) { - taxTotal += calculatePriceTaxAmount({ - price: sm.price, - taxRate: lineRate.rate / 100, - includesTax: taxInclusiveEnabled && sm.includes_tax, - }) - } - } - return taxTotal - } -} - -export default TaxCalculationStrategy diff --git a/packages/medusa/src/subscribers/batch-job.ts b/packages/medusa/src/subscribers/batch-job.ts index e61c41b202..9cc448e39e 100644 --- a/packages/medusa/src/subscribers/batch-job.ts +++ b/packages/medusa/src/subscribers/batch-job.ts @@ -1,3 +1,4 @@ +/* import { EntityManager } from "typeorm" import { BatchJobService, @@ -83,3 +84,4 @@ class BatchJobSubscriber { } export default BatchJobSubscriber +*/ diff --git a/packages/medusa/src/subscribers/cart.ts b/packages/medusa/src/subscribers/cart.ts index 0fb8a12900..421a4ce42d 100644 --- a/packages/medusa/src/subscribers/cart.ts +++ b/packages/medusa/src/subscribers/cart.ts @@ -1,3 +1,5 @@ +// TODO: we need to discuss this +/* import { EntityManager } from "typeorm" import { CartService, EventBusService } from "../services" @@ -47,3 +49,4 @@ class CartSubscriber { } export default CartSubscriber +*/ diff --git a/packages/medusa/src/subscribers/order.js b/packages/medusa/src/subscribers/order.js index f92b46d94d..cc51236966 100644 --- a/packages/medusa/src/subscribers/order.js +++ b/packages/medusa/src/subscribers/order.js @@ -1,3 +1,5 @@ +// TODO: we need to discuss this +/* import { promiseAll } from "@medusajs/utils" class OrderSubscriber { @@ -62,3 +64,4 @@ class OrderSubscriber { } export default OrderSubscriber +*/ diff --git a/packages/medusa/src/subscribers/product.ts b/packages/medusa/src/subscribers/product.ts index 7413d8031e..4ac17cc2bf 100644 --- a/packages/medusa/src/subscribers/product.ts +++ b/packages/medusa/src/subscribers/product.ts @@ -1,3 +1,5 @@ +// TODO: we need to discuss this +/* import { IEventBusService, ISearchService } from "@medusajs/types" import { defaultSearchIndexingProductRelations, FlagRouter } from "@medusajs/utils" import { indexTypes } from "medusa-core-utils" @@ -25,10 +27,10 @@ class ProductSearchSubscriber { this.productService_ = container.productService this.featureFlagRouter_ = container.featureFlagRouter - /** + /!** * Do not subscribe to any event in case no search engine have been installed. * If some events need to be subscribed out of the search engine reason, they can be subscribed above this comment - */ + *!/ try { container[isSearchEngineInstalledResolutionKey] @@ -117,3 +119,4 @@ class ProductSearchSubscriber { } export default ProductSearchSubscriber +*/ diff --git a/packages/medusa/src/subscribers/search-indexing.ts b/packages/medusa/src/subscribers/search-indexing.ts index aeb1007012..ac98953cc0 100644 --- a/packages/medusa/src/subscribers/search-indexing.ts +++ b/packages/medusa/src/subscribers/search-indexing.ts @@ -1,3 +1,5 @@ +// TODO: we need to discuss this +/* import { IEventBusService, ISearchService } from "@medusajs/types" import { FlagRouter, defaultSearchIndexingProductRelations } from "@medusajs/utils" import { indexTypes } from "medusa-core-utils" @@ -78,3 +80,4 @@ class SearchIndexingSubscriber { } export default SearchIndexingSubscriber +*/ diff --git a/packages/medusa/src/types/auth.ts b/packages/medusa/src/types/auth.ts deleted file mode 100644 index 049944a1e6..0000000000 --- a/packages/medusa/src/types/auth.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Customer, User } from ".." - -export type AuthenticateResult = { - success: boolean - user?: User - customer?: Customer - error?: string -} diff --git a/packages/medusa/src/types/batch-job.ts b/packages/medusa/src/types/batch-job.ts index 66584a046e..c9b619a077 100644 --- a/packages/medusa/src/types/batch-job.ts +++ b/packages/medusa/src/types/batch-job.ts @@ -1,3 +1,4 @@ +/* import { Type } from "class-transformer" import { IsArray, @@ -73,3 +74,4 @@ export type BatchJobCreateProps = Pick< BatchJob, "context" | "type" | "created_by" | "dry_run" > +*/ diff --git a/packages/medusa/src/types/cart.ts b/packages/medusa/src/types/cart.ts deleted file mode 100644 index 3a9e069957..0000000000 --- a/packages/medusa/src/types/cart.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { - AddressPayload, - DateComparisonOperator, - StringComparisonOperator, -} from "./common" -import { Cart, CartType } from "../models/cart" - -import { IsType } from "../utils/validators/is-type" -import { Region } from "../models" -import { ValidateNested } from "class-validator" -import { CustomerTypes } from "@medusajs/types" - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function isCart(object: any): object is Cart { - return object.object === "cart" -} - -export class FilterableCartProps { - @ValidateNested() - @IsType([String, [String], StringComparisonOperator]) - id?: string | string[] | StringComparisonOperator - - @IsType([DateComparisonOperator]) - created_at?: DateComparisonOperator - - @IsType([DateComparisonOperator]) - updated_at?: DateComparisonOperator -} - -// TODO: Probably worth moving to `./line-item` instead -export type LineItemUpdate = { - title?: string - unit_price?: number - quantity?: number - metadata?: Record - region_id?: string - variant_id?: string - should_calculate_prices?: boolean -} - -export type LineItemValidateData = { - variant?: { product_id: string } - variant_id: string -} - -class GiftCard { - code: string -} - -class Discount { - code: string -} - -export type CartCreateProps = { - region_id?: string - region?: Region - email?: string - billing_address_id?: string - billing_address?: Partial - shipping_address_id?: string - shipping_address?: Partial - gift_cards?: GiftCard[] - discounts?: Discount[] - customer?: CustomerTypes.CustomerDTO - customer_id?: string - type?: CartType - context?: object - metadata?: Record - sales_channel_id?: string - country_code?: string -} - -export type CartUpdateProps = { - region_id?: string - country_code?: string - email?: string - shipping_address_id?: string - billing_address_id?: string - billing_address?: AddressPayload | string - shipping_address?: AddressPayload | string - completed_at?: Date - payment_authorized_at?: Date | null - gift_cards?: GiftCard[] - discounts?: Discount[] - customer_id?: string - context?: object - metadata?: Record - sales_channel_id?: string -} diff --git a/packages/medusa/src/types/claim.ts b/packages/medusa/src/types/claim.ts deleted file mode 100644 index 381367080e..0000000000 --- a/packages/medusa/src/types/claim.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { ClaimReason, ClaimType, Order } from "../models" -import { AddressPayload } from "./common" - -export type ClaimTypeValue = `${ClaimType}` - -/* CREATE INPUT */ - -export type CreateClaimInput = { - type: ClaimTypeValue - claim_items: CreateClaimItemInput[] - return_shipping?: CreateClaimReturnShippingInput - additional_items?: CreateClaimItemAdditionalItemInput[] - shipping_methods?: CreateClaimShippingMethodInput[] - refund_amount?: number - shipping_address?: AddressPayload - no_notification?: boolean - metadata?: Record - order: Order - claim_order_id?: string - shipping_address_id?: string - return_location_id?: string -} - -type CreateClaimReturnShippingInput = { - option_id?: string - price?: number -} - -type CreateClaimShippingMethodInput = { - id?: string - option_id?: string - price?: number - data?: Record -} - -export type CreateClaimItemInput = { - item_id: string - quantity: number - claim_order_id?: string - reason: ClaimReason - note?: string - tags?: string[] - images?: string[] -} - -type CreateClaimItemAdditionalItemInput = { - variant_id: string - quantity: number -} - -/* UPDATE INPUT */ - -export type UpdateClaimInput = { - claim_items?: UpdateClaimItemInput[] - shipping_methods?: UpdateClaimShippingMethodInput[] - no_notification?: boolean - metadata?: Record -} - -type UpdateClaimShippingMethodInput = { - id?: string - option_id?: string - price?: number - data?: Record -} - -type UpdateClaimItemInput = { - id: string - note?: string - reason?: string - images: UpdateClaimItemImageInput[] - tags: UpdateClaimItemTagInput[] - metadata?: Record -} - -type UpdateClaimItemImageInput = { - id?: string - url?: string -} - -type UpdateClaimItemTagInput = { - id?: string - value?: string -} diff --git a/packages/medusa/src/types/currency.ts b/packages/medusa/src/types/currency.ts deleted file mode 100644 index 20ad33361f..0000000000 --- a/packages/medusa/src/types/currency.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type UpdateCurrencyInput = { - includes_tax?: boolean -} diff --git a/packages/medusa/src/types/customer-groups.ts b/packages/medusa/src/types/customer-groups.ts deleted file mode 100644 index 84db005770..0000000000 --- a/packages/medusa/src/types/customer-groups.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Type } from "class-transformer" -import { IsArray, IsOptional, IsString, ValidateNested } from "class-validator" -import { IsType } from "../utils/validators/is-type" - -import { DateComparisonOperator, StringComparisonOperator } from "./common" - -/** - * Filters to apply on the retrieved customer groups. - */ -export class FilterableCustomerGroupProps { - /** - * IDs to filter customer groups by. - */ - @IsOptional() - @ValidateNested() - @IsType([String, [String], StringComparisonOperator]) - id?: string | string[] | StringComparisonOperator - - /** - * Search term to search customer groups by their name. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Names to filter customer groups by. - */ - @IsOptional() - @IsArray() - @IsString({ each: true }) - name?: string[] - - /** - * Date filters to apply on the customer groups' `update_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on the customer groups' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Filter customer groups by their associated discount condition's ID. - */ - @IsString() - @IsOptional() - discount_condition_id?: string -} - -export class CustomerGroupsBatchCustomer { - @IsString() - id: string -} - -export class CustomerGroupUpdate { - name?: string - metadata?: Record -} diff --git a/packages/medusa/src/types/customers.ts b/packages/medusa/src/types/customers.ts deleted file mode 100644 index 97b1cb3f81..0000000000 --- a/packages/medusa/src/types/customers.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { Transform, Type } from "class-transformer" -import { - IsBoolean, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { optionalBooleanMapper } from "../utils/validators/is-boolean" -import { AddressPayload, DateComparisonOperator } from "./common" - -/** - * Filters used to filter retrieved customers. - */ -export class AdminListCustomerSelector { - /** - * Search term used to search customers' email, first name, last name. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Filter customers by whether they have an account. - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value)) - has_account?: boolean - - /** - * Filter customers by the customer's customer groups. - */ - @IsOptional() - @IsString({ each: true }) - groups?: string[] - - /** - * The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`. - */ - @IsOptional() - @IsString() - order?: string - - /** - * Date filters to apply on the customers' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the customers' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator -} - -export type CreateCustomerInput = { - email: string - password?: string - password_hash?: string - has_account?: boolean - - first_name?: string - last_name?: string - phone?: string - metadata?: Record -} - -export type UpdateCustomerInput = { - password?: string - metadata?: Record - billing_address?: AddressPayload | string - billing_address_id?: string - groups?: { id: string }[] - - email?: string - first_name?: string - last_name?: string - phone?: string -} diff --git a/packages/medusa/src/types/discount.ts b/packages/medusa/src/types/discount.ts deleted file mode 100644 index 812710f301..0000000000 --- a/packages/medusa/src/types/discount.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { Transform, Type } from "class-transformer" -import { - IsArray, - IsBoolean, - IsEnum, - IsOptional, - IsString, - Validate, - ValidateNested, -} from "class-validator" -import { - AllocationType, - DiscountConditionOperator, - DiscountConditionType, - DiscountRuleType, - Region, -} from "../models" -import { optionalBooleanMapper } from "../utils/validators/is-boolean" -import { IsType } from "../utils/validators/is-type" -import { DateComparisonOperator } from "./common" -import { ExactlyOne } from "./validators/exactly-one" - -export type QuerySelector = { - q?: string -} - -/** - * Filters to apply on discounts' rules. - */ -export class AdminGetDiscountsDiscountRuleParams { - /** - * Type to filter discount rules by. - */ - @IsOptional() - @IsEnum(DiscountRuleType) - type?: DiscountRuleType - - /** - * Allocation to filter discount rules by. - */ - @IsOptional() - @IsEnum(AllocationType) - allocation?: AllocationType -} - -export class FilterableDiscountProps { - @IsString() - @IsOptional() - q?: string - - @IsOptional() - @IsType([String, [String]]) - id?: string | string[] - - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value)) - is_dynamic?: boolean - - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value)) - is_disabled?: boolean - - @ValidateNested() - @IsOptional() - @Type(() => AdminGetDiscountsDiscountRuleParams) - rule?: AdminGetDiscountsDiscountRuleParams - - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator -} - -/** - * Fields to create or update a discount condition. - */ -export class AdminUpsertConditionsReq { - /** - * The products associated with the discount condition, if the discount condition's type is `products`. - */ - @Validate(ExactlyOne, [ - "product_collections", - "product_types", - "product_tags", - "customer_groups", - ]) - @IsArray() - @IsOptional() - @IsString({ each: true }) - products?: string[] - - /** - * The product collections associated with the discount condition, if the discount condition's type is `product_collections`. - */ - @Validate(ExactlyOne, [ - "products", - "product_types", - "product_tags", - "customer_groups", - ]) - @IsArray() - @IsOptional() - @IsString({ each: true }) - product_collections?: string[] - - /** - * The product types associated with the discount condition, if the discount condition's type is `product_types`. - */ - @Validate(ExactlyOne, [ - "product_collections", - "products", - "product_tags", - "customer_groups", - ]) - @IsArray() - @IsOptional() - @IsString({ each: true }) - product_types?: string[] - - /** - * The product tags associated with the discount condition, if the discount condition's type is `product_tags`. - */ - @Validate(ExactlyOne, [ - "product_collections", - "product_types", - "products", - "customer_groups", - ]) - @IsArray() - @IsOptional() - @IsString({ each: true }) - product_tags?: string[] - - /** - * The customer groups associated with the discount condition, if the discount condition's type is `customer_groups`. - */ - @Validate(ExactlyOne, [ - "product_collections", - "product_types", - "products", - "product_tags", - ]) - @IsArray() - @IsOptional() - @IsString({ each: true }) - customer_groups?: string[] -} - -export const DiscountConditionMapTypeToProperty = { - [DiscountConditionType.PRODUCTS]: "products", - [DiscountConditionType.PRODUCT_TYPES]: "product_types", - [DiscountConditionType.PRODUCT_COLLECTIONS]: "product_collections", - [DiscountConditionType.PRODUCT_TAGS]: "product_tags", - [DiscountConditionType.CUSTOMER_GROUPS]: "customer_groups", -} - -export type DiscountConditionInput = { - rule_id?: string - id?: string - operator?: DiscountConditionOperator - products?: (string | { id: string })[] - product_collections?: (string | { id: string })[] - product_types?: (string | { id: string })[] - product_tags?: (string | { id: string })[] - customer_groups?: (string | { id: string })[] -} - -export type CreateDiscountRuleInput = { - description?: string - type: DiscountRuleType - value: number - allocation: AllocationType - conditions?: DiscountConditionInput[] -} - -export type CreateDiscountInput = { - code: string - rule: CreateDiscountRuleInput - is_dynamic: boolean - is_disabled: boolean - starts_at?: Date - ends_at?: Date - valid_duration?: string - usage_limit?: number - regions?: string[] | Region[] - metadata?: Record -} - -export type UpdateDiscountRuleInput = { - id: string - description?: string - value?: number - allocation?: AllocationType - conditions?: DiscountConditionInput[] -} - -export type UpdateDiscountInput = { - code?: string - rule?: UpdateDiscountRuleInput - is_disabled?: boolean - starts_at?: Date - ends_at?: Date | null - valid_duration?: string | null - usage_limit?: number | null - regions?: string[] - metadata?: Record -} - -export type CreateDynamicDiscountInput = { - code: string - ends_at?: Date - usage_limit: number - metadata?: Record -} diff --git a/packages/medusa/src/types/draft-orders.ts b/packages/medusa/src/types/draft-orders.ts deleted file mode 100644 index d68340d144..0000000000 --- a/packages/medusa/src/types/draft-orders.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { AddressPayload } from "./common" - -export type DraftOrderStatusValue = "open" | "completed" - -export type DraftOrderListSelector = { q?: string } - -export type DraftOrderCreateProps = { - status?: string - email: string - billing_address_id?: string - billing_address?: Partial - shipping_address_id?: string - shipping_address?: Partial - items?: Item[] - region_id: string - discounts?: Discount[] - customer_id?: string - no_notification_order?: boolean - shipping_methods: ShippingMethod[] - metadata?: Record - idempotency_key?: string -} - -type ShippingMethod = { - option_id: string - data?: Record - price?: number -} - -type Discount = { - code: string -} - -type Item = { - title?: string - unit_price?: number - variant_id?: string - quantity: number - metadata?: Record -} diff --git a/packages/medusa/src/types/fulfillment-provider.ts b/packages/medusa/src/types/fulfillment-provider.ts deleted file mode 100644 index 641bcba459..0000000000 --- a/packages/medusa/src/types/fulfillment-provider.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Return } from "../models" - -export type FulfillmentOptions = { - provider_id: string - options: Record[] -} - -export type CreateReturnType = Omit diff --git a/packages/medusa/src/types/fulfillment.ts b/packages/medusa/src/types/fulfillment.ts deleted file mode 100644 index 1f4d0f5330..0000000000 --- a/packages/medusa/src/types/fulfillment.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { - Address, - ClaimOrder, - Discount, - LineItem, - Payment, - Region, - ShippingMethod, -} from "../models" - -export type FulFillmentItemType = { - item_id: string - quantity: number -} - -export type FulfillmentItemPartition = { - shipping_method: ShippingMethod - items: LineItem[] -} - -export type CreateShipmentConfig = { - metadata?: Record - no_notification?: boolean - location_id?: string -} - -export type CreateFulfillmentOrder = Omit & { - is_claim?: boolean - email?: string - payments: Payment[] - discounts: Discount[] - currency_code: string - tax_rate: number | null - region_id: string - region?: Region - is_swap?: boolean - display_id: number - billing_address: Address - items: LineItem[] - shipping_methods: ShippingMethod[] - no_notification: boolean -} diff --git a/packages/medusa/src/types/gift-card.ts b/packages/medusa/src/types/gift-card.ts deleted file mode 100644 index cba1dced10..0000000000 --- a/packages/medusa/src/types/gift-card.ts +++ /dev/null @@ -1,27 +0,0 @@ -export type CreateGiftCardInput = { - order_id?: string - value?: number - balance?: number - ends_at?: Date - is_disabled?: boolean - region_id: string - metadata?: Record - tax_rate?: number | null -} - -export type UpdateGiftCardInput = { - balance?: number - ends_at?: Date | null - is_disabled?: boolean - region_id?: string - metadata?: Record -} - -export type CreateGiftCardTransactionInput = { - gift_card_id: string - order_id: string - amount: number - created_at?: Date - is_taxable?: boolean - tax_rate?: number | null -} diff --git a/packages/medusa/src/types/global.ts b/packages/medusa/src/types/global.ts index 26f7f98b85..45f5f83d93 100644 --- a/packages/medusa/src/types/global.ts +++ b/packages/medusa/src/types/global.ts @@ -1,14 +1,13 @@ import { CommonTypes } from "@medusajs/types" import { Request } from "express" import { MedusaContainer as coreMedusaContainer } from "medusa-core-utils" -import { Customer, User } from "../models" import { FindConfig, RequestQueryFields } from "./common" declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace Express { interface Request { - user?: (User | Customer) & { customer_id?: string; userId?: string } + user?: { customer_id?: string; userId?: string } scope: MedusaContainer validatedQuery: RequestQueryFields & Record validatedBody: unknown diff --git a/packages/medusa/src/types/invites.ts b/packages/medusa/src/types/invites.ts deleted file mode 100644 index b908e21c3c..0000000000 --- a/packages/medusa/src/types/invites.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Invite } from "../models/invite" - -export type ListInvite = Omit & { - token: string -} diff --git a/packages/medusa/src/types/line-item-adjustment.ts b/packages/medusa/src/types/line-item-adjustment.ts deleted file mode 100644 index f386c9faca..0000000000 --- a/packages/medusa/src/types/line-item-adjustment.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ValidateNested } from "class-validator" -import { IsType } from "../utils/validators/is-type" -import { DateComparisonOperator, StringComparisonOperator } from "./common" - -export class FilterableLineItemAdjustmentProps { - @ValidateNested() - @IsType([String, [String], StringComparisonOperator]) - id?: string | string[] | StringComparisonOperator - - @ValidateNested() - @IsType([String, [String]]) - item_id?: string | string[] - - @ValidateNested() - @IsType([String, [String]]) - description?: string | string[] - - @ValidateNested() - @IsType([String, [String]]) - resource_id?: string | string[] - - @IsType([DateComparisonOperator]) - created_at?: DateComparisonOperator - - @IsType([DateComparisonOperator]) - updated_at?: DateComparisonOperator -} diff --git a/packages/medusa/src/types/line-item.ts b/packages/medusa/src/types/line-item.ts deleted file mode 100644 index 8aa12d4beb..0000000000 --- a/packages/medusa/src/types/line-item.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { CalculationContextData } from "./totals" - -export type GenerateInputData = { - variantId: string - quantity: number - metadata?: Record - unit_price?: number -} - -export type GenerateLineItemContext = { - region_id?: string - unit_price?: number - includes_tax?: boolean - metadata?: Record - customer_id?: string - order_edit_id?: string - cart?: CalculationContextData -} diff --git a/packages/medusa/src/types/note.ts b/packages/medusa/src/types/note.ts deleted file mode 100644 index 2c532f1008..0000000000 --- a/packages/medusa/src/types/note.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Note } from "../models/note" -import { User } from "../models/user" -import { PartialPick } from "./common" - -export interface CreateNoteInput { - value: string - resource_type: string - resource_id: string - author_id?: string - author?: User - metadata?: Record -} - -export type selector = { - resource_id?: string -} - -export type FilterableUserProps = PartialPick< - Note, - | "value" - | "resource_type" - | "resource_id" - | "author_id" - | "updated_at" - | "deleted_at" -> diff --git a/packages/medusa/src/types/oauth.ts b/packages/medusa/src/types/oauth.ts deleted file mode 100644 index 508660a837..0000000000 --- a/packages/medusa/src/types/oauth.ts +++ /dev/null @@ -1,10 +0,0 @@ -export type CreateOauthInput = { - display_name: string - application_name: string - install_url?: string - uninstall_url?: string -} - -export type UpdateOauthInput = { - data: Record -} diff --git a/packages/medusa/src/types/order-edit.ts b/packages/medusa/src/types/order-edit.ts deleted file mode 100644 index f6e4744e47..0000000000 --- a/packages/medusa/src/types/order-edit.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { OrderEdit, OrderEditItemChangeType } from "../models" - -export type CreateOrderEditInput = { - order_id: string - internal_note?: string -} - -export type AddOrderEditLineItemInput = { - quantity: number - variant_id: string - - metadata?: Record -} - -export type CreateOrderEditItemChangeInput = { - type: OrderEditItemChangeType - order_edit_id: string - original_line_item_id?: string - line_item_id?: string -} - -export const defaultOrderEditRelations: string[] = [ - "changes", - "changes.line_item", - "changes.line_item.variant", - "changes.original_line_item", - "changes.original_line_item.variant", - "items", - "items.variant", - "items.adjustments", - "items.tax_lines", - "payment_collection", -] - -export const defaultOrderEditFields: (keyof OrderEdit)[] = [ - "id", - "items", - "changes", - "order_id", - "created_by", - "created_at", - "requested_by", - "requested_at", - "confirmed_by", - "confirmed_at", - "declined_by", - "declined_reason", - "declined_at", - "canceled_by", - "canceled_at", - "internal_note", - "payment_collection_id", -] - -export const storeOrderEditNotAllowedFieldsAndRelations = [ - "internal_note", - "created_by", - "confirmed_by", - "canceled_by", -] - -export const defaultStoreOrderEditRelations = defaultOrderEditRelations.filter( - (field) => !storeOrderEditNotAllowedFieldsAndRelations.includes(field) -) -export const defaultStoreOrderEditFields = defaultOrderEditFields.filter( - (field) => !storeOrderEditNotAllowedFieldsAndRelations.includes(field) -) diff --git a/packages/medusa/src/types/orders.ts b/packages/medusa/src/types/orders.ts deleted file mode 100644 index 7e6f278504..0000000000 --- a/packages/medusa/src/types/orders.ts +++ /dev/null @@ -1,400 +0,0 @@ -import { Type } from "class-transformer" -import { - IsArray, - IsEnum, - IsInt, - IsNotEmpty, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { IsType } from "../utils/validators/is-type" -import { Order, Payment } from "../models" -import { AddressPayload, DateComparisonOperator } from "./common" - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function isOrder(object: any): object is Order { - return object.object === "order" -} - -export type TotalsContext = { - force_taxes?: boolean - includes?: { returnable_items?: boolean } -} - -/** - * @enum - * - * The status of an order. - */ -enum OrderStatus { - /** - * Order is pending. - */ - pending = "pending", - /** - * Order is completed. An order is completed when it's paid and fulfilled. - */ - completed = "completed", - /** - * Order is archived. - */ - archived = "archived", - /** - * Order is canceled. - */ - canceled = "canceled", - /** - * Order requires an action. This status is applied when the order's payment or fulfillment requires an additional action. - */ - requires_action = "requires_action", -} - -/** - * @enum - * - * The fulfillment status of an order. - */ -enum FulfillmentStatus { - /** - * The order isn't fulfilled. - */ - not_fulfilled = "not_fulfilled", - /** - * All of the order's items are fulfilled. - */ - fulfilled = "fulfilled", - /** - * Some, but not all, of the order's items are fulfilled. - */ - partially_fulfilled = "partially_fulfilled", - /** - * All of the order's items are shipped. - */ - shipped = "shipped", - /** - * Some, but not all, of the order's items are shipped. - */ - partially_shipped = "partially_shipped", - /** - * The order's fulfillments are canceled. - */ - canceled = "canceled", - /** - * All of the order's items are returned. - */ - returned = "returned", - /** - * Some, but not all, of the order's items are returned. - */ - partially_returned = "partially_returned", - /** - * The order's fulfillment requires an action. - */ - requires_action = "requires_action", -} - -/** - * @enum - * - * The payment status of the order. - */ -enum PaymentStatus { - /** - * The order's payment is captured. - */ - captured = "captured", - /** - * The order's payment is awaiting. - */ - awaiting = "awaiting", - /** - * The order's payment isn't paid. - */ - not_paid = "not_paid", - /** - * The order's payment is fully refunded. - */ - refunded = "refunded", - /** - * The order's payment is partially refunded. - */ - partially_refunded = "partially_refunded", - /** - * The order's payment is canceled. - */ - canceled = "canceled", - /** - * The order's payment requires an action. - */ - requires_action = "requires_action", -} - -export type CreateOrderInput = { - status?: OrderStatus - email: string - billing_address: AddressPayload - shipping_address: AddressPayload - items: Record[] - region: string - discounts?: Record[] - customer_id: string - payment_method: { - provider_id: string - ata?: Record - } - shipping_method?: { - provider_id: string - profile_id: string - price: number - data?: Record - items?: Record[] - }[] - no_notification?: boolean -} - -export type UpdateOrderInput = { - email?: string - billing_address?: AddressPayload - shipping_address?: AddressPayload - items?: object[] - region?: string - discounts?: object[] - customer_id?: string - payment_method?: { - provider_id?: string - data?: Record - } - shipping_method?: { - provider_id?: string - profile_id?: string - price?: number - data?: Record - items?: Record[] - }[] - no_notification?: boolean - payment?: Payment - status?: OrderStatus - fulfillment_status?: FulfillmentStatus - payment_status?: PaymentStatus - metadata?: Record -} - -export const defaultAdminOrdersRelations = [ - "billing_address", - "claims", - "claims.additional_items", - "claims.additional_items.variant", - "claims.claim_items", - "claims.claim_items.images", - "claims.claim_items.item", - "claims.fulfillments", - "claims.fulfillments.tracking_links", - "claims.return_order", - "claims.return_order.shipping_method", - "claims.return_order.shipping_method.tax_lines", - "claims.shipping_address", - "claims.shipping_methods", - "customer", - "discounts", - "discounts.rule", - "fulfillments", - "fulfillments.items", - "fulfillments.tracking_links", - "gift_card_transactions", - "gift_cards", - "items", - "payments", - "refunds", - "region", - "returns", - "returns.items", - "returns.items.reason", - "returns.shipping_method", - "returns.shipping_method.shipping_option", - "returns.shipping_method.tax_lines", - "shipping_address", - "shipping_methods", - "shipping_methods.shipping_option", - "shipping_methods.tax_lines", - "swaps", - "swaps.additional_items", - "swaps.additional_items.variant", - "swaps.fulfillments", - "swaps.fulfillments.tracking_links", - "swaps.payment", - "swaps.return_order", - "swaps.return_order.shipping_method", - "swaps.return_order.shipping_method.shipping_option", - "swaps.return_order.shipping_method.tax_lines", - "swaps.shipping_address", - "swaps.shipping_methods", - "swaps.shipping_methods.shipping_option", - "swaps.shipping_methods.tax_lines", - // "claims.claim_items.tags", -] - -export const defaultAdminOrdersFields = [ - "id", - "status", - "fulfillment_status", - "payment_status", - "display_id", - "cart_id", - "draft_order_id", - "customer_id", - "email", - "region_id", - "currency_code", - "tax_rate", - "canceled_at", - "created_at", - "updated_at", - "metadata", - "items.refundable", - "swaps.additional_items.refundable", - "claims.additional_items.refundable", - "no_notification", -] as (keyof Order)[] - -/** - * Filters to apply on the retrieved orders. - */ -export class AdminListOrdersSelector { - /** - * Search term to search orders' shipping address, first name, email, and display ID. - */ - @IsString() - @IsOptional() - q?: string - - /** - * ID to filter orders by. - */ - @IsString() - @IsOptional() - id?: string - - /** - * Statuses to filter orders by. - */ - @IsArray() - @IsEnum(OrderStatus, { each: true }) - @IsOptional() - status?: string[] - - /** - * Fulfillment statuses to filter orders by. - */ - @IsArray() - @IsEnum(FulfillmentStatus, { each: true }) - @IsOptional() - fulfillment_status?: string[] - - /** - * Payment statuses to filter orders by. - */ - @IsArray() - @IsEnum(PaymentStatus, { each: true }) - @IsOptional() - payment_status?: string[] - - /** - * Display ID to filter orders by. - */ - @IsString() - @IsOptional() - display_id?: string - - /** - * Cart ID to filter orders by. - */ - @IsString() - @IsOptional() - cart_id?: string - - /** - * Customer ID to filter orders by. - */ - @IsString() - @IsOptional() - customer_id?: string - - /** - * Email to filter orders by. - */ - @IsString() - @IsOptional() - email?: string - - /** - * Regions to filter orders by. - */ - @IsOptional() - @IsType([String, [String]]) - region_id?: string | string[] - - /** - * Currency code to filter orders by. - */ - @IsString() - @IsOptional() - currency_code?: string - - /** - * Tax rate to filter orders by. - */ - @IsString() - @IsOptional() - tax_rate?: string - - /** - * Sales channel IDs to filter orders by. - */ - @IsArray() - @IsOptional() - sales_channel_id?: string[] - - /** - * Date filters to apply on the orders' `canceled_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - canceled_at?: DateComparisonOperator - - /** - * Date filters to apply on the orders' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the orders' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator -} - -export class OrdersReturnItem { - @IsString() - @IsNotEmpty() - item_id: string - - @IsInt() - @IsNotEmpty() - @Type(() => Number) - quantity: number - - @IsString() - @IsOptional() - reason_id?: string - - @IsString() - @IsOptional() - note?: string -} diff --git a/packages/medusa/src/types/payment-collection.ts b/packages/medusa/src/types/payment-collection.ts deleted file mode 100644 index 6897958ae9..0000000000 --- a/packages/medusa/src/types/payment-collection.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { PaymentCollection, PaymentCollectionType } from "../models" - -export type CreatePaymentCollectionInput = { - region_id: string - type: PaymentCollectionType - currency_code: string - amount: number - created_by: string - metadata?: any - description?: string -} - -export type PaymentCollectionsSessionsBatchInput = { - provider_id: string - amount: number - session_id?: string -} - -export type PaymentCollectionsSessionsInput = { - provider_id: string -} - -export const defaultPaymentCollectionRelations = [ - "region", - "region.payment_providers", - "payment_sessions", -] - -export const defaultPaymentCollectionFields: (keyof PaymentCollection)[] = [ - "id", - "type", - "status", - "description", - "amount", - "authorized_amount", - "currency_code", - "metadata", - "region", - "payment_sessions", - "payments", -] - -// eslint-disable-next-line max-len -export const storePaymentCollectionNotAllowedFieldsAndRelations = ["created_by"] - -export const defaultStorePaymentCollectionRelations = - defaultPaymentCollectionRelations.filter( - (field) => - !storePaymentCollectionNotAllowedFieldsAndRelations.includes(field) - ) -export const defaultStorePaymentCollectionFields = - defaultPaymentCollectionFields.filter( - (field) => - !storePaymentCollectionNotAllowedFieldsAndRelations.includes(field) - ) diff --git a/packages/medusa/src/types/payment.ts b/packages/medusa/src/types/payment.ts deleted file mode 100644 index 299f97b124..0000000000 --- a/packages/medusa/src/types/payment.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { - Address, - Cart, - Customer, - PaymentSession, - ShippingMethod, -} from "../models" - -export type PaymentSessionInput = { - payment_session_id?: string - provider_id: string - // TODO: Support legacy payment provider API> Once we are ready to break the api then we can remove the Cart type - cart: - | Cart - | { - context: Record - id: string - email: string - shipping_address: Address | null - shipping_methods: ShippingMethod[] - billing_address?: Address | null - } - customer?: Customer | null - currency_code: string - amount: number - resource_id?: string - paymentSessionData?: Record -} - -export type CreatePaymentInput = { - cart_id?: string - amount: number - currency_code: string - provider_id?: string - payment_session: PaymentSession - resource_id?: string -} diff --git a/packages/medusa/src/types/price-list.ts b/packages/medusa/src/types/price-list.ts deleted file mode 100644 index 208001af42..0000000000 --- a/packages/medusa/src/types/price-list.ts +++ /dev/null @@ -1,228 +0,0 @@ -import { Type } from "class-transformer" -import { - IsEnum, - IsInt, - IsOptional, - IsString, - Validate, - ValidateIf, - ValidateNested, -} from "class-validator" -import { PriceList } from "../models/price-list" -import { DateComparisonOperator } from "./common" -import { XorConstraint } from "./validators/xor" - -/** - * @enum - * - * The type of price list. - */ -export enum PriceListType { - /** - * The price list is used for a sale. - */ - SALE = "sale", - /** - * The price list is used to override original prices for specific conditions. - */ - OVERRIDE = "override", -} - -/** - * @enum - * - * The status of a price list. - */ -export enum PriceListStatus { - /** - * The price list is active, meaning its prices are applied to customers. - */ - ACTIVE = "active", - /** - * The price list is a draft, meaning its not yet applied to customers. - */ - DRAFT = "draft", -} - -/** - * Filters to apply on the retrieved price lists. - */ -export class FilterablePriceListProps { - /** - * IDs to filter price lists by. - */ - @IsString() - @IsOptional() - id?: string - - /** - * Search terms to search price lists' description, name, and customer group's name. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Statuses to filter price lists by. - */ - @IsOptional() - @IsEnum(PriceListStatus, { each: true }) - status?: PriceListStatus[] - - /** - * Name to filter price lists by. - */ - @IsString() - @IsOptional() - name?: string - - /** - * Filter price lists by their associated customer groups. - */ - @IsOptional() - @IsString({ each: true }) - customer_groups?: string[] - - /** - * Description to filter price lists by. - */ - @IsString() - @IsOptional() - description?: string - - /** - * Types to filter price lists by. - */ - @IsOptional() - @IsEnum(PriceListType, { each: true }) - type?: PriceListType[] - - /** - * Date filters to apply on the price lists' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the price lists' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on the price lists' `deleted_at` date. - */ - @ValidateNested() - @IsOptional() - @Type(() => DateComparisonOperator) - deleted_at?: DateComparisonOperator -} - -export class AdminPriceListPricesUpdateReq { - @IsString() - @IsOptional() - id?: string - - @ValidateIf((o) => !o.id) - @Validate(XorConstraint, ["currency_code"]) - region_id?: string - - @ValidateIf((o) => !o.id) - @Validate(XorConstraint, ["region_id"]) - currency_code?: string - - @IsString() - variant_id: string - - @IsInt() - amount: number - - @IsOptional() - @IsInt() - min_quantity?: number - - @IsOptional() - @IsInt() - max_quantity?: number -} - -export class AdminPriceListPricesCreateReq { - @Validate(XorConstraint, ["currency_code"]) - region_id?: string - - @Validate(XorConstraint, ["region_id"]) - currency_code?: string - - @IsInt() - amount: number - - @IsString() - variant_id: string - - @IsOptional() - @IsInt() - min_quantity?: number - - @IsOptional() - @IsInt() - max_quantity?: number -} - -export type CreatePriceListInput = { - name: string - description: string - type: PriceListType - status?: PriceListStatus - prices: AdminPriceListPricesCreateReq[] - customer_groups?: { id: string }[] - starts_at?: Date - ends_at?: Date - includes_tax?: boolean -} - -export type UpdatePriceListInput = Partial< - Pick< - PriceList, - | "name" - | "description" - | "starts_at" - | "ends_at" - | "status" - | "type" - | "includes_tax" - > -> & { - prices?: AdminPriceListPricesUpdateReq[] - customer_groups?: { id: string }[] -} - -export type PriceListPriceUpdateInput = { - id?: string - variant_id?: string - region_id?: string - currency_code?: string - amount?: number - min_quantity?: number - max_quantity?: number -} - -export type PriceListPriceCreateInput = { - region_id?: string - currency_code?: string - variant_id: string - amount: number - min_quantity?: number - max_quantity?: number -} - -export type PriceListLoadConfig = { - include_discount_prices?: boolean - customer_id?: string - cart_id?: string - region_id?: string - currency_code?: string -} diff --git a/packages/medusa/src/types/price-selection.ts b/packages/medusa/src/types/price-selection.ts deleted file mode 100644 index a011e886fc..0000000000 --- a/packages/medusa/src/types/price-selection.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { IsOptional, IsString } from "class-validator" - -import { FindParams } from "./common" - -/** - * The context to apply on retrieved prices. - */ -export class PriceSelectionParams extends FindParams { - /** - * Retrieve prices for a cart ID. - */ - @IsOptional() - @IsString() - cart_id?: string - - /** - * Retrieve prices for a region ID. - */ - @IsOptional() - @IsString() - region_id?: string - - /** - * Retrieve prices for a currency code. - */ - @IsOptional() - @IsString() - currency_code?: string -} - -/** - * The context to apply on retrieved prices by a user admin. - */ -export class AdminPriceSelectionParams extends PriceSelectionParams { - /** - * Retrieve prices for a customer ID. - */ - @IsOptional() - @IsString() - customer_id?: string -} diff --git a/packages/medusa/src/types/pricing.ts b/packages/medusa/src/types/pricing.ts deleted file mode 100644 index 0acb27286d..0000000000 --- a/packages/medusa/src/types/pricing.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { MoneyAmount, Product, ProductVariant, ShippingOption } from "../models" - -import { PriceSelectionContext } from "../interfaces/price-selection-strategy" -import { TaxServiceRate } from "./tax-service" - -/** - * Pricing fields for product variants. - */ -export type ProductVariantPricing = { - /** - * The list of prices. - */ - prices: MoneyAmount[] - /** - * The original price of the variant. - */ - original_price: number | null - /** - * The lowest price among the retrieved prices. - */ - calculated_price: number | null - /** - * Whether the `original_price` field includes taxes. - * - * @featureFlag tax_inclusive_pricing - */ - original_price_includes_tax?: boolean | null - /** - * Whether the `calculated_price` field includes taxes. - * - * @featureFlag tax_inclusive_pricing - */ - calculated_price_includes_tax?: boolean | null - /** - * Either `default` if the `calculated_price` is the original price, or the type of the price list applied, if any. - */ - calculated_price_type?: string | null -} & TaxedPricing - -/** - * Pricing fields related to taxes. - */ -export type TaxedPricing = { - /** - * The price after applying the tax amount on the original price. - */ - original_price_incl_tax: number | null - /** - * The price after applying the tax amount on the calculated price. - */ - calculated_price_incl_tax: number | null - /** - * The tax amount applied to the original price. - */ - original_tax: number | null - /** - * The tax amount applied to the calculated price. - */ - calculated_tax: number | null - /** - * The list of tax rates. - */ - tax_rates: TaxServiceRate[] | null -} - -export type PricingContext = { - price_selection: PriceSelectionContext - automatic_taxes: boolean - tax_rate: number | null -} - -export type ShippingOptionPricing = { - price_incl_tax: number | null - tax_rates: TaxServiceRate[] | null - tax_amount: number -} - -/** @schema PricedShippingOption - * title: "Priced Shipping Option" - * type: object - * allOf: - * - $ref: "#/components/schemas/ShippingOption" - * - type: object - * properties: - * price_incl_tax: - * type: number - * description: Price including taxes - * tax_rates: - * type: array - * description: An array of applied tax rates - * items: - * type: object - * properties: - * rate: - * type: number - * description: The tax rate value - * name: - * type: string - * description: The name of the tax rate - * code: - * type: string - * description: The code of the tax rate - * tax_amount: - * type: number - * description: The taxes applied. - */ -export type PricedShippingOption = Partial & - ShippingOptionPricing - -/** - * @schema PricedVariant - * title: "Priced Product Variant" - * type: object - * allOf: - * - $ref: "#/components/schemas/ProductVariant" - * - type: object - * properties: - * original_price: - * type: number - * description: The original price of the variant without any discounted prices applied. - * calculated_price: - * type: number - * description: The calculated price of the variant. Can be a discounted price. - * original_price_incl_tax: - * type: number - * description: The original price of the variant including taxes. - * calculated_price_incl_tax: - * type: number - * description: The calculated price of the variant including taxes. - * original_tax: - * type: number - * description: The taxes applied on the original price. - * calculated_tax: - * type: number - * description: The taxes applied on the calculated price. - * tax_rates: - * type: array - * description: An array of applied tax rates - * items: - * type: object - * properties: - * rate: - * type: number - * description: The tax rate value - * name: - * type: string - * description: The name of the tax rate - * code: - * type: string - * description: The code of the tax rate - */ -export type PricedVariant = Partial & ProductVariantPricing - -/** - * @schema PricedProduct - * title: "Priced Product" - * type: object - * allOf: - * - $ref: "#/components/schemas/Product" - * - type: object - * properties: - * variants: - * description: "The product variants and their prices." - * type: array - * items: - * $ref: "#/components/schemas/PricedVariant" - */ -export type PricedProduct = Omit, "variants"> & { - variants: PricedVariant[] -} - -export type VariantPriceSetRes = { - id: string - title: string - price: PriceModulePrice | PriceModulePrice[] -} - -type PriceModulePrice = { - variant_id: string - price_set_id: string -} diff --git a/packages/medusa/src/types/product-category.ts b/packages/medusa/src/types/product-category.ts deleted file mode 100644 index 60a9ca9b36..0000000000 --- a/packages/medusa/src/types/product-category.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Transform } from "class-transformer" -import { - IsNotEmpty, - IsOptional, - IsString, - IsBoolean, - ValidateIf, -} from "class-validator" -import { isDefined } from "medusa-core-utils" -import { ProductCategory } from "../models" - -export const tempReorderRank = 99999 -type ProductCategoryInput = { - handle?: string - is_internal?: boolean - is_active?: boolean - parent_category_id?: string | null - parent_category?: ProductCategory | null - rank?: number - metadata?: Record -} - -export type CreateProductCategoryInput = ProductCategoryInput & { - name: string -} - -export type UpdateProductCategoryInput = ProductCategoryInput & { - name?: string -} - -export class AdminProductCategoriesReqBase { - @Transform(({ value }) => (value === "null" ? null : value)) - @ValidateIf((input) => isDefined(input.description)) - @IsString() - description?: string - - @IsOptional() - @IsString() - handle?: string - - @IsBoolean() - @IsOptional() - is_internal?: boolean - - @IsBoolean() - @IsOptional() - is_active?: boolean - - @IsString() - @IsOptional() - @Transform(({ value }) => { - return value === "null" ? null : value - }) - parent_category_id?: string | null -} - -export class ProductBatchProductCategory { - @IsString() - id: string -} - -export type ReorderConditions = { - targetCategoryId: string - originalParentId: string | null - targetParentId: string | null | undefined - originalRank: number - targetRank: number | undefined - shouldChangeParent: boolean - shouldChangeRank: boolean - shouldIncrementRank: boolean - shouldDeleteElement: boolean -} diff --git a/packages/medusa/src/types/product-collection.ts b/packages/medusa/src/types/product-collection.ts deleted file mode 100644 index 17dca44e03..0000000000 --- a/packages/medusa/src/types/product-collection.ts +++ /dev/null @@ -1,11 +0,0 @@ -export type CreateProductCollection = { - title: string - handle?: string - metadata?: Record -} - -export type UpdateProductCollection = { - title?: string - handle?: string - metadata?: Record -} diff --git a/packages/medusa/src/types/product-tax-rate.ts b/packages/medusa/src/types/product-tax-rate.ts deleted file mode 100644 index a71c649b5b..0000000000 --- a/packages/medusa/src/types/product-tax-rate.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { DateComparisonOperator } from "./common" - -/** - * The filters that can be applied when querying for shipping tax rates. - */ -export class FilterableProductTaxRateProps { - product_id?: string | string[] - rate_id?: string | string[] - created_at?: DateComparisonOperator - updated_at?: DateComparisonOperator -} diff --git a/packages/medusa/src/types/product-variant.ts b/packages/medusa/src/types/product-variant.ts deleted file mode 100644 index 15a429be48..0000000000 --- a/packages/medusa/src/types/product-variant.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { - DateComparisonOperator, - NumericalComparisonOperator, - StringComparisonOperator, - WithRequiredProperty, -} from "./common" -import { - IsBoolean, - IsInt, - IsOptional, - IsString, - Validate, - ValidateIf, - ValidateNested, -} from "class-validator" - -import { IsType } from "../utils/validators/is-type" -import { PricedVariant } from "./pricing" -import { ProductVariant } from "../models" -import { XorConstraint } from "./validators/xor" - -export type ProductVariantPrice = { - id?: string - currency_code?: string - region_id?: string - amount: number - min_quantity?: number - max_quantity?: number -} - -export type GetRegionPriceContext = { - regionId: string - quantity?: number - customer_id?: string - include_discount_prices?: boolean -} - -export type ProductVariantOption = { - option_id: string - value: string -} - -export type CreateProductVariantInput = { - title?: string - product_id?: string - sku?: string - barcode?: string - ean?: string - upc?: string - variant_rank?: number - inventory_quantity?: number - allow_backorder?: boolean - manage_inventory?: boolean - hs_code?: string - origin_country?: string - mid_code?: string - material?: string - weight?: number - length?: number - height?: number - width?: number - options: ProductVariantOption[] - prices: ProductVariantPrice[] - metadata?: Record -} - -export type UpdateProductVariantInput = { - title?: string - product_id?: string - sku?: string - barcode?: string - ean?: string - upc?: string - inventory_quantity?: number - allow_backorder?: boolean - manage_inventory?: boolean - hs_code?: string - origin_country?: string - variant_rank?: number - mid_code?: string - material?: string - weight?: number - length?: number - height?: number - width?: number - options?: ProductVariantOption[] - prices?: ProductVariantPrice[] - metadata?: Record -} - -export type UpdateProductVariantData = { - variant: ProductVariant - updateData: UpdateProductVariantInput -} - -export type UpdateVariantPricesData = { - variantId: string - prices: ProductVariantPrice[] -} - -export type UpdateVariantRegionPriceData = { - variantId: string - price: { - currency_code: string - region_id: string - amount: number - } -} - -export type UpdateVariantCurrencyPriceData = { - variantId: string - price: WithRequiredProperty -} - -export class FilterableProductVariantProps { - @ValidateNested() - @IsType([String, [String], StringComparisonOperator]) - id?: string | string[] | StringComparisonOperator - - @IsType([String, [String]]) - title?: string | string[] - - @IsType([String, [String]]) - product_id?: string | string[] - - @IsType([String, [String]]) - sku?: string | string[] - - @IsType([String, [String]]) - barcode?: string | string[] - - @IsType([String, [String]]) - ean?: string | string[] - - @IsType([String]) - upc?: string - - @IsType([Number, NumericalComparisonOperator]) - inventory_quantity?: number | NumericalComparisonOperator - - @IsBoolean() - allow_backorder?: boolean - - @IsBoolean() - manage_inventory?: boolean - - @IsType([String, [String]]) - hs_code?: string | string[] - - @IsType([String, [String]]) - origin_country?: string | string[] - - @IsType([String, [String]]) - mid_code?: string | string[] - - @IsString() - material?: string - - @IsType([Number, NumericalComparisonOperator]) - weight?: number | NumericalComparisonOperator - - @IsType([Number, NumericalComparisonOperator]) - length?: number | NumericalComparisonOperator - - @IsType([Number, NumericalComparisonOperator]) - height?: number | NumericalComparisonOperator - - @IsType([Number, NumericalComparisonOperator]) - width?: number | NumericalComparisonOperator - - @IsString() - q?: string - - @IsType([DateComparisonOperator]) - created_at?: DateComparisonOperator - - @IsType([DateComparisonOperator]) - updated_at?: DateComparisonOperator -} - -export class ProductVariantPricesUpdateReq { - @IsString() - @IsOptional() - id?: string - - @ValidateIf((o) => !o.id) - @Validate(XorConstraint, ["currency_code"]) - region_id?: string - - @ValidateIf((o) => !o.id) - @Validate(XorConstraint, ["region_id"]) - currency_code?: string - - @IsInt() - amount: number - - @IsOptional() - @IsInt() - min_quantity?: number - - @IsOptional() - @IsInt() - max_quantity?: number -} - -export class ProductVariantPricesCreateReq { - @Validate(XorConstraint, ["currency_code"]) - region_id?: string - - @Validate(XorConstraint, ["region_id"]) - currency_code?: string - - @IsInt() - amount: number - - @IsOptional() - @IsInt() - min_quantity?: number - - @IsOptional() - @IsInt() - max_quantity?: number -} diff --git a/packages/medusa/src/types/product.ts b/packages/medusa/src/types/product.ts deleted file mode 100644 index 9ef67cb1c5..0000000000 --- a/packages/medusa/src/types/product.ts +++ /dev/null @@ -1,340 +0,0 @@ -import { Transform, Type } from "class-transformer" -import { - IsArray, - IsBoolean, - IsEnum, - IsOptional, - IsString, - ValidateNested, -} from "class-validator" -import { - PriceList, - Product, - ProductCategory, - ProductOptionValue, - ProductStatus, - SalesChannel, -} from "../models" -import { DateComparisonOperator, FindConfig, Selector } from "./common" - -import { FindOperator } from "typeorm" -import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels" -import { FeatureFlagDecorators } from "../utils/feature-flag-decorators" -import { optionalBooleanMapper } from "../utils/validators/is-boolean" -import { IsType } from "../utils/validators/is-type" -import { PriceListLoadConfig } from "./price-list" - -/** - * Filters to apply on retrieved products. - */ -export class FilterableProductProps { - /** - * IDs to filter products by. - */ - @IsOptional() - @IsType([String, [String]]) - id?: string | string[] - - /** - * Search term to search products' title, description, variants' title and sku, and collections' title. - */ - @IsString() - @IsOptional() - q?: string - - /** - * Statuses to filter products by. - */ - @IsOptional() - @IsEnum(ProductStatus, { each: true }) - status?: ProductStatus[] - - /** - * Filter products by their associated price lists' ID. - */ - @IsArray() - @IsOptional() - price_list_id?: string[] - - /** - * Filter products by their associated product collection's ID. - */ - @IsArray() - @IsOptional() - collection_id?: string[] - - /** - * Filter products by their associated tags' value. - */ - @IsArray() - @IsOptional() - tags?: string[] - - /** - * Title to filter products by. - */ - @IsString() - @IsOptional() - title?: string - - /** - * Description to filter products by. - */ - @IsString() - @IsOptional() - description?: string - - /** - * Handle to filter products by. - */ - @IsString() - @IsOptional() - handle?: string - - /** - * Filter products by whether they're gift cards. - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value.toLowerCase())) - is_giftcard?: boolean - - /** - * Filter products by their associated product type's ID. - */ - @IsArray() - @IsOptional() - type_id?: string[] - - /** - * Filter products by their associated sales channels' ID. - */ - @FeatureFlagDecorators(SalesChannelFeatureFlag.key, [IsOptional(), IsArray()]) - sales_channel_id?: string[] - - /** - * Filter products by their associated discount condition's ID. - */ - @IsString() - @IsOptional() - discount_condition_id?: string - - /** - * Filter products by their associated product category's ID. - */ - @IsArray() - @IsOptional() - category_id?: string[] - - /** - * Whether to include product category children in the response. - * - * @featureFlag product_categories - */ - @IsBoolean() - @IsOptional() - @Transform(({ value }) => optionalBooleanMapper.get(value.toLowerCase())) - include_category_children?: boolean - - /** - * Date filters to apply on the products' `created_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - created_at?: DateComparisonOperator - - /** - * Date filters to apply on the products' `updated_at` date. - */ - @IsOptional() - @ValidateNested() - @Type(() => DateComparisonOperator) - updated_at?: DateComparisonOperator - - /** - * Date filters to apply on the products' `deleted_at` date. - */ - @ValidateNested() - @IsOptional() - @Type(() => DateComparisonOperator) - deleted_at?: DateComparisonOperator -} - -export type ProductSelector = - | FilterableProductProps - | (Selector & { - q?: string - discount_condition_id?: string - price_list_id?: string[] | FindOperator - sales_channel_id?: string[] | FindOperator - category_id?: string[] | FindOperator - }) - -/** - * Service Level DTOs - */ - -export type CreateProductInput = { - title: string - subtitle?: string - profile_id?: string - description?: string - is_giftcard?: boolean - discountable?: boolean - images?: string[] - thumbnail?: string - handle?: string - status?: ProductStatus - type?: CreateProductProductTypeInput - collection_id?: string - tags?: CreateProductProductTagInput[] - options?: CreateProductProductOption[] - variants?: CreateProductProductVariantInput[] - sales_channels?: CreateProductProductSalesChannelInput[] | null - categories?: CreateProductProductCategoryInput[] | null - weight?: number - length?: number - height?: number - width?: number - hs_code?: string - origin_country?: string - mid_code?: string - material?: string - metadata?: Record - external_id?: string | null -} - -export type CreateProductProductTagInput = { - id?: string - value: string -} - -export type CreateProductProductSalesChannelInput = { - id: string -} - -export type CreateProductProductCategoryInput = { - id: string -} - -export type CreateProductProductTypeInput = { - id?: string - value: string -} - -export type CreateProductProductVariantInput = { - title: string - sku?: string - ean?: string - upc?: string - barcode?: string - hs_code?: string - inventory_quantity?: number - allow_backorder?: boolean - manage_inventory?: boolean - weight?: number - length?: number - height?: number - width?: number - origin_country?: string - mid_code?: string - material?: string - metadata?: Record - prices?: CreateProductProductVariantPriceInput[] - options?: { value: string }[] -} - -export type UpdateProductProductVariantDTO = { - id?: string - title?: string - sku?: string - ean?: string - upc?: string - barcode?: string - hs_code?: string - inventory_quantity?: number - allow_backorder?: boolean - manage_inventory?: boolean - weight?: number - length?: number - height?: number - width?: number - origin_country?: string - mid_code?: string - material?: string - metadata?: Record - prices?: CreateProductProductVariantPriceInput[] - options?: { value: string; option_id: string }[] -} - -export type CreateProductProductOption = { - title: string -} - -export type CreateProductProductVariantPriceInput = { - region_id?: string - currency_code?: string - amount: number - min_quantity?: number - max_quantity?: number -} - -export type UpdateProductInput = Omit< - Partial, - "variants" -> & { - variants?: UpdateProductProductVariantDTO[] -} - -export type ProductOptionInput = { - title: string - values?: ProductOptionValue[] -} - -export type FindProductConfig = FindConfig & PriceListLoadConfig - -export class ProductSalesChannelReq { - @IsString() - id: string -} - -export class ProductProductCategoryReq { - @IsString() - id: string -} - -export class ProductTagReq { - @IsString() - @IsOptional() - id?: string - - @IsString() - value: string -} - -/** - * The details of a product type, used to create or update an existing product type. - */ -export class ProductTypeReq { - /** - * The ID of the product type. It's only required when referring to an existing product type. - */ - @IsString() - @IsOptional() - id?: string - - /** - * The value of the product type. - */ - @IsString() - value: string -} - -export type ProductFilterOptions = { - price_list_id?: FindOperator - sales_channel_id?: FindOperator - category_id?: FindOperator - include_category_children?: boolean - discount_condition_id?: string -} diff --git a/packages/medusa/src/types/publishable-api-key.ts b/packages/medusa/src/types/publishable-api-key.ts deleted file mode 100644 index 9e529c9965..0000000000 --- a/packages/medusa/src/types/publishable-api-key.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type CreatePublishableApiKeyInput = { - title: string -} - -export type UpdatePublishableApiKeyInput = { - title?: string -} diff --git a/packages/medusa/src/types/region.ts b/packages/medusa/src/types/region.ts deleted file mode 100644 index c665634316..0000000000 --- a/packages/medusa/src/types/region.ts +++ /dev/null @@ -1,26 +0,0 @@ -export type UpdateRegionInput = { - name?: string - currency_code?: string - tax_code?: string - tax_rate?: number - gift_cards_taxable?: boolean - automatic_taxes?: boolean - tax_provider_id?: string | null - payment_providers?: string[] - fulfillment_providers?: string[] - countries?: string[] - includes_tax?: boolean - metadata?: Record -} - -export type CreateRegionInput = { - name: string - currency_code: string - tax_code?: string - tax_rate: number - payment_providers: string[] - fulfillment_providers: string[] - countries: string[] - includes_tax?: boolean - metadata?: Record -} diff --git a/packages/medusa/src/types/return-reason.ts b/packages/medusa/src/types/return-reason.ts deleted file mode 100644 index 16fd17363d..0000000000 --- a/packages/medusa/src/types/return-reason.ts +++ /dev/null @@ -1,14 +0,0 @@ -export type CreateReturnReason = { - value: string - label: string - parent_return_reason_id?: string - description?: string - metadata?: Record -} - -export type UpdateReturnReason = { - description?: string - label?: string - parent_return_reason_id?: string - metadata?: Record -} diff --git a/packages/medusa/src/types/return.ts b/packages/medusa/src/types/return.ts deleted file mode 100644 index aeebcb0ad5..0000000000 --- a/packages/medusa/src/types/return.ts +++ /dev/null @@ -1,31 +0,0 @@ -type OrdersReturnItem = { - item_id: string - quantity: number - reason_id?: string - note?: string -} - -export type CreateReturnInput = { - order_id: string - swap_id?: string - claim_order_id?: string - items?: OrdersReturnItem[] - shipping_method?: { - option_id?: string - price?: number - } - no_notification?: boolean - metadata?: Record - refund_amount?: number - location_id?: string -} - -export type UpdateReturnInput = { - items?: OrdersReturnItem[] - shipping_method?: { - option_id: string - price?: number - } - no_notification?: boolean - metadata?: Record -} diff --git a/packages/medusa/src/types/routing.ts b/packages/medusa/src/types/routing.ts index 8aedf22874..fcb0223b85 100644 --- a/packages/medusa/src/types/routing.ts +++ b/packages/medusa/src/types/routing.ts @@ -1,5 +1,4 @@ import type { NextFunction, Request, Response } from "express" -import type { Customer, User } from "../models" import { MedusaContainer, @@ -62,7 +61,7 @@ export interface MedusaRequest export interface AuthenticatedMedusaRequest extends MedusaRequest { - user: (User | Customer) & { customer_id?: string; userId?: string } // TODO: Remove this property when v2 is released + user: { customer_id?: string; userId?: string } // TODO: Remove this property when v2 is released auth: { actor_id: string auth_user_id: string diff --git a/packages/medusa/src/types/sales-channels.ts b/packages/medusa/src/types/sales-channels.ts deleted file mode 100644 index c07e37ab06..0000000000 --- a/packages/medusa/src/types/sales-channels.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { IsString } from "class-validator" - -export type CreateSalesChannelInput = { - name: string - description?: string - is_disabled?: boolean -} - -export type UpdateSalesChannelInput = Partial - -export class ProductBatchSalesChannel { - @IsString() - id: string -} diff --git a/packages/medusa/src/types/shipping-options.ts b/packages/medusa/src/types/shipping-options.ts deleted file mode 100644 index 77339bb3f2..0000000000 --- a/packages/medusa/src/types/shipping-options.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { Cart, Order } from ".." -import { - RequirementType, - ShippingOptionRequirement, -} from "../models/shipping-option-requirement" - -import { ShippingOptionPriceType } from "../models/shipping-option" - -export type ShippingRequirement = { - type: RequirementType - amount: number - id: string -} - -export type ShippingMethodUpdate = { - data?: any - price?: number - return_id?: string - swap_id?: string - order_id?: string - claim_order_id?: string | null -} - -export type CreateShippingMethod = { - data?: any - shipping_option_id?: string - price?: number - return_id?: string - swap_id?: string - cart_id?: string - order_id?: string - draft_order_id?: string - claim_order_id?: string -} - -export type CreateShippingMethodDto = CreateShippingMethod & { - cart?: Cart - order?: Order -} - -export type CreateShippingOptionInput = { - price_type: ShippingOptionPriceType - name: string - region_id: string - profile_id: string - provider_id: string - data: Record - includes_tax?: boolean - - amount?: number - is_return?: boolean - admin_only?: boolean - metadata?: Record - requirements?: RequirementInput[] -} - -export type RequirementInput = { type: RequirementType; amount: number } - -export type ValidateRequirementTypeInput = { - id?: string - type: RequirementType - amount: number -} - -export type CreateCustomShippingOptionInput = { - price: number - shipping_option_id: string - cart_id?: string - metadata?: Record -} - -export type UpdateShippingOptionInput = { - metadata?: Record - price_type?: ShippingOptionPriceType - amount?: number - name?: string - admin_only?: boolean - is_return?: boolean - requirements?: RequirementInput[] - region_id?: string - provider_id?: string - profile_id?: string - data?: string - includes_tax?: boolean -} - -export type ValidatePriceTypeAndAmountInput = { - amount?: number - price_type?: ShippingOptionPriceType -} diff --git a/packages/medusa/src/types/shipping-profile.ts b/packages/medusa/src/types/shipping-profile.ts deleted file mode 100644 index e813ff027f..0000000000 --- a/packages/medusa/src/types/shipping-profile.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ShippingProfileType } from "../models" - -export type CreateShippingProfile = { - name: string - type: ShippingProfileType - metadata?: Record -} - -export type UpdateShippingProfile = { - name?: string - metadata?: Record - type?: ShippingProfileType - products?: string[] - shipping_options?: string[] -} diff --git a/packages/medusa/src/types/shipping-tax-rate.ts b/packages/medusa/src/types/shipping-tax-rate.ts deleted file mode 100644 index ab60a189ec..0000000000 --- a/packages/medusa/src/types/shipping-tax-rate.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { DateComparisonOperator } from "./common" - -/** - * The filters that can be applied when querying for shipping tax rates. - */ -export class FilterableShippingTaxRateProps { - shipping_option_id?: string | string[] - rate_id?: string | string[] - created_at?: DateComparisonOperator - updated_at?: DateComparisonOperator -} diff --git a/packages/medusa/src/types/store.ts b/packages/medusa/src/types/store.ts deleted file mode 100644 index cb64d2dceb..0000000000 --- a/packages/medusa/src/types/store.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { ModulesResponse as sdkModulesResponse } from "@medusajs/modules-sdk" -import { FulfillmentProvider, PaymentProvider, Store } from "../models" -import { FeatureFlagsResponse } from "./feature-flags" - -export type UpdateStoreInput = { - name?: string - swap_link_template?: string - payment_link_template?: string - invite_link_template?: string - default_currency_code?: string - currencies?: string[] - metadata?: Record - default_sales_channel_id?: string -} - -/** - * @schema ModulesResponse - * type: array - * items: - * type: object - * required: - * - module - * - resolution - * properties: - * module: - * description: The key of the module. - * type: string - * resolution: - * description: The resolution path of the module or false if module is not installed. - * type: string - */ -export type ModulesResponse = sdkModulesResponse - -/** - * @schema ExtendedStoreDTO - * allOf: - * - $ref: "#/components/schemas/Store" - * - type: object - * required: - * - payment_providers - * - fulfillment_providers - * - feature_flags - * - modules - * properties: - * payment_providers: - * description: "The store's payment providers." - * $ref: "#/components/schemas/PaymentProvider" - * fulfillment_providers: - * description: "The store's fulfillment providers." - * $ref: "#/components/schemas/FulfillmentProvider" - * feature_flags: - * description: "The feature flags enabled in the store's backend." - * $ref: "#/components/schemas/FeatureFlagsResponse" - * modules: - * description: "The modules installed in the store's backend." - * $ref: "#/components/schemas/ModulesResponse" - * - */ -export type ExtendedStoreDTO = Store & { - payment_providers: PaymentProvider[] - fulfillment_providers: FulfillmentProvider[] - feature_flags: FeatureFlagsResponse - modules: ModulesResponse -} diff --git a/packages/medusa/src/types/tax-rate.ts b/packages/medusa/src/types/tax-rate.ts deleted file mode 100644 index f51e029762..0000000000 --- a/packages/medusa/src/types/tax-rate.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { - DateComparisonOperator, - NumericalComparisonOperator, - StringComparisonOperator, -} from "./common" - -export type FilterableTaxRateProps = { - region_id?: string | string[] - code?: string | string[] | StringComparisonOperator - name?: string | string[] - rate?: number | NumericalComparisonOperator - created_at?: Date | DateComparisonOperator - updated_at?: Date | DateComparisonOperator - deleted_at?: Date | DateComparisonOperator - q?: string -} - -export type UpdateTaxRateInput = { - region_id?: string - code?: string - name?: string - rate?: number | null -} - -export type CreateTaxRateInput = { - region_id: string - code: string - name: string - rate?: number | null -} - -export type TaxRateListByConfig = { - region_id?: string -} diff --git a/packages/medusa/src/types/tax-service.ts b/packages/medusa/src/types/tax-service.ts deleted file mode 100644 index eeca0dc0a7..0000000000 --- a/packages/medusa/src/types/tax-service.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { LineItemTaxLine, ShippingMethodTaxLine } from "../models" - -export type TaxLinesMaps = { - lineItemsTaxLines: { [lineItemId: string]: LineItemTaxLine[] } - shippingMethodsTaxLines: { - [shippingMethodId: string]: ShippingMethodTaxLine[] - } -} - -/** - * The tax rate object as configured in Medusa. These may have an unspecified - * numerical rate as they may be used for lookup purposes in the tax provider - * plugin. - */ -export type TaxServiceRate = { - /** - * The tax rate. - */ - rate?: number | null - /** - * The tax rate's name. - */ - name: string - /** - * The tax rate's code. - */ - code: string | null -} - -/** - * The tax line properties for a given shipping method. - */ -export type ProviderShippingMethodTaxLine = { - /** - * The tax rate. - */ - rate: number - /** - * The tax rate's name. - */ - name: string - /** - * The tax code. - */ - code: string | null - /** - * Holds any necessary additional data to be added to the shipping method tax lines. - */ - metadata?: Record - /** - * The shipping method's ID. - */ - shipping_method_id: string -} - -/** - * The tax line properties for a given line item. - */ -export type ProviderLineItemTaxLine = { - /** - * The tax rate. - */ - rate: number - /** - * The tax rate's name. - */ - name: string - /** - * The tax code. - */ - code: string | null - /** - * The line item's ID. - */ - item_id: string - /** - * Holds any necessary additional data to be added to the line item tax lines. - */ - metadata?: Record -} - -/** - * A union type of the possible provider tax lines. - */ -export type ProviderTaxLine = - | ProviderLineItemTaxLine - | ProviderShippingMethodTaxLine diff --git a/packages/medusa/src/types/token.ts b/packages/medusa/src/types/token.ts deleted file mode 100644 index 01c8e3ef00..0000000000 --- a/packages/medusa/src/types/token.ts +++ /dev/null @@ -1,3 +0,0 @@ -export enum TokenEvents { - ORDER_UPDATE_TOKEN_CREATED = "order-update-token.created", -} diff --git a/packages/medusa/src/types/totals.ts b/packages/medusa/src/types/totals.ts deleted file mode 100644 index de8d4930bc..0000000000 --- a/packages/medusa/src/types/totals.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { - Address, - ClaimOrder, - Customer, - Discount, - LineItem, - Region, - ShippingMethod, - Swap, -} from "../models" - -export type CalculationContextData = { - discounts: Discount[] - items: LineItem[] - customer: Customer - region: Region - shipping_address: Address | null - swaps?: Swap[] - claims?: ClaimOrder[] - shipping_methods?: ShippingMethod[] -} - -/** The amount of a gift card allocated to a line item */ -export type GiftCardAllocation = { - amount: number - unit_amount: number -} - -/** The amount of a discount allocated to a line item */ -export type DiscountAllocation = { - amount: number - unit_amount: number -} - -/** - * A map of line item ids and its corresponding gift card and discount - * allocations - */ -export type LineAllocationsMap = { - [K: string]: { - /** - * The gift card applied on the line item. - */ - gift_card?: GiftCardAllocation - /** - * The discount applied on the line item. - */ - discount?: DiscountAllocation - } -} - -/** - * Options to use for subtotal calculations - */ -export type SubtotalOptions = { - excludeNonDiscounts?: boolean -} - -/** - * Associates a line item and discount allocation. - */ -export type LineDiscount = { - lineItem: LineItem - variant: string - amount: number -} - -/** - * Associates a line item and discount allocation. - */ -export type LineDiscountAmount = { - item: LineItem - amount: number - customAdjustmentsAmount: number -} diff --git a/packages/medusa/src/types/user.ts b/packages/medusa/src/types/user.ts deleted file mode 100644 index 64e6391f56..0000000000 --- a/packages/medusa/src/types/user.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { User, UserRoles } from "../models/user" -import { PartialPick } from "./common" - -export interface CreateUserInput { - id?: string - email: string - first_name?: string - last_name?: string - api_token?: string - role?: UserRoles - metadata?: Record -} - -export interface UpdateUserInput { - readonly email?: string - first_name?: string - last_name?: string - readonly password_hash?: string - api_token?: string - role?: UserRoles - metadata?: Record -} - -export enum UserRole { - MEMBER = "member", - ADMIN = "admin", - DEVELOPER = "developer", -} - -export type FilterableUserProps = PartialPick< - User, - | "email" - | "first_name" - | "last_name" - | "role" - | "created_at" - | "updated_at" - | "deleted_at" -> diff --git a/packages/medusa/src/utils/__tests__/validator.spec.ts b/packages/medusa/src/utils/__tests__/validator.spec.ts deleted file mode 100644 index 00c1162ea8..0000000000 --- a/packages/medusa/src/utils/__tests__/validator.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { IsString } from "class-validator" -import { AdminPostProductsReq as MedusaAdminPostProductsReq } from "../../api/routes/admin/products/create-product" -import { registerOverriddenValidators, validator } from "../validator" - -class AdminPostProductsReq extends MedusaAdminPostProductsReq { - @IsString() - custom_attribute: string -} - -describe("Validator", function () { - it("should override the original validator", async function () { - let err = await validator(MedusaAdminPostProductsReq, { - title: "test", - }) - .then(() => void 0) - .catch((err) => err) - - expect(err).not.toBeDefined() - - registerOverriddenValidators(AdminPostProductsReq) - - err = await validator(MedusaAdminPostProductsReq, { - title: "test", - }) - .then(() => void 0) - .catch((err) => err) - - expect(err).toBeDefined() - expect(err.message).toEqual("custom_attribute must be a string") - - err = await validator(MedusaAdminPostProductsReq, { - title: "test", - custom_attribute: "test", - }) - .then(() => void 0) - .catch((err) => err) - - expect(err).not.toBeDefined() - }) -}) diff --git a/packages/medusa/src/utils/index.ts b/packages/medusa/src/utils/index.ts index 3b175244ef..5b25a5dcaf 100644 --- a/packages/medusa/src/utils/index.ts +++ b/packages/medusa/src/utils/index.ts @@ -10,8 +10,6 @@ export * from "./is-date" export * from "./is-object" export * from "./is-string" export * from "./omit-deep" -export * from "./product-category" -export * from "./queries" export * from "./remote-query-fetch-data" export * from "./remove-undefined-properties" export * from "./set-metadata" diff --git a/packages/medusa/src/api/middlewares/__tests__/transform-query.spec.ts b/packages/medusa/src/utils/middlewares/__tests__/transform-query.spec.ts similarity index 100% rename from packages/medusa/src/api/middlewares/__tests__/transform-query.spec.ts rename to packages/medusa/src/utils/middlewares/__tests__/transform-query.spec.ts diff --git a/packages/medusa/src/api/middlewares/authenticate-customer.ts b/packages/medusa/src/utils/middlewares/authenticate-customer.ts similarity index 100% rename from packages/medusa/src/api/middlewares/authenticate-customer.ts rename to packages/medusa/src/utils/middlewares/authenticate-customer.ts diff --git a/packages/medusa/src/api/middlewares/authenticate.ts b/packages/medusa/src/utils/middlewares/authenticate.ts similarity index 100% rename from packages/medusa/src/api/middlewares/authenticate.ts rename to packages/medusa/src/utils/middlewares/authenticate.ts diff --git a/packages/medusa/src/api/middlewares/await-middleware.ts b/packages/medusa/src/utils/middlewares/await-middleware.ts similarity index 100% rename from packages/medusa/src/api/middlewares/await-middleware.ts rename to packages/medusa/src/utils/middlewares/await-middleware.ts diff --git a/packages/medusa/src/api/middlewares/check-registered-modules.ts b/packages/medusa/src/utils/middlewares/check-registered-modules.ts similarity index 100% rename from packages/medusa/src/api/middlewares/check-registered-modules.ts rename to packages/medusa/src/utils/middlewares/check-registered-modules.ts diff --git a/packages/medusa/src/api/middlewares/error-handler.ts b/packages/medusa/src/utils/middlewares/error-handler.ts similarity index 100% rename from packages/medusa/src/api/middlewares/error-handler.ts rename to packages/medusa/src/utils/middlewares/error-handler.ts diff --git a/packages/medusa/src/api/middlewares/feature-flag-enabled.ts b/packages/medusa/src/utils/middlewares/feature-flag-enabled.ts similarity index 100% rename from packages/medusa/src/api/middlewares/feature-flag-enabled.ts rename to packages/medusa/src/utils/middlewares/feature-flag-enabled.ts diff --git a/packages/medusa/src/utils/middlewares/index.ts b/packages/medusa/src/utils/middlewares/index.ts new file mode 100644 index 0000000000..ee4cdcd5e9 --- /dev/null +++ b/packages/medusa/src/utils/middlewares/index.ts @@ -0,0 +1,10 @@ +export { default as authenticate } from "./authenticate" +export { default as authenticateCustomer } from "./authenticate-customer" +export { default as wrapHandler } from "./await-middleware" +export { default as errorHandler } from "./error-handler" +export { isFeatureFlagEnabled } from "./feature-flag-enabled" +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/middlewares/normalized-query.ts b/packages/medusa/src/utils/middlewares/normalized-query.ts similarity index 100% rename from packages/medusa/src/api/middlewares/normalized-query.ts rename to packages/medusa/src/utils/middlewares/normalized-query.ts diff --git a/packages/medusa/src/api/middlewares/require-customer-authentication.ts b/packages/medusa/src/utils/middlewares/require-customer-authentication.ts similarity index 100% rename from packages/medusa/src/api/middlewares/require-customer-authentication.ts rename to packages/medusa/src/utils/middlewares/require-customer-authentication.ts diff --git a/packages/medusa/src/api/middlewares/transform-body.ts b/packages/medusa/src/utils/middlewares/transform-body.ts similarity index 100% rename from packages/medusa/src/api/middlewares/transform-body.ts rename to packages/medusa/src/utils/middlewares/transform-body.ts diff --git a/packages/medusa/src/api/middlewares/transform-includes-options.ts b/packages/medusa/src/utils/middlewares/transform-includes-options.ts similarity index 100% rename from packages/medusa/src/api/middlewares/transform-includes-options.ts rename to packages/medusa/src/utils/middlewares/transform-includes-options.ts diff --git a/packages/medusa/src/api/middlewares/transform-query.ts b/packages/medusa/src/utils/middlewares/transform-query.ts similarity index 100% rename from packages/medusa/src/api/middlewares/transform-query.ts rename to packages/medusa/src/utils/middlewares/transform-query.ts diff --git a/packages/medusa/src/utils/naming-strategy.ts b/packages/medusa/src/utils/naming-strategy.ts deleted file mode 100644 index 74463244df..0000000000 --- a/packages/medusa/src/utils/naming-strategy.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Since typeorm require us to use ES6 and that migrating require a lot of work -// one solution is to override directly the one from typeorm so that there is no complain about -// the output build -import { DefaultNamingStrategy } from "typeorm" - -DefaultNamingStrategy.prototype.eagerJoinRelationAlias = function ( - alias: string, - propertyPath: string -): string { - const path = propertyPath - .split(".") - .map((p) => p.substring(0, 2)) - .join("_") - const out = alias + "_" + path - const match = out.match(/_/g) || [] - return out + match.length -} diff --git a/packages/medusa/src/utils/product-category/index.ts b/packages/medusa/src/utils/product-category/index.ts deleted file mode 100644 index 01ec732be2..0000000000 --- a/packages/medusa/src/utils/product-category/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { FindOptionsWhere } from "typeorm" -import { ProductCategory } from "../../models" -import { isDefined } from "medusa-core-utils" - -export const categoryMatchesScope = ( - category: ProductCategory, - query: FindOptionsWhere -): boolean => { - return Object.keys(query ?? {}).every(key => category[key] === query[key]) -} - -export const fetchCategoryDescendantsIds = ( - productCategory: ProductCategory, - query: FindOptionsWhere -) => { - let result = [productCategory.id] - - ;(productCategory.category_children || []).forEach((child) => { - if (categoryMatchesScope(child, query)) { - result = result.concat(fetchCategoryDescendantsIds(child, query)) - } - }) - - return result -} diff --git a/packages/medusa/src/utils/queries/index.ts b/packages/medusa/src/utils/queries/index.ts deleted file mode 100644 index 0413143cb8..0000000000 --- a/packages/medusa/src/utils/queries/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./products" diff --git a/packages/medusa/src/utils/queries/products/get-variants-from-price-list.ts b/packages/medusa/src/utils/queries/products/get-variants-from-price-list.ts deleted file mode 100644 index b2f0ae17e1..0000000000 --- a/packages/medusa/src/utils/queries/products/get-variants-from-price-list.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { MedusaContainer, ProductVariantDTO } from "@medusajs/types" - -export async function getVariantsFromPriceList( - container: MedusaContainer, - priceListId: string -) { - const remoteQuery = container.resolve("remoteQuery") - const query = { - price_list: { - __args: { id: [priceListId] }, - prices: { - price_set: { - variant_link: { variant: { fields: ["id", "product_id"] } }, - }, - }, - }, - } - - const priceLists = await remoteQuery(query) - const variants: ProductVariantDTO[] = [] - - priceLists.forEach((priceList) => { - priceList.prices?.forEach((price) => { - const variant = price.price_set?.variant_link?.variant - - if (variant) { - variants.push(variant) - } - }) - }) - - return variants -} diff --git a/packages/medusa/src/utils/queries/products/index.ts b/packages/medusa/src/utils/queries/products/index.ts deleted file mode 100644 index d33b807605..0000000000 --- a/packages/medusa/src/utils/queries/products/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./get-variants-from-price-list" -export * from "./list-products" -export * from "./retrieve-product" diff --git a/packages/medusa/src/utils/queries/products/list-products.ts b/packages/medusa/src/utils/queries/products/list-products.ts deleted file mode 100644 index 117fe0dde4..0000000000 --- a/packages/medusa/src/utils/queries/products/list-products.ts +++ /dev/null @@ -1,235 +0,0 @@ -import { MedusaContainer } from "@medusajs/types" -import { MedusaV2Flag, promiseAll } from "@medusajs/utils" - -import { PriceListService } from "../../../services" -import { getVariantsFromPriceList } from "./get-variants-from-price-list" - -export async function listProducts( - container: MedusaContainer, - filterableFields, - listConfig -) { - // TODO: Add support for fields/expands - - const remoteQuery = container.resolve("remoteQuery") - const featureFlagRouter = container.resolve("featureFlagRouter") - - const productIdsFilter: Set = new Set() - const variantIdsFilter: Set = new Set() - - const promises: Promise[] = [] - - // This is not the best way of handling cross filtering but for now I would say it is fine - const salesChannelIdFilter = filterableFields.sales_channel_id - delete filterableFields.sales_channel_id - - const priceListId = filterableFields.price_list_id - delete filterableFields.price_list_id - - if (priceListId) { - if (featureFlagRouter.isFeatureEnabled(MedusaV2Flag.key)) { - const variants = await getVariantsFromPriceList(container, priceListId) - - variants.forEach((pv) => variantIdsFilter.add(pv.id)) - } else { - // TODO: it is working but validate the behaviour. - // e.g pricing context properly set. - // At the moment filtering by price list but not having any customer id or - // include discount forces the query to filter with price list id is null - const priceListService = container.resolve( - "priceListService" - ) as PriceListService - - promises.push( - priceListService - .listPriceListsVariantIdsMap(priceListId) - .then((priceListVariantIdsMap) => { - priceListVariantIdsMap[priceListId].map((variantId) => - variantIdsFilter.add(variantId) - ) - }) - ) - } - } - - const discountConditionId = filterableFields.discount_condition_id - delete filterableFields.discount_condition_id - - if (discountConditionId) { - // TODO implement later - } - - await promiseAll(promises) - - if (productIdsFilter.size > 0) { - filterableFields.id = Array.from(productIdsFilter) - } - - if (variantIdsFilter.size > 0) { - filterableFields.variants = { id: Array.from(variantIdsFilter) } - } - - const variables = { - filters: filterableFields, - order: listConfig.order, - skip: listConfig.skip, - take: listConfig.take, - } - - const query = { - product: { - __args: variables, - ...defaultAdminProductRemoteQueryObject, - }, - } - - if (salesChannelIdFilter) { - query.product["sales_channels"]["__args"] = { id: salesChannelIdFilter } - } - - const { - rows: products, - metadata: { count }, - } = await remoteQuery(query) - - products.forEach((product) => { - product.profile_id = product.profile?.id - }) - - return [products, count] -} - -export const defaultAdminProductRemoteQueryObject = { - fields: [ - "id", - "title", - "subtitle", - "status", - "external_id", - "description", - "handle", - "is_giftcard", - "discountable", - "thumbnail", - "collection_id", - "type_id", - "weight", - "length", - "height", - "width", - "hs_code", - "origin_country", - "mid_code", - "material", - "created_at", - "updated_at", - "deleted_at", - "metadata", - ], - images: { - fields: ["id", "created_at", "updated_at", "deleted_at", "url", "metadata"], - }, - tags: { - fields: ["id", "created_at", "updated_at", "deleted_at", "value"], - }, - - type: { - fields: ["id", "created_at", "updated_at", "deleted_at", "value"], - }, - - collection: { - fields: ["title", "handle", "id", "created_at", "updated_at", "deleted_at"], - }, - - categories: { - fields: [ - "id", - "name", - "description", - "handle", - "is_active", - "is_internal", - "parent_category_id", - ], - }, - - options: { - fields: [ - "id", - "created_at", - "updated_at", - "deleted_at", - "title", - "product_id", - "metadata", - ], - values: { - fields: [ - "id", - "created_at", - "updated_at", - "deleted_at", - "value", - "option_id", - "variant_id", - "metadata", - ], - }, - }, - - variants: { - fields: [ - "id", - "created_at", - "updated_at", - "deleted_at", - "title", - "product_id", - "sku", - "barcode", - "ean", - "upc", - "variant_rank", - "inventory_quantity", - "allow_backorder", - "manage_inventory", - "hs_code", - "origin_country", - "mid_code", - "material", - "weight", - "length", - "height", - "width", - "metadata", - ], - - options: { - fields: [ - "id", - "created_at", - "updated_at", - "deleted_at", - "value", - "option_id", - "variant_id", - "metadata", - ], - }, - }, - profile: { - fields: ["id", "created_at", "updated_at", "deleted_at", "name", "type"], - }, - sales_channels: { - fields: [ - "id", - "name", - "description", - "is_disabled", - "created_at", - "updated_at", - "deleted_at", - "metadata", - ], - }, -} diff --git a/packages/medusa/src/utils/queries/products/retrieve-product.ts b/packages/medusa/src/utils/queries/products/retrieve-product.ts deleted file mode 100644 index 336e5d52cf..0000000000 --- a/packages/medusa/src/utils/queries/products/retrieve-product.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MedusaError } from "@medusajs/utils" - -export async function retrieveProduct(container, id, remoteQueryObject = {}) { - // TODO: Add support for fields/expands - const remoteQuery = container.resolve("remoteQuery") - - const variables = { id } - - const query = { - product: { - __args: variables, - ...remoteQueryObject, - }, - } - - const [product] = await remoteQuery(query) - - if (!product) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Product with id: ${id} not found` - ) - } - - product.profile_id = product.profile?.id - - return product -} diff --git a/packages/modules/file/package.json b/packages/modules/file/package.json index 958d773bc4..2895039ecf 100644 --- a/packages/modules/file/package.json +++ b/packages/modules/file/package.json @@ -36,7 +36,7 @@ "devDependencies": { "@mikro-orm/cli": "5.9.7", "cross-env": "^5.2.1", - "faker": "^6.6.6", + "faker": "^5.5.3", "jest": "^29.6.3", "medusa-test-utils": "^1.1.43", "pg-god": "^1.0.12", diff --git a/packages/modules/product/package.json b/packages/modules/product/package.json index c5d474ada1..f0115aef1f 100644 --- a/packages/modules/product/package.json +++ b/packages/modules/product/package.json @@ -39,7 +39,7 @@ "devDependencies": { "@mikro-orm/cli": "5.9.7", "cross-env": "^5.2.1", - "faker": "^6.6.6", + "faker": "^5.5.3", "jest": "^29.6.3", "medusa-test-utils": "^1.1.44", "pg-god": "^1.0.12", diff --git a/packages/modules/region/src/loaders/defaults.ts b/packages/modules/region/src/loaders/defaults.ts index 2375b51dda..7ea3aa1a7b 100644 --- a/packages/modules/region/src/loaders/defaults.ts +++ b/packages/modules/region/src/loaders/defaults.ts @@ -1,7 +1,5 @@ -import { Logger } from "@medusajs/types" -import { LoaderOptions, ModulesSdkTypes } from "@medusajs/types" -import { ContainerRegistrationKeys } from "@medusajs/utils" -import { DefaultsUtils } from "@medusajs/utils" +import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types" +import { ContainerRegistrationKeys, DefaultsUtils } from "@medusajs/utils" import { Country } from "@models" export default async ({ container }: LoaderOptions): Promise => { diff --git a/www/apps/ui/package.json b/www/apps/ui/package.json index d3a9028450..e384ccbbdc 100644 --- a/www/apps/ui/package.json +++ b/www/apps/ui/package.json @@ -17,7 +17,7 @@ "@medusajs/icons": "^1.2.0", "@medusajs/ui": "^3.0.0", "@medusajs/ui-preset": "^1.1.3", - "@radix-ui/react-dialog": "^1.0.4", + "@radix-ui/react-dialog": "1.0.4", "@radix-ui/react-scroll-area": "^1.0.4", "@radix-ui/react-tabs": "^1.0.4", "@types/node": "20.4.9", diff --git a/yarn.lock b/yarn.lock index 5b25232498..b53256403d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,17 +5,10 @@ __metadata: version: 6 cacheKey: 8c0 -"@aashutoshrathi/word-wrap@npm:^1.2.3": - version: 1.2.6 - resolution: "@aashutoshrathi/word-wrap@npm:1.2.6" - checksum: 53c2b231a61a46792b39a0d43bc4f4f776bb4542aa57ee04930676802e5501282c2fc8aac14e4cd1f1120ff8b52616b6ff5ab539ad30aa2277d726444b71619f - languageName: node - linkType: hard - "@adobe/css-tools@npm:^4.0.1": - version: 4.3.1 - resolution: "@adobe/css-tools@npm:4.3.1" - checksum: 05672719b544cc0c21ae3ed0eb6349bf458e9d09457578eeeb07cf0f696469ac6417e9c9be1b129e5d6a18098a061c1db55b2275591760ef30a79822436fcbfa + version: 4.3.3 + resolution: "@adobe/css-tools@npm:4.3.3" + checksum: e76e712df713964b87cdf2aca1f0477f19bebd845484d5fcba726d3ec7782366e2f26ec8cb2dcfaf47081a5c891987d8a9f5c3f30d11e1eb3c1848adc27fcb24 languageName: node linkType: hard @@ -27,12 +20,12 @@ __metadata: linkType: hard "@ampproject/remapping@npm:^2.2.0, @ampproject/remapping@npm:^2.2.1": - version: 2.2.1 - resolution: "@ampproject/remapping@npm:2.2.1" + version: 2.3.0 + resolution: "@ampproject/remapping@npm:2.3.0" dependencies: - "@jridgewell/gen-mapping": ^0.3.0 - "@jridgewell/trace-mapping": ^0.3.9 - checksum: 92ce5915f8901d8c7cd4f4e6e2fe7b9fd335a29955b400caa52e0e5b12ca3796ada7c2f10e78c9c5b0f9c2539dff0ffea7b19850a56e1487aa083531e1e46d43 + "@jridgewell/gen-mapping": ^0.3.5 + "@jridgewell/trace-mapping": ^0.3.24 + checksum: 81d63cca5443e0f0c72ae18b544cc28c7c0ec2cea46e7cb888bb0e0f411a1191d0d6b7af798d54e30777d8d1488b2ec0732aac2be342d3d7d3ffd271c6f489ed languageName: node linkType: hard @@ -62,36 +55,36 @@ __metadata: languageName: node linkType: hard -"@ariakit/core@npm:0.4.1": - version: 0.4.1 - resolution: "@ariakit/core@npm:0.4.1" - checksum: 2402e054f888d67b44bed81e80757a915ea0f943c3ac76e65f3a1f96973eaa291a344fb6edeeee09f007ede372ef745e43a058e1404ee745d2caf55b7290a8b8 +"@ariakit/core@npm:0.4.6": + version: 0.4.6 + resolution: "@ariakit/core@npm:0.4.6" + checksum: ca95be5acfd55ad99fa2eaddfdcf2dd178622ac64634bec80709dc4c722f8f15ac6d321831c72ab034001fe00964f7a2531e519916f29cf885d8cf3ffdbb6776 languageName: node linkType: hard -"@ariakit/react-core@npm:0.4.1": - version: 0.4.1 - resolution: "@ariakit/react-core@npm:0.4.1" +"@ariakit/react-core@npm:0.4.6": + version: 0.4.6 + resolution: "@ariakit/react-core@npm:0.4.6" dependencies: - "@ariakit/core": 0.4.1 + "@ariakit/core": 0.4.6 "@floating-ui/dom": ^1.0.0 use-sync-external-store: ^1.2.0 peerDependencies: react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 - checksum: a6388f8c46dd49f0a117639950261fdf7d38c0b395b5e2d87edd1cf9aa479ea0cab338b716a915b7d13142e88ad0430b85a95c9558dbc892c9a7b51bbc702092 + checksum: cd24d020a380a5de48607119c7f46a1b64bc8780d7b4a18f09207b2a3c13957cfc1c5dc0256ad8dd0924714b074e30f4af5702d25b438885516d9c900cc8ce91 languageName: node linkType: hard "@ariakit/react@npm:^0.4.1": - version: 0.4.1 - resolution: "@ariakit/react@npm:0.4.1" + version: 0.4.6 + resolution: "@ariakit/react@npm:0.4.6" dependencies: - "@ariakit/react-core": 0.4.1 + "@ariakit/react-core": 0.4.6 peerDependencies: react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 - checksum: 31a2a8f63a8e3ab5037445669da4005ab61d5f7957c39780b32ef3ac77db478ac39b940a16a252c24f2babf95c44d363fc904667b7ddf86bb30332845080cddc + checksum: 647d540c81d116de690e80544152471be59ced91ca1a31e81dbafea162397e3ce16844401eac708c06e8ad834ca6779eb373fc4634e28d6ecdb7e0f2fce4a061 languageName: node linkType: hard @@ -213,33 +206,34 @@ __metadata: linkType: hard "@aws-sdk/client-s3@npm:^3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/client-s3@npm:3.556.0" + version: 3.569.0 + resolution: "@aws-sdk/client-s3@npm:3.569.0" dependencies: "@aws-crypto/sha1-browser": 3.0.0 "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/credential-provider-node": 3.556.0 - "@aws-sdk/middleware-bucket-endpoint": 3.535.0 - "@aws-sdk/middleware-expect-continue": 3.535.0 - "@aws-sdk/middleware-flexible-checksums": 3.535.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-location-constraint": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-sdk-s3": 3.556.0 - "@aws-sdk/middleware-signing": 3.556.0 - "@aws-sdk/middleware-ssec": 3.537.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/signature-v4-multi-region": 3.556.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 - "@aws-sdk/xml-builder": 3.535.0 + "@aws-sdk/client-sso-oidc": 3.569.0 + "@aws-sdk/client-sts": 3.569.0 + "@aws-sdk/core": 3.567.0 + "@aws-sdk/credential-provider-node": 3.569.0 + "@aws-sdk/middleware-bucket-endpoint": 3.568.0 + "@aws-sdk/middleware-expect-continue": 3.567.0 + "@aws-sdk/middleware-flexible-checksums": 3.567.0 + "@aws-sdk/middleware-host-header": 3.567.0 + "@aws-sdk/middleware-location-constraint": 3.567.0 + "@aws-sdk/middleware-logger": 3.568.0 + "@aws-sdk/middleware-recursion-detection": 3.567.0 + "@aws-sdk/middleware-sdk-s3": 3.569.0 + "@aws-sdk/middleware-signing": 3.567.0 + "@aws-sdk/middleware-ssec": 3.567.0 + "@aws-sdk/middleware-user-agent": 3.567.0 + "@aws-sdk/region-config-resolver": 3.567.0 + "@aws-sdk/signature-v4-multi-region": 3.569.0 + "@aws-sdk/types": 3.567.0 + "@aws-sdk/util-endpoints": 3.567.0 + "@aws-sdk/util-user-agent-browser": 3.567.0 + "@aws-sdk/util-user-agent-node": 3.568.0 + "@aws-sdk/xml-builder": 3.567.0 "@smithy/config-resolver": ^2.2.0 "@smithy/core": ^1.4.2 "@smithy/eventstream-serde-browser": ^2.2.0 @@ -273,27 +267,28 @@ __metadata: "@smithy/util-utf8": ^2.3.0 "@smithy/util-waiter": ^2.2.0 tslib: ^2.6.2 - checksum: 3755905c409f45e5772bb895be9efdb7d0bc4837f43417aa9952b4cdd944c6542d6df0b20b80a9ea5168a3d500e56b169f077c1fa4081cad4278a185c740d080 + checksum: 426a13f97d0c7c0d5b87748646d9da5df8f851fb0f2e92f7f6642d35ec32fa4756273a60f8da3d8da1852d01f8ee1f62969ee9d880be08a798dd32000846c08d languageName: node linkType: hard -"@aws-sdk/client-sso-oidc@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/client-sso-oidc@npm:3.556.0" +"@aws-sdk/client-sso-oidc@npm:3.569.0": + version: 3.569.0 + resolution: "@aws-sdk/client-sso-oidc@npm:3.569.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 + "@aws-sdk/client-sts": 3.569.0 + "@aws-sdk/core": 3.567.0 + "@aws-sdk/credential-provider-node": 3.569.0 + "@aws-sdk/middleware-host-header": 3.567.0 + "@aws-sdk/middleware-logger": 3.568.0 + "@aws-sdk/middleware-recursion-detection": 3.567.0 + "@aws-sdk/middleware-user-agent": 3.567.0 + "@aws-sdk/region-config-resolver": 3.567.0 + "@aws-sdk/types": 3.567.0 + "@aws-sdk/util-endpoints": 3.567.0 + "@aws-sdk/util-user-agent-browser": 3.567.0 + "@aws-sdk/util-user-agent-node": 3.568.0 "@smithy/config-resolver": ^2.2.0 "@smithy/core": ^1.4.2 "@smithy/fetch-http-handler": ^2.5.0 @@ -320,28 +315,26 @@ __metadata: "@smithy/util-retry": ^2.2.0 "@smithy/util-utf8": ^2.3.0 tslib: ^2.6.2 - peerDependencies: - "@aws-sdk/credential-provider-node": ^3.556.0 - checksum: 578c67922d31e88c5b7c1b45e73041dc8a3c8989992c37e87ce9f53aacb638730157fb4e981ca445945dd1ad1df5f46e2c76decd9ab26895e4b57fbc629b8fda + checksum: 84ec9dbd946d9d836636efe5b5a40755f4c495097bb6b67f4bf2424727446e8484ef2f3a7d1b0e6e933aadeaf45127b14674e7e8e46418918a1ae097cf86a7ed languageName: node linkType: hard -"@aws-sdk/client-sso@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/client-sso@npm:3.556.0" +"@aws-sdk/client-sso@npm:3.568.0": + version: 3.568.0 + resolution: "@aws-sdk/client-sso@npm:3.568.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 + "@aws-sdk/core": 3.567.0 + "@aws-sdk/middleware-host-header": 3.567.0 + "@aws-sdk/middleware-logger": 3.568.0 + "@aws-sdk/middleware-recursion-detection": 3.567.0 + "@aws-sdk/middleware-user-agent": 3.567.0 + "@aws-sdk/region-config-resolver": 3.567.0 + "@aws-sdk/types": 3.567.0 + "@aws-sdk/util-endpoints": 3.567.0 + "@aws-sdk/util-user-agent-browser": 3.567.0 + "@aws-sdk/util-user-agent-node": 3.568.0 "@smithy/config-resolver": ^2.2.0 "@smithy/core": ^1.4.2 "@smithy/fetch-http-handler": ^2.5.0 @@ -368,26 +361,28 @@ __metadata: "@smithy/util-retry": ^2.2.0 "@smithy/util-utf8": ^2.3.0 tslib: ^2.6.2 - checksum: f0666befa86731f602705b863a3d354188d4645d765f73f6adbce65e9d72b5a71d8bf8074f7d498d8d7c440518d728fd2418c29306de749b10d251d37525ca39 + checksum: b73bbeec480c6fe448b310fa607f4d89ae37dc3d7d4067041794938a633c708d0d6f227579e9fd26976a0074737520e83707a99b61d9a77e782358a177db633a languageName: node linkType: hard -"@aws-sdk/client-sts@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/client-sts@npm:3.556.0" +"@aws-sdk/client-sts@npm:3.569.0": + version: 3.569.0 + resolution: "@aws-sdk/client-sts@npm:3.569.0" dependencies: "@aws-crypto/sha256-browser": 3.0.0 "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/core": 3.556.0 - "@aws-sdk/middleware-host-header": 3.535.0 - "@aws-sdk/middleware-logger": 3.535.0 - "@aws-sdk/middleware-recursion-detection": 3.535.0 - "@aws-sdk/middleware-user-agent": 3.540.0 - "@aws-sdk/region-config-resolver": 3.535.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 - "@aws-sdk/util-user-agent-browser": 3.535.0 - "@aws-sdk/util-user-agent-node": 3.535.0 + "@aws-sdk/client-sso-oidc": 3.569.0 + "@aws-sdk/core": 3.567.0 + "@aws-sdk/credential-provider-node": 3.569.0 + "@aws-sdk/middleware-host-header": 3.567.0 + "@aws-sdk/middleware-logger": 3.568.0 + "@aws-sdk/middleware-recursion-detection": 3.567.0 + "@aws-sdk/middleware-user-agent": 3.567.0 + "@aws-sdk/region-config-resolver": 3.567.0 + "@aws-sdk/types": 3.567.0 + "@aws-sdk/util-endpoints": 3.567.0 + "@aws-sdk/util-user-agent-browser": 3.567.0 + "@aws-sdk/util-user-agent-node": 3.568.0 "@smithy/config-resolver": ^2.2.0 "@smithy/core": ^1.4.2 "@smithy/fetch-http-handler": ^2.5.0 @@ -414,15 +409,13 @@ __metadata: "@smithy/util-retry": ^2.2.0 "@smithy/util-utf8": ^2.3.0 tslib: ^2.6.2 - peerDependencies: - "@aws-sdk/credential-provider-node": ^3.556.0 - checksum: e100a9b4deddebc9873236060a036e903dac752f35eccc73446a23830901453b5d1c319dbea63e24a01843251e8bd135c221a297249cab63fc4ff81279639a2a + checksum: ef9ec337215adbeb7c4aa2de968a716965438c445bc95f1f1e905b4ce928fb941ed2e27bcbae003b346fa6b16c983a682ae12a74bef407bf9989de47314a8b74 languageName: node linkType: hard -"@aws-sdk/core@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/core@npm:3.556.0" +"@aws-sdk/core@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/core@npm:3.567.0" dependencies: "@smithy/core": ^1.4.2 "@smithy/protocol-http": ^3.3.0 @@ -431,27 +424,27 @@ __metadata: "@smithy/types": ^2.12.0 fast-xml-parser: 4.2.5 tslib: ^2.6.2 - checksum: b63102d87fe3dc3afda490071fba39bf71be8eadfad1f96dd28fdb28d2960375dda795d188bd88322a5baa7207a761fd03045fd5c880e9a5e0027bb9b16340cb + checksum: 074fb005cb6baae7805c0470d7c0d5baf1825aafee43a2458c6cacf89d1593f7a3d84a68cab32bf3c3bae69e828ecf4d222db37e791f2c81c0cb8c7a07fb21ff languageName: node linkType: hard -"@aws-sdk/credential-provider-env@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/credential-provider-env@npm:3.535.0" +"@aws-sdk/credential-provider-env@npm:3.568.0": + version: 3.568.0 + resolution: "@aws-sdk/credential-provider-env@npm:3.568.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/property-provider": ^2.2.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: 2d245d723fd3be302a173ac8e93948b7edc9af0f0698b95d8a205dfaa6446cb0fdfcfa1c16ca66f89baf289ba4a77b3bbdc05537d93ee3451715e47ab33b5031 + checksum: 5eead9b30f37ee694a485aba951abc8e65f0a2e7c310f6e85215060daf4275f7a6a7216e86b94327faa7ba47c3457e3279c7aae0e7d34b8db8d2c6686472c543 languageName: node linkType: hard -"@aws-sdk/credential-provider-http@npm:3.552.0": - version: 3.552.0 - resolution: "@aws-sdk/credential-provider-http@npm:3.552.0" +"@aws-sdk/credential-provider-http@npm:3.568.0": + version: 3.568.0 + resolution: "@aws-sdk/credential-provider-http@npm:3.568.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/fetch-http-handler": ^2.5.0 "@smithy/node-http-handler": ^2.5.0 "@smithy/property-provider": ^2.2.0 @@ -460,185 +453,187 @@ __metadata: "@smithy/types": ^2.12.0 "@smithy/util-stream": ^2.2.0 tslib: ^2.6.2 - checksum: 3faf5a149647da222541d6c6da5462cc3caca3c545c2c99a99f7119a5cb7d41699780285cd71bda747feecb81857bab69884d5b32d45384c89f16b3d56822cab + checksum: 24d1e16ac9deb12397d7a5c8d40b8fa975b6908ebc4c0c964003cbcc3db8a8aae21cfb4a954a5d8222ca7cd37faa45caca5ce911b16edd094f1c9761a481af55 languageName: node linkType: hard -"@aws-sdk/credential-provider-ini@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/credential-provider-ini@npm:3.556.0" +"@aws-sdk/credential-provider-ini@npm:3.568.0": + version: 3.568.0 + resolution: "@aws-sdk/credential-provider-ini@npm:3.568.0" dependencies: - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/credential-provider-env": 3.535.0 - "@aws-sdk/credential-provider-process": 3.535.0 - "@aws-sdk/credential-provider-sso": 3.556.0 - "@aws-sdk/credential-provider-web-identity": 3.556.0 - "@aws-sdk/types": 3.535.0 + "@aws-sdk/credential-provider-env": 3.568.0 + "@aws-sdk/credential-provider-process": 3.568.0 + "@aws-sdk/credential-provider-sso": 3.568.0 + "@aws-sdk/credential-provider-web-identity": 3.568.0 + "@aws-sdk/types": 3.567.0 "@smithy/credential-provider-imds": ^2.3.0 "@smithy/property-provider": ^2.2.0 "@smithy/shared-ini-file-loader": ^2.4.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: 173a8ae85920430d45eb398d3516e527155dedb43fcb85ce5b3359149944cceca79941078f9cd8c12eed6e4479f113492bfc1d92e0caceaffdf1e1925e4495eb + peerDependencies: + "@aws-sdk/client-sts": ^3.568.0 + checksum: 10c93720e62fb8b07443329119e5598c71ab3d9acb27b8495d5bd6a7332cb0968dd4395491bd2cf42f4ae78aae676e05cea72cd777b5177247fa35dabde614a6 languageName: node linkType: hard -"@aws-sdk/credential-provider-node@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/credential-provider-node@npm:3.556.0" +"@aws-sdk/credential-provider-node@npm:3.569.0": + version: 3.569.0 + resolution: "@aws-sdk/credential-provider-node@npm:3.569.0" dependencies: - "@aws-sdk/credential-provider-env": 3.535.0 - "@aws-sdk/credential-provider-http": 3.552.0 - "@aws-sdk/credential-provider-ini": 3.556.0 - "@aws-sdk/credential-provider-process": 3.535.0 - "@aws-sdk/credential-provider-sso": 3.556.0 - "@aws-sdk/credential-provider-web-identity": 3.556.0 - "@aws-sdk/types": 3.535.0 + "@aws-sdk/credential-provider-env": 3.568.0 + "@aws-sdk/credential-provider-http": 3.568.0 + "@aws-sdk/credential-provider-ini": 3.568.0 + "@aws-sdk/credential-provider-process": 3.568.0 + "@aws-sdk/credential-provider-sso": 3.568.0 + "@aws-sdk/credential-provider-web-identity": 3.568.0 + "@aws-sdk/types": 3.567.0 "@smithy/credential-provider-imds": ^2.3.0 "@smithy/property-provider": ^2.2.0 "@smithy/shared-ini-file-loader": ^2.4.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: 5faa4684bad86ba20413fa1428c83ac0d4fb3e6747f487997eae6f30f517fe59c7e8465262fa6a7026757657f1afcf8d25658952f97bcd8c2b2b3acf26b3307a + checksum: c26c7f16078f5561625f2e5d62070b41264685190eb62de995b7e64c1c784b3073556f981c87d44732ef4ef06886916155e5c789979157d6c66fa2e4d488a5a1 languageName: node linkType: hard -"@aws-sdk/credential-provider-process@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/credential-provider-process@npm:3.535.0" +"@aws-sdk/credential-provider-process@npm:3.568.0": + version: 3.568.0 + resolution: "@aws-sdk/credential-provider-process@npm:3.568.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/property-provider": ^2.2.0 "@smithy/shared-ini-file-loader": ^2.4.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: 096a78241c0e76c614ee69d2f7e0169d4314e4dd0a43805164faa6d3381d5112587e26066c55e1b7aee763520b04cfaea83ae674eb76580c4fff0f45912de02f + checksum: 7a284fb9693707b523245ec57c401f86c0486a21a5e840edaedd55a3ee86a220941fd81c85a9d22d37f8572b5da6924116ca869a17f797a792c76b364515db92 languageName: node linkType: hard -"@aws-sdk/credential-provider-sso@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/credential-provider-sso@npm:3.556.0" +"@aws-sdk/credential-provider-sso@npm:3.568.0": + version: 3.568.0 + resolution: "@aws-sdk/credential-provider-sso@npm:3.568.0" dependencies: - "@aws-sdk/client-sso": 3.556.0 - "@aws-sdk/token-providers": 3.556.0 - "@aws-sdk/types": 3.535.0 + "@aws-sdk/client-sso": 3.568.0 + "@aws-sdk/token-providers": 3.568.0 + "@aws-sdk/types": 3.567.0 "@smithy/property-provider": ^2.2.0 "@smithy/shared-ini-file-loader": ^2.4.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: cad5d3b23a99b0e4c8d8ab879d90133e7309cd31883b9db38dc3275c726b041ab3e96be77d281aea688c2947e8378a9a79bba6fc25b5d4a364e3b4c64b3ae7ce + checksum: 29ba22700760eb27ab14cfc0d6a362193888c40fe14cf901f5aa44a02a254d85e8fed65b321ab6b09915d2f67a423fbe54848239f9705a76d018a7ca4460e7ba languageName: node linkType: hard -"@aws-sdk/credential-provider-web-identity@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/credential-provider-web-identity@npm:3.556.0" +"@aws-sdk/credential-provider-web-identity@npm:3.568.0": + version: 3.568.0 + resolution: "@aws-sdk/credential-provider-web-identity@npm:3.568.0" dependencies: - "@aws-sdk/client-sts": 3.556.0 - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/property-provider": ^2.2.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: 1e50940eadf63c912cc95559f9c61bd595beb94cb7ee4b57dd436af08bca2e2f172386b4b8195e3b7eff727dfb8743760abeedf792f76daee480ad29f877dcb3 + peerDependencies: + "@aws-sdk/client-sts": ^3.568.0 + checksum: 4d7e539c766875c2c5f73f3664f69d43b5eb5dee8a65419406192446e66932cb89036beca75be01f3d3f9bc613663128c87283b6408791c4652add5055f2f6ab languageName: node linkType: hard -"@aws-sdk/middleware-bucket-endpoint@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.535.0" +"@aws-sdk/middleware-bucket-endpoint@npm:3.568.0": + version: 3.568.0 + resolution: "@aws-sdk/middleware-bucket-endpoint@npm:3.568.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-arn-parser": 3.535.0 + "@aws-sdk/types": 3.567.0 + "@aws-sdk/util-arn-parser": 3.568.0 "@smithy/node-config-provider": ^2.3.0 "@smithy/protocol-http": ^3.3.0 "@smithy/types": ^2.12.0 "@smithy/util-config-provider": ^2.3.0 tslib: ^2.6.2 - checksum: f19ef992d64642ea9cad78906dd58b5ca354f80003ae04c21d1b1357db7e16b05d04c0ac821ac5d0ed09ff80f42acb9165b5a8cd09e43bb99f1c5720de3c30b5 + checksum: 45e4e12a7455ab7e758e87523159ec48b87aa56345e7db66537e591729a162d3d6259e9fc09d986fedddf963718d4fda8ed6463457e5e09af36319c243df9b11 languageName: node linkType: hard -"@aws-sdk/middleware-expect-continue@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-expect-continue@npm:3.535.0" +"@aws-sdk/middleware-expect-continue@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/middleware-expect-continue@npm:3.567.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/protocol-http": ^3.3.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: a2236c5cfa69e557bdcb0eb56282921d9cde8e50f5c3896cc97a15f150565920d88b8be6d16dae8b563001bc4b8afea1e435f71c1b181fe3abda9bba04cfb30f + checksum: 68303e662972653b5a7c0e7e2d4e850e049a3a687094b19e65af35fc2eef3fc17fd01fe4f94922facc24be2bb6191bb2e38dd1a01920f26d31193bac3db49e53 languageName: node linkType: hard -"@aws-sdk/middleware-flexible-checksums@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.535.0" +"@aws-sdk/middleware-flexible-checksums@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/middleware-flexible-checksums@npm:3.567.0" dependencies: "@aws-crypto/crc32": 3.0.0 "@aws-crypto/crc32c": 3.0.0 - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/is-array-buffer": ^2.2.0 "@smithy/protocol-http": ^3.3.0 "@smithy/types": ^2.12.0 "@smithy/util-utf8": ^2.3.0 tslib: ^2.6.2 - checksum: 5e07de340bffc50fb5450f700664d8b3abd6bb399395de962a353734a68a2f88420b9b2a8ebb9286016e71978f0c653ed93875eeb7898f477737f471fc002b3f + checksum: 14cd9c6bc2c1d90b5d5433bc1af22985aa90d8974cfe819e3232641afc522fdeb16149a77b3bcc9d2668b7b8e6fffe13991af93c83b8228494418d96c0da6484 languageName: node linkType: hard -"@aws-sdk/middleware-host-header@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-host-header@npm:3.535.0" +"@aws-sdk/middleware-host-header@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/middleware-host-header@npm:3.567.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/protocol-http": ^3.3.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: 8b26adc069da04c3e6d1f66cb5ebe505373657ba5b85578fc09bd607fb6b25ef4168478f8acacaa69ec3f045ef619f522fafba9844c11835d5933a3f95ade4ea + checksum: ad60e1a02054e7c29e63f9bc2ddc9374dd0d48b282910bd8d3e5ba06bd278b3a2c2d5ede620705e5ccc674641e4738379f6bd402817d2620f09f6949b2c10364 languageName: node linkType: hard -"@aws-sdk/middleware-location-constraint@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-location-constraint@npm:3.535.0" +"@aws-sdk/middleware-location-constraint@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/middleware-location-constraint@npm:3.567.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: de9536d0d4e787f2eb04c2f693c1ac1860a3d519b009bbc73f7dc81c431a5abcde0d5cbdd139ec1969a05fe690ebaf1c2271953f3e8985114b469ef5ee6890e2 + checksum: 7cf51ab39761f3c2e5c57cec92ca427443fc8e48032f55affcd809f6f7379c1092b2c8e83bdca743b240c45c7f4ea1dd613f3c2cc03ad5be865c75c95b04c1c4 languageName: node linkType: hard -"@aws-sdk/middleware-logger@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-logger@npm:3.535.0" +"@aws-sdk/middleware-logger@npm:3.568.0": + version: 3.568.0 + resolution: "@aws-sdk/middleware-logger@npm:3.568.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: f0e01443203c30d8064d5a16968de20060cd4c0742a4eb2537443fe767135c08cda1a2d5a75db33c319b639d31c9340de9f128eefdf73bb50283e40569f68471 + checksum: 9ec1b71afaf1c6bd6c19c9da83cdacc10a4207233bfc896fe2fb634b104075aa4cdb3bd7ad114b70fdc795beca0e4aa05e7e94bcc9cec197faf9291191b5c2f4 languageName: node linkType: hard -"@aws-sdk/middleware-recursion-detection@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/middleware-recursion-detection@npm:3.535.0" +"@aws-sdk/middleware-recursion-detection@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/middleware-recursion-detection@npm:3.567.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/protocol-http": ^3.3.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: 3bbb86ba971d2b034b7dea415fc6c3fb0c1a879c8153841849e9b2bfd9edd5a78e29a299ceaf74829007d96550420246b795721ac7d8cfb244e59e5f9dee54b3 + checksum: d350d8ebb099ceae2d73e520cbe46d43eb4a85f1ac847158e7211a78e150a69313d8914e08569119f4ce88c8d95b3dd870aa6ea62ede0b6c66f7e34effb12f50 languageName: node linkType: hard -"@aws-sdk/middleware-sdk-s3@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/middleware-sdk-s3@npm:3.556.0" +"@aws-sdk/middleware-sdk-s3@npm:3.569.0": + version: 3.569.0 + resolution: "@aws-sdk/middleware-sdk-s3@npm:3.569.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-arn-parser": 3.535.0 + "@aws-sdk/types": 3.567.0 + "@aws-sdk/util-arn-parser": 3.568.0 "@smithy/node-config-provider": ^2.3.0 "@smithy/protocol-http": ^3.3.0 "@smithy/signature-v4": ^2.3.0 @@ -646,186 +641,177 @@ __metadata: "@smithy/types": ^2.12.0 "@smithy/util-config-provider": ^2.3.0 tslib: ^2.6.2 - checksum: 398837daac9a78be96d5364fdd79dbfb679050f06670ba377c1312c4cb6aada63ef21818fd04488c3b61234664d28d4c4272b462af0bdcf84e12c58e3ae0648c + checksum: a92de7459f619a1aea587521d929dec1d34dd30741f8155a34774b2ea5e427078fc596554567c01eeab19e93caad28ae6663ecb99c707ee562d2c679e00d483c languageName: node linkType: hard -"@aws-sdk/middleware-signing@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/middleware-signing@npm:3.556.0" +"@aws-sdk/middleware-signing@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/middleware-signing@npm:3.567.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/property-provider": ^2.2.0 "@smithy/protocol-http": ^3.3.0 "@smithy/signature-v4": ^2.3.0 "@smithy/types": ^2.12.0 "@smithy/util-middleware": ^2.2.0 tslib: ^2.6.2 - checksum: 0fb90db7704f72ca0cc152580b60289194244c849c185bfd27710b02ce8c8ad536d19b2d7d6e1db8c11821164aca6cdfbf132c2dd07ce81c008562b6ec8c7944 + checksum: f69e7b78748ad280a15250e96447cd1ceb2565b53aa4c66acf73e3ce5cd8a6116718f95ec72b7e5865d392f16a4c081d708aa9354f324bc1f9d1e1bdd812b2f7 languageName: node linkType: hard -"@aws-sdk/middleware-ssec@npm:3.537.0": - version: 3.537.0 - resolution: "@aws-sdk/middleware-ssec@npm:3.537.0" +"@aws-sdk/middleware-ssec@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/middleware-ssec@npm:3.567.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: 4c4ed67709d97fd3d614fb00052082ac4697e0c2ad9aafb6794a3bd04ca3a373b0fd06f950be0f4831787410823ea7daca206e631469c819a2e5eae54c268b5a + checksum: b059e3f5d2d2a4dba33c4fbe6914eef195abca5587bef84a088838d3f07cabe39fc48ea25c7bb114b71e71262b9c0843cb613da9c0a41badc42a85f0a090fb4a languageName: node linkType: hard -"@aws-sdk/middleware-user-agent@npm:3.540.0": - version: 3.540.0 - resolution: "@aws-sdk/middleware-user-agent@npm:3.540.0" +"@aws-sdk/middleware-user-agent@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/middleware-user-agent@npm:3.567.0" dependencies: - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-endpoints": 3.540.0 + "@aws-sdk/types": 3.567.0 + "@aws-sdk/util-endpoints": 3.567.0 "@smithy/protocol-http": ^3.3.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: 10a98b243c32db59beb794df62ff9468b1e83d277412698d7a9351fcb8abf5f62630648ee0aaa02eaec9d32f565c78e3c91d4e79836ef9177e7219f623180dd2 + checksum: acc3faae857f6ebfc4ba38dd6a71a5e0394f62e21053155ec71078564a9d67f3b20b9f1411eee5fdbfa355f100a4b002d8f115d353b8547b9a3367828e9f009e languageName: node linkType: hard -"@aws-sdk/region-config-resolver@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/region-config-resolver@npm:3.535.0" +"@aws-sdk/region-config-resolver@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/region-config-resolver@npm:3.567.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/node-config-provider": ^2.3.0 "@smithy/types": ^2.12.0 "@smithy/util-config-provider": ^2.3.0 "@smithy/util-middleware": ^2.2.0 tslib: ^2.6.2 - checksum: 08d76cfc54f2d9fffb8a2fd873e19b95564842b78a2a923260b3100117100054bb95f15f723c1f7268d10ffc61150109dca6b512ac629d125a000550ecfd0146 + checksum: 168dbd91082b572233e8baf62fab7a8e66a6e4c7e9f39ba27e827bca4d0481859d5801f84a3029c7bd9a0669cae9e7b59d20043ed2d980c05eb7ac0eec489b59 languageName: node linkType: hard "@aws-sdk/s3-request-presigner@npm:^3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/s3-request-presigner@npm:3.556.0" + version: 3.569.0 + resolution: "@aws-sdk/s3-request-presigner@npm:3.569.0" dependencies: - "@aws-sdk/signature-v4-multi-region": 3.556.0 - "@aws-sdk/types": 3.535.0 - "@aws-sdk/util-format-url": 3.535.0 + "@aws-sdk/signature-v4-multi-region": 3.569.0 + "@aws-sdk/types": 3.567.0 + "@aws-sdk/util-format-url": 3.567.0 "@smithy/middleware-endpoint": ^2.5.1 "@smithy/protocol-http": ^3.3.0 "@smithy/smithy-client": ^2.5.1 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: b4e6516c2e8a6e1403f5dba54e5cd5bd639475248c443513a4dcde755c22071bba62dcaf7e452cfbb52dd3af5f80b0730b8b04aa5ee82fabf008e008190ec2c2 + checksum: ea886ec14007305e2702cf2377e1212601bd617964546e7649d140fbc730aae6c602190872509e0853610b3dcf0ec7814a1b8a9345cdc0ec5fd79c8a512ab7da languageName: node linkType: hard -"@aws-sdk/signature-v4-multi-region@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/signature-v4-multi-region@npm:3.556.0" +"@aws-sdk/signature-v4-multi-region@npm:3.569.0": + version: 3.569.0 + resolution: "@aws-sdk/signature-v4-multi-region@npm:3.569.0" dependencies: - "@aws-sdk/middleware-sdk-s3": 3.556.0 - "@aws-sdk/types": 3.535.0 + "@aws-sdk/middleware-sdk-s3": 3.569.0 + "@aws-sdk/types": 3.567.0 "@smithy/protocol-http": ^3.3.0 "@smithy/signature-v4": ^2.3.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: d490ea8133725cf9b334ac6a4eb7eef752346117775f364d0abc70a6ba2507725386a3a1d784c75e409d7b83c8650b7dc2306b9f9deb3e087521e2352bb546f9 + checksum: 2df5a8a0a71638a49ab9867c55dd2b5dae2b259cc83181d32bb48513cce4ec659f4cf78a33cfdc5b5954154e8b716f9315af520d97e4a8f937aa5f07d9f5ef85 languageName: node linkType: hard -"@aws-sdk/token-providers@npm:3.556.0": - version: 3.556.0 - resolution: "@aws-sdk/token-providers@npm:3.556.0" +"@aws-sdk/token-providers@npm:3.568.0": + version: 3.568.0 + resolution: "@aws-sdk/token-providers@npm:3.568.0" dependencies: - "@aws-sdk/client-sso-oidc": 3.556.0 - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/property-provider": ^2.2.0 "@smithy/shared-ini-file-loader": ^2.4.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: cb8d6261dd082a536995c17836cb2f4a16a2e39b29bce3f7318e04dc01165f5ec9439d0373fd7af45faf2eb6ba96d3331ed084eebc3b3301be2ac9b18e9957cb + peerDependencies: + "@aws-sdk/client-sso-oidc": ^3.568.0 + checksum: b464d5502a861929d083bef1be24540b4382808bef99670ce124ce7a38cde4da545bf1230caa72a26bd6a0f785b183ba7276bed4759100d999d7f1bfbbbe1544 languageName: node linkType: hard -"@aws-sdk/types@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/types@npm:3.535.0" +"@aws-sdk/types@npm:3.567.0, @aws-sdk/types@npm:^3.222.0": + version: 3.567.0 + resolution: "@aws-sdk/types@npm:3.567.0" dependencies: "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: 1c8ed3a76b508287ee840a9c37f9df7a382459dfe4d46aa0cf90eddacdf32eae9c0e0d274a18956095e567234d0b07c81ff7d4fbeed3ca3c9caf52ccadcea409 + checksum: c034c4895e01f39891f9f2701f69f117f6ad0434f0a49d785ce1e26d43e1f2dae6a56235f0d3cfe0cfc6db23d01700afbf32875470af1ed3a9571b039883b106 languageName: node linkType: hard -"@aws-sdk/types@npm:^3.222.0": - version: 3.398.0 - resolution: "@aws-sdk/types@npm:3.398.0" - dependencies: - "@smithy/types": ^2.2.2 - tslib: ^2.5.0 - checksum: a41a60d64840eb8df11f126c644e4569dc3b0cfab4107751530fdff2af90740ee5ed840bf7cf90c81fb82ddb9d8f309b8ee1d2328a1bc9729c6409f90fa11674 - languageName: node - linkType: hard - -"@aws-sdk/util-arn-parser@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/util-arn-parser@npm:3.535.0" +"@aws-sdk/util-arn-parser@npm:3.568.0": + version: 3.568.0 + resolution: "@aws-sdk/util-arn-parser@npm:3.568.0" dependencies: tslib: ^2.6.2 - checksum: 0061dd01d95187826912903f7a08e5a6d377ce82fcfa91a5a6d1f4343bd51fb32d2cb942612e555f6b85a92e95d55873fce99daef43b2558243efdfe2b27d88a + checksum: 4e6168b86a1ff4509f25b56e473c95bdcc0ecbaedcded29cbbd500eb7c156de63f2426282cd50489ac7f321a990056349974730f9e27ac3fe872ba3573b09fb6 languageName: node linkType: hard -"@aws-sdk/util-endpoints@npm:3.540.0": - version: 3.540.0 - resolution: "@aws-sdk/util-endpoints@npm:3.540.0" +"@aws-sdk/util-endpoints@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/util-endpoints@npm:3.567.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/types": ^2.12.0 "@smithy/util-endpoints": ^1.2.0 tslib: ^2.6.2 - checksum: 9e08e764c22d81af819bb8c1ae975d724debbe4911a69acec34cb10fcc7e5d923eb430d3de0b50ad2f160f75a9839cb39320077f93964c9bd2cf13d2d92f0fc4 + checksum: f3ab9378e4e27e4652d209456e0ba0f72ffa455069c690af14e79cddf344bf122e83ddea8bcabad7d15d1b088125065706438961fcc169fe32885afdb29ab98c languageName: node linkType: hard -"@aws-sdk/util-format-url@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/util-format-url@npm:3.535.0" +"@aws-sdk/util-format-url@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/util-format-url@npm:3.567.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/querystring-builder": ^2.2.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: e54002828bef2f2dcf1f17bc782b7fc87e1298e8084dc465912215c0b909880421b0ae5b57aa9d1e1a55beb7b438437d37e9a213d4fba75605030d10931d5465 + checksum: a4c6748da9e999b3bacd59a1c1c0982b969905d3c8895fd79d8f24bc39844cb98ed4abfdadef069b3e1a0a563ba2db93e928b036afd51242389ed8ed02c4fbd5 languageName: node linkType: hard "@aws-sdk/util-locate-window@npm:^3.0.0": - version: 3.310.0 - resolution: "@aws-sdk/util-locate-window@npm:3.310.0" + version: 3.568.0 + resolution: "@aws-sdk/util-locate-window@npm:3.568.0" dependencies: - tslib: ^2.5.0 - checksum: 9f040d9cb01687317ac9f61d5c9e349aeb506deb114f6259d48949428695e5c4e40b36920091451f74e037b016a6534e43d5a5eb225e18fa45eedb998c87bd6f + tslib: ^2.6.2 + checksum: cb1d0919498206fe266542a635cd05909456a06f007a6a550ff897a01390b239e51c2a50e47509e23c179f8df8001bd5fecd900045da5ec989c3f934c3fd3d56 languageName: node linkType: hard -"@aws-sdk/util-user-agent-browser@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/util-user-agent-browser@npm:3.535.0" +"@aws-sdk/util-user-agent-browser@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/util-user-agent-browser@npm:3.567.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/types": ^2.12.0 bowser: ^2.11.0 tslib: ^2.6.2 - checksum: 347f92df14527a6a30baca22cec326ecae8109cdaa7c011b193275acd4a19e3dfe90194aa91629bb82aa62cf690b2bc2742117f78a8d0fb01570b6eac6cb87a7 + checksum: 4143652ddf90e71c8933d35539174605c69a34d6e19fbe98acbdd9026647ed3bfdb1c79897da2580619c446c26bb0ab26a6b95b514c109db3c704880c9a01520 languageName: node linkType: hard -"@aws-sdk/util-user-agent-node@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/util-user-agent-node@npm:3.535.0" +"@aws-sdk/util-user-agent-node@npm:3.568.0": + version: 3.568.0 + resolution: "@aws-sdk/util-user-agent-node@npm:3.568.0" dependencies: - "@aws-sdk/types": 3.535.0 + "@aws-sdk/types": 3.567.0 "@smithy/node-config-provider": ^2.3.0 "@smithy/types": ^2.12.0 tslib: ^2.6.2 @@ -834,7 +820,7 @@ __metadata: peerDependenciesMeta: aws-crt: optional: true - checksum: 144a92ca5745ed78159d05466698472d10e0529946bcba67cc350be03c2272be7a58c76caa5f8831bbc66438f635a5a10167182aab02be601648843c9c0347f9 + checksum: b5ccc605b75c1e8f73ab29e704fd42c907ade45711b24a7c6303ccab698d1afa0a9ee817b0ea2cd5ffe42b2ac3149f28a6fdd97003158edd3d80e007f2ea2297 languageName: node linkType: hard @@ -847,13 +833,13 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/xml-builder@npm:3.535.0": - version: 3.535.0 - resolution: "@aws-sdk/xml-builder@npm:3.535.0" +"@aws-sdk/xml-builder@npm:3.567.0": + version: 3.567.0 + resolution: "@aws-sdk/xml-builder@npm:3.567.0" dependencies: "@smithy/types": ^2.12.0 tslib: ^2.6.2 - checksum: 8e45d10ef3e19c09c2f19aef1a4d8e6194b257a3a9a6b773e36899e85910006a62d3550fdd658be64df713f49b12402765e5afd4d601bacce11a944ec67f6b65 + checksum: a89998ceb2a4a86808d9ed574141767c84ff251f15a4d194ba0ec3cc825dca17674b1666a3b2adb9ab39eef96ce848f29eefad74a86a6bcb49cc4a37024ca665 languageName: node linkType: hard @@ -884,15 +870,15 @@ __metadata: languageName: node linkType: hard -"@babel/cli@npm:^7.12.10": - version: 7.22.5 - resolution: "@babel/cli@npm:7.22.5" +"@babel/cli@npm:^7.12.10, @babel/cli@npm:^7.14.3, @babel/cli@npm:^7.7.5": + version: 7.24.5 + resolution: "@babel/cli@npm:7.24.5" dependencies: - "@jridgewell/trace-mapping": ^0.3.17 + "@jridgewell/trace-mapping": ^0.3.25 "@nicolo-ribaudo/chokidar-2": 2.1.8-no-fsevents.3 chokidar: ^3.4.0 commander: ^4.0.1 - convert-source-map: ^1.1.0 + convert-source-map: ^2.0.0 fs-readdir-recursive: ^1.1.0 glob: ^7.2.0 make-dir: ^2.1.0 @@ -907,34 +893,7 @@ __metadata: bin: babel: ./bin/babel.js babel-external-helpers: ./bin/babel-external-helpers.js - checksum: 3c3362ed4acb0d8bbaa3ca86a4b13486c22df3f92c036e2d9e1972a4622c6de602036b8693811284c693e46900a432a8e3e92111e78ce10af9fd197fca154283 - languageName: node - linkType: hard - -"@babel/cli@npm:^7.14.3, @babel/cli@npm:^7.7.5": - version: 7.18.6 - resolution: "@babel/cli@npm:7.18.6" - dependencies: - "@jridgewell/trace-mapping": ^0.3.8 - "@nicolo-ribaudo/chokidar-2": 2.1.8-no-fsevents.3 - chokidar: ^3.4.0 - commander: ^4.0.1 - convert-source-map: ^1.1.0 - fs-readdir-recursive: ^1.1.0 - glob: ^7.0.0 - make-dir: ^2.1.0 - slash: ^2.0.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - dependenciesMeta: - "@nicolo-ribaudo/chokidar-2": - optional: true - chokidar: - optional: true - bin: - babel: ./bin/babel.js - babel-external-helpers: ./bin/babel-external-helpers.js - checksum: d9db59862c482a6013ecb89140d337a72b75d1221674cf7276c4a614dac24126f879c8561433c76f73c2683e03db5d5e83d6d0c042ad7a102985f96cc9b99bc3 + checksum: ec1c0546986b1b2423a125f919701b1c29ea1e999302035379adbfb9104e819d9cecc9d947ac91a26a9da7e6445f1812fc61deabf9d0a5f3894f53ec19fdfa04 languageName: node linkType: hard @@ -947,36 +906,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.5, @babel/code-frame@npm:^7.5.5, @babel/code-frame@npm:^7.8.3": - version: 7.22.5 - resolution: "@babel/code-frame@npm:7.22.5" - dependencies: - "@babel/highlight": ^7.22.5 - checksum: 0b6c5eaf9e58be7140ac790b7bdf8148e8a24e26502dcaa50f157259c083b0584285748fd90d342ae311a5bb1eaad7835aec625296d2b46853464f9bd8991e28 - languageName: node - linkType: hard - -"@babel/code-frame@npm:^7.22.13": - version: 7.22.13 - resolution: "@babel/code-frame@npm:7.22.13" - dependencies: - "@babel/highlight": ^7.22.13 - chalk: ^2.4.2 - checksum: f4cc8ae1000265677daf4845083b72f88d00d311adb1a93c94eb4b07bf0ed6828a81ae4ac43ee7d476775000b93a28a9cddec18fbdc5796212d8dcccd5de72bd - languageName: node - linkType: hard - -"@babel/code-frame@npm:^7.23.5": - version: 7.23.5 - resolution: "@babel/code-frame@npm:7.23.5" - dependencies: - "@babel/highlight": ^7.23.4 - chalk: ^2.4.2 - checksum: a10e843595ddd9f97faa99917414813c06214f4d9205294013e20c70fbdf4f943760da37dec1d998bf3e6fc20fa2918a47c0e987a7e458663feb7698063ad7c6 - languageName: node - linkType: hard - -"@babel/code-frame@npm:^7.24.2": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.24.2": version: 7.24.2 resolution: "@babel/code-frame@npm:7.24.2" dependencies: @@ -986,58 +916,13 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.11.0": +"@babel/compat-data@npm:^7.11.0, @babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.5, @babel/compat-data@npm:^7.24.4": version: 7.24.4 resolution: "@babel/compat-data@npm:7.24.4" checksum: 9cd8a9cd28a5ca6db5d0e27417d609f95a8762b655e8c9c97fd2de08997043ae99f0139007083c5e607601c6122e8432c85fe391731b19bf26ad458fa0c60dd3 languageName: node linkType: hard -"@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/compat-data@npm:7.22.5" - checksum: 97f3c24a71b4e7d5f91c5807f6206a9cdb4123e595c51b34a19e9ea22b837003f969f732fde8819928d66e7b64047fd736c6717c8a1b96bf27fbfc30f6834aff - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9, @babel/compat-data@npm:^7.23.2": - version: 7.23.2 - resolution: "@babel/compat-data@npm:7.23.2" - checksum: 0397a08c3e491696cc1b12cf0879bf95fc550bfc6ef524d5a9452981aa0e192a958b2246debfb230fa22718fac473cc5a36616f89b1ad6e7e52055732cd374a1 - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.23.5": - version: 7.23.5 - resolution: "@babel/compat-data@npm:7.23.5" - checksum: 081278ed46131a890ad566a59c61600a5f9557bd8ee5e535890c8548192532ea92590742fd74bd9db83d74c669ef8a04a7e1c85cdea27f960233e3b83c3a957c - languageName: node - linkType: hard - -"@babel/core@npm:7.12.9": - version: 7.12.9 - resolution: "@babel/core@npm:7.12.9" - dependencies: - "@babel/code-frame": ^7.10.4 - "@babel/generator": ^7.12.5 - "@babel/helper-module-transforms": ^7.12.1 - "@babel/helpers": ^7.12.5 - "@babel/parser": ^7.12.7 - "@babel/template": ^7.12.7 - "@babel/traverse": ^7.12.9 - "@babel/types": ^7.12.7 - convert-source-map: ^1.7.0 - debug: ^4.1.0 - gensync: ^1.0.0-beta.1 - json5: ^2.1.2 - lodash: ^4.17.19 - resolve: ^1.3.2 - semver: ^5.4.1 - source-map: ^0.5.0 - checksum: c11d26f5a33a29c94fdd1c492dfd723f48926c51e975448dda57c081c0d74c7b03298642b2651559e0d330ec868b5757b60f9648c71cf7f89fddf79a17cf006f - languageName: node - linkType: hard - "@babel/core@npm:7.14.3": version: 7.14.3 resolution: "@babel/core@npm:7.14.3" @@ -1061,102 +946,44 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.1.0, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.10, @babel/core@npm:^7.12.3, @babel/core@npm:^7.12.7, @babel/core@npm:^7.14.3, @babel/core@npm:^7.16.0, @babel/core@npm:^7.21.3, @babel/core@npm:^7.7.2, @babel/core@npm:^7.7.5, @babel/core@npm:^7.8.0": - version: 7.22.5 - resolution: "@babel/core@npm:7.22.5" +"@babel/core@npm:^7.1.0, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.10, @babel/core@npm:^7.12.3, @babel/core@npm:^7.12.7, @babel/core@npm:^7.14.3, @babel/core@npm:^7.18.9, @babel/core@npm:^7.20.12, @babel/core@npm:^7.21.3, @babel/core@npm:^7.23.0, @babel/core@npm:^7.23.2, @babel/core@npm:^7.23.5, @babel/core@npm:^7.23.9, @babel/core@npm:^7.7.2, @babel/core@npm:^7.7.5, @babel/core@npm:^7.8.0": + version: 7.24.5 + resolution: "@babel/core@npm:7.24.5" dependencies: "@ampproject/remapping": ^2.2.0 - "@babel/code-frame": ^7.22.5 - "@babel/generator": ^7.22.5 - "@babel/helper-compilation-targets": ^7.22.5 - "@babel/helper-module-transforms": ^7.22.5 - "@babel/helpers": ^7.22.5 - "@babel/parser": ^7.22.5 - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.5 - "@babel/types": ^7.22.5 - convert-source-map: ^1.7.0 - debug: ^4.1.0 - gensync: ^1.0.0-beta.2 - json5: ^2.2.2 - semver: ^6.3.0 - checksum: c00e1474a41c18b669511dd1a1bd757d854cc8128218421a73c3b1c76b44fb22a57bbbd29a73b7a156cb1460af7a94602f81bed76b8d78c6ffae4de954b32a50 - languageName: node - linkType: hard - -"@babel/core@npm:^7.13.16, @babel/core@npm:^7.18.9, @babel/core@npm:^7.20.12, @babel/core@npm:^7.22.20, @babel/core@npm:^7.22.9": - version: 7.23.2 - resolution: "@babel/core@npm:7.23.2" - dependencies: - "@ampproject/remapping": ^2.2.0 - "@babel/code-frame": ^7.22.13 - "@babel/generator": ^7.23.0 - "@babel/helper-compilation-targets": ^7.22.15 - "@babel/helper-module-transforms": ^7.23.0 - "@babel/helpers": ^7.23.2 - "@babel/parser": ^7.23.0 - "@babel/template": ^7.22.15 - "@babel/traverse": ^7.23.2 - "@babel/types": ^7.23.0 - convert-source-map: ^2.0.0 - debug: ^4.1.0 - gensync: ^1.0.0-beta.2 - json5: ^2.2.3 - semver: ^6.3.1 - checksum: 14ad6e0a3ac0085dc008e7fb0c8513f0a3e39f2ab883a964a89ef1311338d49cf085c94cb6165c07fdec0fdcc6e865ce4811253c479f9f45ac375226dfe3ad3b - languageName: node - linkType: hard - -"@babel/core@npm:^7.23.5": - version: 7.23.7 - resolution: "@babel/core@npm:7.23.7" - dependencies: - "@ampproject/remapping": ^2.2.0 - "@babel/code-frame": ^7.23.5 - "@babel/generator": ^7.23.6 + "@babel/code-frame": ^7.24.2 + "@babel/generator": ^7.24.5 "@babel/helper-compilation-targets": ^7.23.6 - "@babel/helper-module-transforms": ^7.23.3 - "@babel/helpers": ^7.23.7 - "@babel/parser": ^7.23.6 - "@babel/template": ^7.22.15 - "@babel/traverse": ^7.23.7 - "@babel/types": ^7.23.6 + "@babel/helper-module-transforms": ^7.24.5 + "@babel/helpers": ^7.24.5 + "@babel/parser": ^7.24.5 + "@babel/template": ^7.24.0 + "@babel/traverse": ^7.24.5 + "@babel/types": ^7.24.5 convert-source-map: ^2.0.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 json5: ^2.2.3 semver: ^6.3.1 - checksum: 38c9934973d384ed83369712978453eac91dc3f22167404dbdb272b64f602e74728a6f37012c53ee57e521b8ae2da60097f050497d9b6a212d28b59cdfb2cd1d + checksum: e26ba810a77bc8e21579a12fc36c79a0a60554404dc9447f2d64eb1f26d181c48d3b97d39d9f158e9911ec7162a8280acfaf2b4b210e975f0dd4bd4dbb1ee159 languageName: node linkType: hard "@babel/eslint-parser@npm:^7.15.8": - version: 7.22.5 - resolution: "@babel/eslint-parser@npm:7.22.5" + version: 7.24.5 + resolution: "@babel/eslint-parser@npm:7.24.5" dependencies: "@nicolo-ribaudo/eslint-scope-5-internals": 5.1.1-v1 eslint-visitor-keys: ^2.1.0 - semver: ^6.3.0 + semver: ^6.3.1 peerDependencies: - "@babel/core": ">=7.11.0" - eslint: ^7.5.0 || ^8.0.0 - checksum: 070de521c139f53b9cb10a94c9089834aba887ebfac136fc890bafc8e43effc6042e4161d8f379441f65db1042d04126b557403dad551912a94c717d14eafd74 + "@babel/core": ^7.11.0 + eslint: ^7.5.0 || ^8.0.0 || ^9.0.0 + checksum: bf8e89a00bd0895962c8c592b3f81a21186a9002bbbc57b0d6d9a72a8aeb087858222842f094479dd96f1783a5a1744ba9f1e907fdba60aa92f4775275550097 languageName: node linkType: hard -"@babel/generator@npm:^7.12.11, @babel/generator@npm:^7.12.5, @babel/generator@npm:^7.22.5, @babel/generator@npm:^7.7.2": - version: 7.22.5 - resolution: "@babel/generator@npm:7.22.5" - dependencies: - "@babel/types": ^7.22.5 - "@jridgewell/gen-mapping": ^0.3.2 - "@jridgewell/trace-mapping": ^0.3.17 - jsesc: ^2.5.1 - checksum: 0613eddb4d1f7d82d88ad304e1acf48fddc3cdfb4c94bc3d2a9128cf0cdeedc0aa8d60301715c3b67537c00d9c9c9d50aad4339e7af1295c90def21893b17f7f - languageName: node - linkType: hard - -"@babel/generator@npm:^7.14.3, @babel/generator@npm:^7.24.5": +"@babel/generator@npm:^7.14.3, @babel/generator@npm:^7.23.0, @babel/generator@npm:^7.23.5, @babel/generator@npm:^7.24.5, @babel/generator@npm:^7.7.2": version: 7.24.5 resolution: "@babel/generator@npm:7.24.5" dependencies: @@ -1168,31 +995,7 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.22.9, @babel/generator@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/generator@npm:7.23.0" - dependencies: - "@babel/types": ^7.23.0 - "@jridgewell/gen-mapping": ^0.3.2 - "@jridgewell/trace-mapping": ^0.3.17 - jsesc: ^2.5.1 - checksum: b7d8727c574119b5ef06e5d5d0d8d939527d51537db4b08273caebb18f3f2b1d4517b874776085e161fd47d28f26b22c08e7f270b64f43b2afd4a60c5936d6cd - languageName: node - linkType: hard - -"@babel/generator@npm:^7.23.5, @babel/generator@npm:^7.23.6": - version: 7.23.6 - resolution: "@babel/generator@npm:7.23.6" - dependencies: - "@babel/types": ^7.23.6 - "@jridgewell/gen-mapping": ^0.3.2 - "@jridgewell/trace-mapping": ^0.3.17 - jsesc: ^2.5.1 - checksum: 53540e905cd10db05d9aee0a5304e36927f455ce66f95d1253bb8a179f286b88fa7062ea0db354c566fe27f8bb96567566084ffd259f8feaae1de5eccc8afbda - languageName: node - linkType: hard - -"@babel/helper-annotate-as-pure@npm:^7.18.6, @babel/helper-annotate-as-pure@npm:^7.22.5": +"@babel/helper-annotate-as-pure@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" dependencies: @@ -1210,16 +1013,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.5" - dependencies: - "@babel/types": ^7.22.5 - checksum: 73a61a56364849770d5569264ba0a5f06035387cafd219d1ae26077f80a1dfb75f240e6abcd991c655641ad8fe066b964261942b4086ba2efc946c807c9d1698 - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.10.4, @babel/helper-compilation-targets@npm:^7.13.16, @babel/helper-compilation-targets@npm:^7.23.6": +"@babel/helper-compilation-targets@npm:^7.10.4, @babel/helper-compilation-targets@npm:^7.13.16, @babel/helper-compilation-targets@npm:^7.20.7, @babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.23.6": version: 7.23.6 resolution: "@babel/helper-compilation-targets@npm:7.23.6" dependencies: @@ -1232,73 +1026,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.13.0, @babel/helper-compilation-targets@npm:^7.17.7, @babel/helper-compilation-targets@npm:^7.20.7, @babel/helper-compilation-targets@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-compilation-targets@npm:7.22.5" - dependencies: - "@babel/compat-data": ^7.22.5 - "@babel/helper-validator-option": ^7.22.5 - browserslist: ^4.21.3 - lru-cache: ^5.1.1 - semver: ^6.3.0 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: f36a2f27d970fa61b32090840ec847f73c6ada50becf7222c8778dd7ae07661c56f83d57e4c18437160e221512f91c442e3b86703741b45fc1277a548a6fd819 - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.22.15, @babel/helper-compilation-targets@npm:^7.22.6": - version: 7.22.15 - resolution: "@babel/helper-compilation-targets@npm:7.22.15" - dependencies: - "@babel/compat-data": ^7.22.9 - "@babel/helper-validator-option": ^7.22.15 - browserslist: ^4.21.9 - lru-cache: ^5.1.1 - semver: ^6.3.1 - checksum: 45b9286861296e890f674a3abb199efea14a962a27d9b8adeb44970a9fd5c54e73a9e342e8414d2851cf4f98d5994537352fbce7b05ade32e9849bbd327f9ff1 - languageName: node - linkType: hard - -"@babel/helper-create-class-features-plugin@npm:^7.12.1, @babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0, @babel/helper-create-class-features-plugin@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-create-class-features-plugin@npm:7.22.5" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-function-name": ^7.22.5 - "@babel/helper-member-expression-to-functions": ^7.22.5 - "@babel/helper-optimise-call-expression": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.5 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.5 - semver: ^6.3.0 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: a7a98b73dde9c7b0820f5b56e2b8f4cdeaf1a23ec9ab5bb642a9b6cc7c24154e84d20f6de49761dbc34dc84a4797a87db328e8f4b86867bff004a5809fe9e3d5 - languageName: node - linkType: hard - -"@babel/helper-create-class-features-plugin@npm:^7.22.11": - version: 7.22.15 - resolution: "@babel/helper-create-class-features-plugin@npm:7.22.15" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-function-name": ^7.22.5 - "@babel/helper-member-expression-to-functions": ^7.22.15 - "@babel/helper-optimise-call-expression": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.9 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - semver: ^6.3.1 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 2ae5759fe8845fda99b34f2ba6cd0794fc860213d14c93a87aa9180960252bce621157a79c373b7fbb423b25a55fb0e20eae0d5f8e4ad5ef22dc70e7c2af3805 - languageName: node - linkType: hard - -"@babel/helper-create-class-features-plugin@npm:^7.24.5": +"@babel/helper-create-class-features-plugin@npm:^7.12.1, @babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.24.1, @babel/helper-create-class-features-plugin@npm:^7.24.4, @babel/helper-create-class-features-plugin@npm:^7.24.5": version: 7.24.5 resolution: "@babel/helper-create-class-features-plugin@npm:7.24.5" dependencies: @@ -1317,20 +1045,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.5" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - regexpu-core: ^5.3.1 - semver: ^6.3.0 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 134e019881cd985bf329648c2885eee31298e2ef0610ed3ba36dca8dc3a5d17851c61d890acb7904bf72a755182bdca39861079729ca71940f0149ed589c9f85 - languageName: node - linkType: hard - -"@babel/helper-create-regexp-features-plugin@npm:^7.22.15": +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.22.15, @babel/helper-create-regexp-features-plugin@npm:^7.22.5": version: 7.22.15 resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.15" dependencies: @@ -1343,43 +1058,9 @@ __metadata: languageName: node linkType: hard -"@babel/helper-define-polyfill-provider@npm:^0.1.5": - version: 0.1.5 - resolution: "@babel/helper-define-polyfill-provider@npm:0.1.5" - dependencies: - "@babel/helper-compilation-targets": ^7.13.0 - "@babel/helper-module-imports": ^7.12.13 - "@babel/helper-plugin-utils": ^7.13.0 - "@babel/traverse": ^7.13.0 - debug: ^4.1.1 - lodash.debounce: ^4.0.8 - resolve: ^1.14.2 - semver: ^6.1.2 - peerDependencies: - "@babel/core": ^7.4.0-0 - checksum: b83aa728cc2fd4882a82ce67c300407024a05adc3f88c461a02438b2ab50c66e711f8ba36ef622637eb7af4d40aaafa0d70e77e0da9adc5710f190a686082f94 - languageName: node - linkType: hard - -"@babel/helper-define-polyfill-provider@npm:^0.4.0": - version: 0.4.0 - resolution: "@babel/helper-define-polyfill-provider@npm:0.4.0" - dependencies: - "@babel/helper-compilation-targets": ^7.17.7 - "@babel/helper-plugin-utils": ^7.16.7 - debug: ^4.1.1 - lodash.debounce: ^4.0.8 - resolve: ^1.14.2 - semver: ^6.1.2 - peerDependencies: - "@babel/core": ^7.4.0-0 - checksum: 953c6ebda6871f2aa093f002f5e085ecbefe684580543fc7c309fe9aa5ce626758e02697a51cd25acf5cab56b1028a789fd38674d5872de74927a58049fbdc19 - languageName: node - linkType: hard - -"@babel/helper-define-polyfill-provider@npm:^0.4.3": - version: 0.4.3 - resolution: "@babel/helper-define-polyfill-provider@npm:0.4.3" +"@babel/helper-define-polyfill-provider@npm:^0.6.1, @babel/helper-define-polyfill-provider@npm:^0.6.2": + version: 0.6.2 + resolution: "@babel/helper-define-polyfill-provider@npm:0.6.2" dependencies: "@babel/helper-compilation-targets": ^7.22.6 "@babel/helper-plugin-utils": ^7.22.5 @@ -1388,7 +1069,7 @@ __metadata: resolve: ^1.14.2 peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 0007035157e0d32ee9cb4ca319b89d6f3705523383efe52a59eb3d4dfa2ed08c5147e49c10a6e6d69c15221d89c76c8e5875475d6710fb44a5c37b8e69388e40 + checksum: f777fe0ee1e467fdaaac059c39ed203bdc94ef2465fb873316e9e1acfc511a276263724b061e3b0af2f6d7ad3ff174f2bb368fde236a860e0f650fda43d7e022 languageName: node linkType: hard @@ -1399,23 +1080,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-environment-visitor@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-environment-visitor@npm:7.22.5" - checksum: c9377464c1839741a0a77bbad56de94c896f4313eb034c988fc2ab01293e7c4027244c93b4256606c5f4e34c68cf599a7d31a548d537577c7da836bbca40551b - languageName: node - linkType: hard - -"@babel/helper-function-name@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-function-name@npm:7.22.5" - dependencies: - "@babel/template": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: 3ce2e87967fe54aa463d279150ddda0dae3b5bc3f8c2773b90670b553b61e8fe62da7edcd7b1e1891c5b25af4924a6700dad2e9d8249b910a5bf7caa2eaf4c13 - languageName: node - linkType: hard - "@babel/helper-function-name@npm:^7.23.0": version: 7.23.0 resolution: "@babel/helper-function-name@npm:7.23.0" @@ -1435,24 +1099,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.22.15": - version: 7.23.0 - resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0" - dependencies: - "@babel/types": ^7.23.0 - checksum: b810daddf093ffd0802f1429052349ed9ea08ef7d0c56da34ffbcdecbdafac86f95bdea2fe30e0e0e629febc7dd41b56cb5eacc10d1a44336d37b755dac31fa4 - languageName: node - linkType: hard - -"@babel/helper-member-expression-to-functions@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-member-expression-to-functions@npm:7.22.5" - dependencies: - "@babel/types": ^7.22.5 - checksum: c04a71976b2508c6f1fa46562439b74970cea37958e450bcd59363b9c62ac49fb8e3cef544b08264b1d710b3f36214486cb7e1102e4f1ee8e1c2878b5eebcc75 - languageName: node - linkType: hard - "@babel/helper-member-expression-to-functions@npm:^7.23.0, @babel/helper-member-expression-to-functions@npm:^7.24.5": version: 7.24.5 resolution: "@babel/helper-member-expression-to-functions@npm:7.24.5" @@ -1462,25 +1108,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.12.13, @babel/helper-module-imports@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-module-imports@npm:7.22.5" - dependencies: - "@babel/types": ^7.22.5 - checksum: 04f8c0586c485c33017c63e0fc5fc16bd33b883cef3c88e4b3a8bf7bc807b3f9a7bcb9372fbcc01c0a539a5d1cdb477e7bdec77e250669edab00f796683b6b07 - languageName: node - linkType: hard - -"@babel/helper-module-imports@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/helper-module-imports@npm:7.22.15" - dependencies: - "@babel/types": ^7.22.15 - checksum: 4e0d7fc36d02c1b8c8b3006dfbfeedf7a367d3334a04934255de5128115ea0bafdeb3e5736a2559917f0653e4e437400d54542da0468e08d3cbc86d3bbfa8f30 - languageName: node - linkType: hard - -"@babel/helper-module-imports@npm:^7.24.1, @babel/helper-module-imports@npm:^7.24.3": +"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.22.15, @babel/helper-module-imports@npm:^7.24.1, @babel/helper-module-imports@npm:^7.24.3": version: 7.24.3 resolution: "@babel/helper-module-imports@npm:7.24.3" dependencies: @@ -1489,23 +1117,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.12.1, @babel/helper-module-transforms@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-module-transforms@npm:7.22.5" - dependencies: - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-module-imports": ^7.22.5 - "@babel/helper-simple-access": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.5 - "@babel/helper-validator-identifier": ^7.22.5 - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: a28cf9a91ed657392f75ada08d96a46e8d0df420b7d5d1ac0bb1633d1404807d0cb6e6a3b0666c747d30f378fbb34985d30c6f25e2fcdd69dc58656e47aafe92 - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.14.2": +"@babel/helper-module-transforms@npm:^7.14.2, @babel/helper-module-transforms@npm:^7.23.3, @babel/helper-module-transforms@npm:^7.24.5": version: 7.24.5 resolution: "@babel/helper-module-transforms@npm:7.24.5" dependencies: @@ -1520,36 +1132,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/helper-module-transforms@npm:7.23.0" - dependencies: - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-module-imports": ^7.22.15 - "@babel/helper-simple-access": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/helper-validator-identifier": ^7.22.20 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 15a52e401bd17fe44ba9be51cca693a3e182dc93264dc28ede732081c43211741df81ce8eb15e82e81c8ad51beb8893301ecc31d5c77add0f7be78dff6815318 - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/helper-module-transforms@npm:7.23.3" - dependencies: - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-module-imports": ^7.22.15 - "@babel/helper-simple-access": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/helper-validator-identifier": ^7.22.20 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 211e1399d0c4993671e8e5c2b25383f08bee40004ace5404ed4065f0e9258cc85d99c1b82fd456c030ce5cfd4d8f310355b54ef35de9924eabfc3dff1331d946 - languageName: node - linkType: hard - "@babel/helper-optimise-call-expression@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" @@ -1559,21 +1141,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:7.10.4": - version: 7.10.4 - resolution: "@babel/helper-plugin-utils@npm:7.10.4" - checksum: 113d0405281f5490658f7c1c3a81b4a37927375e1ebcccd2fd90be538a102da0c2d6024561aaf26bd1c71ef7688b5a8b96a87d938db8d9774454ab635011fc7f - languageName: node - linkType: hard - -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.13.0, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.16.7, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": - version: 7.22.5 - resolution: "@babel/helper-plugin-utils@npm:7.22.5" - checksum: d2c4bfe2fa91058bcdee4f4e57a3f4933aed7af843acfd169cd6179fab8d13c1d636474ecabb2af107dc77462c7e893199aa26632bac1c6d7e025a17cbb9d20d - languageName: node - linkType: hard - -"@babel/helper-plugin-utils@npm:^7.18.9, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.24.5": +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.18.9, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.24.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": version: 7.24.5 resolution: "@babel/helper-plugin-utils@npm:7.24.5" checksum: 4ae40094e6a2f183281213344f4df60c66b16b19a2bc38d2bb11810a6dc0a0e7ec638957d0e433ff8b615775b8f3cd1b7edbf59440d1b50e73c389fc22913377 @@ -1593,47 +1161,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-remap-async-to-generator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-remap-async-to-generator@npm:7.22.5" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-wrap-function": ^7.22.5 - "@babel/types": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: a4ec78db69db61dbc65eb5b07c8ab4e836caf89a3a8b2983c2afcde805c11f5c660e0932739315d9f08d7ac442360822227ce9f9fdd9436993d342de9a043cf5 - languageName: node - linkType: hard - -"@babel/helper-replace-supers@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-replace-supers@npm:7.22.5" - dependencies: - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-member-expression-to-functions": ^7.22.5 - "@babel/helper-optimise-call-expression": ^7.22.5 - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: 0590aa037340e069de866f313eca7d7f0031bd95b56e5182bef79c05a97e763a6098fa4ab77fed8e3798e832bb6a3230bea438e669bc4d90112f09e841bff064 - languageName: node - linkType: hard - -"@babel/helper-replace-supers@npm:^7.22.9": - version: 7.22.20 - resolution: "@babel/helper-replace-supers@npm:7.22.20" - dependencies: - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-member-expression-to-functions": ^7.22.15 - "@babel/helper-optimise-call-expression": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 6b0858811ad46873817c90c805015d63300e003c5a85c147a17d9845fa2558a02047c3cc1f07767af59014b2dd0fa75b503e5bc36e917f360e9b67bb6f1e79f4 - languageName: node - linkType: hard - "@babel/helper-replace-supers@npm:^7.24.1": version: 7.24.1 resolution: "@babel/helper-replace-supers@npm:7.24.1" @@ -1647,16 +1174,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-simple-access@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-simple-access@npm:7.22.5" - dependencies: - "@babel/types": ^7.22.5 - checksum: f0cf81a30ba3d09a625fd50e5a9069e575c5b6719234e04ee74247057f8104beca89ed03e9217b6e9b0493434cedc18c5ecca4cea6244990836f1f893e140369 - languageName: node - linkType: hard - -"@babel/helper-simple-access@npm:^7.24.5": +"@babel/helper-simple-access@npm:^7.22.5, @babel/helper-simple-access@npm:^7.24.5": version: 7.24.5 resolution: "@babel/helper-simple-access@npm:7.24.5" dependencies: @@ -1674,25 +1192,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-split-export-declaration@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-split-export-declaration@npm:7.22.5" - dependencies: - "@babel/types": ^7.22.5 - checksum: a1e463086f97778584c44129c5c37282d033bf97867b300ff42e64279df18d41fe0e56ebe6a1b27f907afa66ad2a313558db8d2e83e73384c5b22ac726c9c52a - languageName: node - linkType: hard - -"@babel/helper-split-export-declaration@npm:^7.22.6": - version: 7.22.6 - resolution: "@babel/helper-split-export-declaration@npm:7.22.6" - dependencies: - "@babel/types": ^7.22.5 - checksum: d83e4b623eaa9622c267d3c83583b72f3aac567dc393dda18e559d79187961cb29ae9c57b2664137fc3d19508370b12ec6a81d28af73a50e0846819cb21c6e44 - languageName: node - linkType: hard - -"@babel/helper-split-export-declaration@npm:^7.24.5": +"@babel/helper-split-export-declaration@npm:^7.22.6, @babel/helper-split-export-declaration@npm:^7.24.5": version: 7.24.5 resolution: "@babel/helper-split-export-declaration@npm:7.24.5" dependencies: @@ -1701,42 +1201,14 @@ __metadata: languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-string-parser@npm:7.22.5" - checksum: 6b0ff8af724377ec41e5587fffa7605198da74cb8e7d8d48a36826df0c0ba210eb9fedb3d9bef4d541156e0bd11040f021945a6cbb731ccec4aefb4affa17aa4 - languageName: node - linkType: hard - -"@babel/helper-string-parser@npm:^7.23.4": - version: 7.23.4 - resolution: "@babel/helper-string-parser@npm:7.23.4" - checksum: f348d5637ad70b6b54b026d6544bd9040f78d24e7ec245a0fc42293968181f6ae9879c22d89744730d246ce8ec53588f716f102addd4df8bbc79b73ea10004ac - languageName: node - linkType: hard - -"@babel/helper-string-parser@npm:^7.24.1": +"@babel/helper-string-parser@npm:^7.22.5, @babel/helper-string-parser@npm:^7.24.1": version: 7.24.1 resolution: "@babel/helper-string-parser@npm:7.24.1" checksum: 2f9bfcf8d2f9f083785df0501dbab92770111ece2f90d120352fda6dd2a7d47db11b807d111e6f32aa1ba6d763fe2dc6603d153068d672a5d0ad33ca802632b2 languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-validator-identifier@npm:7.22.20" - checksum: dcad63db345fb110e032de46c3688384b0008a42a4845180ce7cd62b1a9c0507a1bed727c4d1060ed1a03ae57b4d918570259f81724aaac1a5b776056f37504e - languageName: node - linkType: hard - -"@babel/helper-validator-identifier@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-validator-identifier@npm:7.22.5" - checksum: 2ff1d3833154d17ccf773b8a71fdc0cd0e7356aa8033179d0e3133787dfb33d97796cbff8b92a97c56268205337dfc720227aeddc677c1bc08ae1b67a95252d7 - languageName: node - linkType: hard - -"@babel/helper-validator-identifier@npm:^7.24.5": +"@babel/helper-validator-identifier@npm:^7.22.20, @babel/helper-validator-identifier@npm:^7.22.5, @babel/helper-validator-identifier@npm:^7.24.5": version: 7.24.5 resolution: "@babel/helper-validator-identifier@npm:7.24.5" checksum: 05f957229d89ce95a137d04e27f7d0680d84ae48b6ad830e399db0779341f7d30290f863a93351b4b3bde2166737f73a286ea42856bb07c8ddaa95600d38645c @@ -1750,55 +1222,18 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/helper-validator-option@npm:7.22.15" - checksum: e9661bf80ba18e2dd978217b350fb07298e57ac417f4f1ab9fa011505e20e4857f2c3b4b538473516a9dc03af5ce3a831e5ed973311c28326f4c330b6be981c2 - languageName: node - linkType: hard - -"@babel/helper-validator-option@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-validator-option@npm:7.22.5" - checksum: 23e310bf1b90d085b1ae250f31d423fb6cc004da882f0d3409266e5e4c7fd41ed0a172283a6a9a16083c5f2e11f987b32c815c80c60d9a948e23dd6dcf2e0437 - languageName: node - linkType: hard - "@babel/helper-wrap-function@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-wrap-function@npm:7.22.20" + version: 7.24.5 + resolution: "@babel/helper-wrap-function@npm:7.24.5" dependencies: - "@babel/helper-function-name": ^7.22.5 - "@babel/template": ^7.22.15 - "@babel/types": ^7.22.19 - checksum: 97b5f42ff4d305318ff2f99a5f59d3e97feff478333b2d893c4f85456d3c66372070f71d7bf9141f598c8cf2741c49a15918193633c427a88d170d98eb8c46eb + "@babel/helper-function-name": ^7.23.0 + "@babel/template": ^7.24.0 + "@babel/types": ^7.24.5 + checksum: 242fcd32d59d26463fd8d989707b88691deec871ac2bf15e03ab2f1b185d1d4f3db2c6a8dd3c10c89d4ff63da238df1c4d318cfc3dcd8e1c1fabdcf27f28d858 languageName: node linkType: hard -"@babel/helper-wrap-function@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-wrap-function@npm:7.22.5" - dependencies: - "@babel/helper-function-name": ^7.22.5 - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: 34aa811cc433a3fe2d1bcb7c703ad57c523fd9cad5df8da0651175569cb63dc95b1557305735d922d94a4420e11b2a87d65dbe7f14b49b69e2c7a9c0fdea5647 - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.12.5, @babel/helpers@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helpers@npm:7.22.5" - dependencies: - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: efa2d0fc2107e270782a784af3a52e5e0b97187b7b34feeeeb00454bc322e802ff4007b22410c387c05580c793f517c4bafc8a6a3acfdb0e3a1b349728f270c4 - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.14.0": +"@babel/helpers@npm:^7.14.0, @babel/helpers@npm:^7.24.5": version: 7.24.5 resolution: "@babel/helpers@npm:7.24.5" dependencies: @@ -1809,62 +1244,7 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.23.2": - version: 7.23.2 - resolution: "@babel/helpers@npm:7.23.2" - dependencies: - "@babel/template": ^7.22.15 - "@babel/traverse": ^7.23.2 - "@babel/types": ^7.23.0 - checksum: 3a6a939c5277a27486e7c626812f0643b35d1c053ac2eb66911f5ae6c0a4e4bcdd40750eba36b766b0ee8a753484287f50ae56232a5f8f2947116723e44b9e35 - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.23.7": - version: 7.23.7 - resolution: "@babel/helpers@npm:7.23.7" - dependencies: - "@babel/template": ^7.22.15 - "@babel/traverse": ^7.23.7 - "@babel/types": ^7.23.6 - checksum: f74a61ad28a1bc1fdd9133ad571c07787b66d6db017c707b87c203b0cd06879cea8b33e9c6a8585765a4949efa5df3cc9e19b710fe867f11be38ee29fd4a0488 - languageName: node - linkType: hard - -"@babel/highlight@npm:^7.10.4, @babel/highlight@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/highlight@npm:7.22.5" - dependencies: - "@babel/helper-validator-identifier": ^7.22.5 - chalk: ^2.0.0 - js-tokens: ^4.0.0 - checksum: e8cc07b5de76a9bf779982096ccbbe5a867c36d3786b26151eb570d9344a68af8aa065ed97d431e0d18ba55fe792c7c4301e0d62afff7a52ee0d20678443be54 - languageName: node - linkType: hard - -"@babel/highlight@npm:^7.22.13": - version: 7.22.20 - resolution: "@babel/highlight@npm:7.22.20" - dependencies: - "@babel/helper-validator-identifier": ^7.22.20 - chalk: ^2.4.2 - js-tokens: ^4.0.0 - checksum: f3c3a193afad23434297d88e81d1d6c0c2cf02423de2139ada7ce0a7fc62d8559abf4cc996533c1a9beca7fc990010eb8d544097f75e818ac113bf39ed810aa2 - languageName: node - linkType: hard - -"@babel/highlight@npm:^7.23.4": - version: 7.23.4 - resolution: "@babel/highlight@npm:7.23.4" - dependencies: - "@babel/helper-validator-identifier": ^7.22.20 - chalk: ^2.4.2 - js-tokens: ^4.0.0 - checksum: fbff9fcb2f5539289c3c097d130e852afd10d89a3a08ac0b5ebebbc055cc84a4bcc3dcfed463d488cde12dd0902ef1858279e31d7349b2e8cee43913744bda33 - languageName: node - linkType: hard - -"@babel/highlight@npm:^7.24.2": +"@babel/highlight@npm:^7.10.4, @babel/highlight@npm:^7.24.2": version: 7.24.5 resolution: "@babel/highlight@npm:7.24.5" dependencies: @@ -1876,29 +1256,11 @@ __metadata: languageName: node linkType: hard -"@babel/node@npm:^7.12.10, @babel/node@npm:^7.12.6": - version: 7.22.5 - resolution: "@babel/node@npm:7.22.5" +"@babel/node@npm:^7.12.10, @babel/node@npm:^7.12.6, @babel/node@npm:^7.22.10": + version: 7.23.9 + resolution: "@babel/node@npm:7.23.9" dependencies: - "@babel/register": ^7.22.5 - commander: ^4.0.1 - core-js: ^3.30.2 - node-environment-flags: ^1.0.5 - regenerator-runtime: ^0.13.11 - v8flags: ^3.1.1 - peerDependencies: - "@babel/core": ^7.0.0-0 - bin: - babel-node: ./bin/babel-node.js - checksum: 2b81150d2a0e313d3e281b7c87ec2d044e103ad149e4d4a54b5b0c6a2f816e460934bb47d54699ee57a544bcc34d8d2a497112c12137aef5b1431e62a2192d82 - languageName: node - linkType: hard - -"@babel/node@npm:^7.22.10": - version: 7.22.10 - resolution: "@babel/node@npm:7.22.10" - dependencies: - "@babel/register": ^7.22.5 + "@babel/register": ^7.23.7 commander: ^4.0.1 core-js: ^3.30.2 node-environment-flags: ^1.0.5 @@ -1908,7 +1270,7 @@ __metadata: "@babel/core": ^7.0.0-0 bin: babel-node: ./bin/babel-node.js - checksum: ebb7269d908a0f150a044fbba9282d946c4f43bea6007b685506a2d596de9c6798f98a61ee5de900a6784e36b7dcf14c84085213f0ef276e926915fea7e7780c + checksum: 6de13cbfde3dd3edd55384c14327b8ffb6d0ae6e65fabe3ffa699752319087249660fead7b7254a1e6d4a6d6316c6ab411845c495909fdef074f94ed2c47eb08 languageName: node linkType: hard @@ -1921,25 +1283,7 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.12.11, @babel/parser@npm:^7.12.7, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.3.3": - version: 7.22.5 - resolution: "@babel/parser@npm:7.22.5" - bin: - parser: ./bin/babel-parser.js - checksum: d6a1b1e1f375cf7f81263c57f0b6d41d67e9f498d75960ec7ab62a194d7c232a125a951009edc0c991cb7d6cc6b78b006b15e1e8fb83e0de3fe0ceb6bf3d95ef - languageName: node - linkType: hard - -"@babel/parser@npm:^7.13.16, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.22.7, @babel/parser@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/parser@npm:7.23.0" - bin: - parser: ./bin/babel-parser.js - checksum: ab4ea9360ed4ba3c728c5a9bf33035103ebde20a7e943c4ae1d42becb02a313d731d12a93c795c5a19777031e4022e64b92a52262eda902522a1a18649826283 - languageName: node - linkType: hard - -"@babel/parser@npm:^7.14.3, @babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.5": +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.3, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.5, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.5, @babel/parser@npm:^7.3.3": version: 7.24.5 resolution: "@babel/parser@npm:7.24.5" bin: @@ -1948,60 +1292,51 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.23.5, @babel/parser@npm:^7.23.6": - version: 7.23.6 - resolution: "@babel/parser@npm:7.23.6" - bin: - parser: ./bin/babel-parser.js - checksum: 6f76cd5ccae1fa9bcab3525b0865c6222e9c1d22f87abc69f28c5c7b2c8816a13361f5bd06bddbd5faf903f7320a8feba02545c981468acec45d12a03db7755e - languageName: node - linkType: hard - -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.22.15" +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.5" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-plugin-utils": ^7.24.5 peerDependencies: "@babel/core": ^7.0.0 - checksum: fb2288ac168e6670a77f73b92e835f7a579468435e81c9261729e9ba9c601ff22622bacd3e71eb190b135016a6fbab5d824501c7b91733dd379022a75163806c + checksum: b471972dcc4a3ba32821329a57725e2b563421e975d7ffec7fcabd70af0fced6a50bcc9ed2a8cbd4a9ac7c09cfbf43c7116e82f3b9064b33a22309500b632108 languageName: node linkType: hard -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.22.5" +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0 - checksum: 573bd9b1984d74e3663cb7f5f317646223020107681e8dcffe68b041bd620ebbb35c0cc05f4ee20f2da502d02a9633e2b477596e71f4f7802f72c02e948f38af + checksum: d4e592e6fc4878654243d2e7b51ea86471b868a8cb09de29e73b65d2b64159990c6c198fd7c9c2af2e38b1cddf70206243792853c47384a84f829dada152f605 languageName: node linkType: hard -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.22.15" +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - "@babel/plugin-transform-optional-chaining": ^7.22.15 + "@babel/plugin-transform-optional-chaining": ^7.24.1 peerDependencies: "@babel/core": ^7.13.0 - checksum: 46fb46af40446918d64530f544ea0104e274ccd8a16b8a8f6fa2e51a198af6ac2b620aaf8875f3427671f09717949a584c79fe20f521245214f50b8de56cd116 + checksum: 351c36e45795a7890d610ab9041a52f4078a59429f6e74c281984aa44149a10d43e82b3a8172c703c0d5679471e165d1c02b6d2e45a677958ee301b89403f202 languageName: node linkType: hard -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.22.5" +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - "@babel/plugin-transform-optional-chaining": ^7.22.5 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: - "@babel/core": ^7.13.0 - checksum: 1e38dcd28d2dc5012f96550a3fa1330d71fc923607ceccc91e83c0b7dd3eaeb4d8c632946909c389964acb3e35c888f81653e2d24f7cc02a83fe39a64ca59e89 + "@babel/core": ^7.0.0 + checksum: d7dd5a59a54635a3152895dcaa68f3370bb09d1f9906c1e72232ff759159e6be48de4a598a993c986997280a2dc29922a48aaa98020f16439f3f57ad72788354 languageName: node linkType: hard @@ -2031,7 +1366,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-class-properties@npm:^7.10.4, @babel/plugin-proposal-class-properties@npm:^7.12.1, @babel/plugin-proposal-class-properties@npm:^7.13.0, @babel/plugin-proposal-class-properties@npm:^7.7.4": +"@babel/plugin-proposal-class-properties@npm:^7.10.4, @babel/plugin-proposal-class-properties@npm:^7.12.1, @babel/plugin-proposal-class-properties@npm:^7.7.4": version: 7.18.6 resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" dependencies: @@ -2043,18 +1378,16 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-decorators@npm:^7.12.1, @babel/plugin-proposal-decorators@npm:^7.12.12": - version: 7.22.5 - resolution: "@babel/plugin-proposal-decorators@npm:7.22.5" +"@babel/plugin-proposal-decorators@npm:^7.12.1": + version: 7.24.1 + resolution: "@babel/plugin-proposal-decorators@npm:7.24.1" dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.5 - "@babel/plugin-syntax-decorators": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.24.1 + "@babel/helper-plugin-utils": ^7.24.0 + "@babel/plugin-syntax-decorators": ^7.24.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 31930187a8b3fc58ea92b7b667c7947de70a31c4309122e223cdac7bddaab963f4ed0ca8aaeca730dd313521574f8c34e427c4fadc0ecb2d38522ddd5a7acb5f + checksum: ffe49522ada6581f1c760b777dbd913afcd204e11e6907c4f2c293ce6d30961449ac19d9960250d8743a1f60e21cb667e51a3af15992dfe7627105e039c46a9b languageName: node linkType: hard @@ -2070,18 +1403,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-export-default-from@npm:^7.12.1": - version: 7.22.5 - resolution: "@babel/plugin-proposal-export-default-from@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-export-default-from": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: db5d0df5bb8d13078cf2793900ca89075622e4a8c4c5246328b1b62ad3c99990b18e4716de10123a34649fea885d8a615082a21db905903d27fa0bcbd53da799 - languageName: node - linkType: hard - "@babel/plugin-proposal-export-namespace-from@npm:^7.10.4": version: 7.18.9 resolution: "@babel/plugin-proposal-export-namespace-from@npm:7.18.9" @@ -2118,7 +1439,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.10.4, @babel/plugin-proposal-nullish-coalescing-operator@npm:^7.12.1, @babel/plugin-proposal-nullish-coalescing-operator@npm:^7.13.8": +"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.10.4": version: 7.18.6 resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.18.6" dependencies: @@ -2142,20 +1463,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-object-rest-spread@npm:7.12.1": - version: 7.12.1 - resolution: "@babel/plugin-proposal-object-rest-spread@npm:7.12.1" - dependencies: - "@babel/helper-plugin-utils": ^7.10.4 - "@babel/plugin-syntax-object-rest-spread": ^7.8.0 - "@babel/plugin-transform-parameters": ^7.12.1 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: f773d59ead8b056b646d585e95d610cca2f0aeaa2eeaad74b3eb9e25821b06f27e361dd0aac9a088a10c22fee1ead8863f82a2be073e28eb04ca9a330a00941e - languageName: node - linkType: hard - -"@babel/plugin-proposal-object-rest-spread@npm:^7.11.0, @babel/plugin-proposal-object-rest-spread@npm:^7.12.1": +"@babel/plugin-proposal-object-rest-spread@npm:^7.11.0": version: 7.20.7 resolution: "@babel/plugin-proposal-object-rest-spread@npm:7.20.7" dependencies: @@ -2182,7 +1490,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-optional-chaining@npm:^7.11.0, @babel/plugin-proposal-optional-chaining@npm:^7.12.7, @babel/plugin-proposal-optional-chaining@npm:^7.13.12, @babel/plugin-proposal-optional-chaining@npm:^7.14.2": +"@babel/plugin-proposal-optional-chaining@npm:^7.11.0, @babel/plugin-proposal-optional-chaining@npm:^7.14.2": version: 7.21.0 resolution: "@babel/plugin-proposal-optional-chaining@npm:7.21.0" dependencies: @@ -2195,7 +1503,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-private-methods@npm:^7.10.4, @babel/plugin-proposal-private-methods@npm:^7.12.1": +"@babel/plugin-proposal-private-methods@npm:^7.10.4": version: 7.18.6 resolution: "@babel/plugin-proposal-private-methods@npm:7.18.6" dependencies: @@ -2216,20 +1524,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-private-property-in-object@npm:^7.12.1": - version: 7.21.11 - resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.11" - dependencies: - "@babel/helper-annotate-as-pure": ^7.18.6 - "@babel/helper-create-class-features-plugin": ^7.21.0 - "@babel/helper-plugin-utils": ^7.20.2 - "@babel/plugin-syntax-private-property-in-object": ^7.14.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 3c8c9ea175101b1cbb2b0e8fee20fcbdd03eb0700d3581aa826ac3573c9b002f39b1512c2af9fd1903ff921bcc864da95ad3cdeba53c9fbcfb3dc23916eacf47 - languageName: node - linkType: hard - "@babel/plugin-proposal-unicode-property-regex@npm:^7.10.4, @babel/plugin-proposal-unicode-property-regex@npm:^7.4.4": version: 7.18.6 resolution: "@babel/plugin-proposal-unicode-property-regex@npm:7.18.6" @@ -2286,14 +1580,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-decorators@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-syntax-decorators@npm:7.22.5" +"@babel/plugin-syntax-decorators@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-syntax-decorators@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: a24ad01f89523575b93f3bdef48a16e80d2e0a3e0fc90803c0397c58c6c7abf92379e941719f7f469757d6778d5ac60dc488d4a8b406bd6bbf3c636da477e534 + checksum: 14028a746f86efbdd47e4961456bb53d656e9e3461890f66b1b01032151d15fda5ba99fcaa60232a229a33aa9e73b11c2597b706d5074c520155757e372cd17b languageName: node linkType: hard @@ -2308,17 +1602,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-export-default-from@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-syntax-export-default-from@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 57fae17e0db773fa6f11263cf59e9c1946145c3dde01b399c364c6a6b0b7c9df18051d697ad95b5c6927d7f081921aa1f1096bbd9a2762746e92c1144810c32c - languageName: node - linkType: hard - "@babel/plugin-syntax-export-namespace-from@npm:^7.8.3": version: 7.8.3 resolution: "@babel/plugin-syntax-export-namespace-from@npm:7.8.3" @@ -2330,36 +1613,36 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-flow@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-syntax-flow@npm:7.22.5" +"@babel/plugin-syntax-flow@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-syntax-flow@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 07afc7df02141597968532bfbfa3f6c0ad21a2bdd885d0e5e035dcf60fdf35f0995631c9750b464e1a6f2feea14160a82787f914e88e8f7115dc99f09853e43e + checksum: 618de04360a96111408abdaafaba2efbaef0d90faad029d50e0281eaad5d7c7bd2ce4420bbac0ee27ad84c2b7bbc3e48f782064f81ed5bc40c398637991004c7 languageName: node linkType: hard -"@babel/plugin-syntax-import-assertions@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-syntax-import-assertions@npm:7.22.5" +"@babel/plugin-syntax-import-assertions@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b297d7c757c746ed0ef3496ad749ae2ce648ec73dae5184120b191c280e62da7dc104ee126bc0053dfece3ce198a5ee7dc1cbf4768860f666afef5dee84a7146 + checksum: 72f0340d73e037f0702c61670054e0af66ece7282c5c2f4ba8de059390fee502de282defdf15959cd9f71aa18dc5c5e4e7a0fde317799a0600c6c4e0a656d82b languageName: node linkType: hard -"@babel/plugin-syntax-import-attributes@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-syntax-import-attributes@npm:7.22.5" +"@babel/plugin-syntax-import-attributes@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: de0b104a82cb8ffdc29472177210936609b973665a2ad8ef26c078251d7c728fbd521119de4c417285408a8bae345b5da09cd4a4a3311619f71b9b2c64cce3fa + checksum: 309634e3335777aee902552b2cf244c4a8050213cc878b3fb9d70ad8cbbff325dc46ac5e5791836ff477ea373b27832238205f6ceaff81f7ea7c4c7e8fbb13bb languageName: node linkType: hard @@ -2385,25 +1668,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:7.12.1": - version: 7.12.1 - resolution: "@babel/plugin-syntax-jsx@npm:7.12.1" +"@babel/plugin-syntax-jsx@npm:^7.12.1, @babel/plugin-syntax-jsx@npm:^7.23.3, @babel/plugin-syntax-jsx@npm:^7.24.1, @babel/plugin-syntax-jsx@npm:^7.7.2": + version: 7.24.1 + resolution: "@babel/plugin-syntax-jsx@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.10.4 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 11d435f9e4e71c0f00e5bc295b40747c2c42341b7f38ddc5f8ac41d49ddfa247514dbe91932fa3dabd65581b4c7a9fe5b3d1c2b285e5ca32f4e5296cc185d40c - languageName: node - linkType: hard - -"@babel/plugin-syntax-jsx@npm:^7.12.1, @babel/plugin-syntax-jsx@npm:^7.22.5, @babel/plugin-syntax-jsx@npm:^7.7.2": - version: 7.22.5 - resolution: "@babel/plugin-syntax-jsx@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: b56ceaa9c6adc17fadfb48e1c801d07797195df2a581489e33c8034950e12e7778de6e1e70d6bcf7c5c7ada6222fe6bad5746187ab280df435f5a2799c8dd0d8 + checksum: 6cec76fbfe6ca81c9345c2904d8d9a8a0df222f9269f0962ed6eb2eb8f3f10c2f15e993d1ef09dbaf97726bf1792b5851cf5bd9a769f966a19448df6be95d19a languageName: node linkType: hard @@ -2440,7 +1712,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-object-rest-spread@npm:7.8.3, @babel/plugin-syntax-object-rest-spread@npm:^7.8.0, @babel/plugin-syntax-object-rest-spread@npm:^7.8.3": +"@babel/plugin-syntax-object-rest-spread@npm:^7.8.0, @babel/plugin-syntax-object-rest-spread@npm:^7.8.3": version: 7.8.3 resolution: "@babel/plugin-syntax-object-rest-spread@npm:7.8.3" dependencies: @@ -2495,18 +1767,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-typescript@npm:^7.22.5, @babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.22.5 - resolution: "@babel/plugin-syntax-typescript@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 523a76627f17e67dc1999f4d7c7a71ed79e9f77f55a61cf05051101967ac23ec378ff0c93787b2cbd5d53720ad799658d796a649fa351682b2bf636f63b665a1 - languageName: node - linkType: hard - -"@babel/plugin-syntax-typescript@npm:^7.24.1": +"@babel/plugin-syntax-typescript@npm:^7.24.1, @babel/plugin-syntax-typescript@npm:^7.7.2": version: 7.24.1 resolution: "@babel/plugin-syntax-typescript@npm:7.24.1" dependencies: @@ -2529,7 +1790,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-arrow-functions@npm:^7.10.4": +"@babel/plugin-transform-arrow-functions@npm:^7.10.4, @babel/plugin-transform-arrow-functions@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-arrow-functions@npm:7.24.1" dependencies: @@ -2540,46 +1801,21 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-arrow-functions@npm:^7.12.1, @babel/plugin-transform-arrow-functions@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-arrow-functions@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 1b24d47ddac6ae2fe8c7fab9a020fdb6a556d17d8c5f189bb470ff2958a5437fe6441521fd3d850f4283a1131d7a0acf3e8ebe789f9077f54bab4e2e8c6df176 - languageName: node - linkType: hard - -"@babel/plugin-transform-async-generator-functions@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.22.5" - dependencies: - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-remap-async-to-generator": ^7.22.5 - "@babel/plugin-syntax-async-generators": ^7.8.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 99ba86cbabb93d6a339398ca8ddaba8fbb40224831daa9ccff692c8532d7ce5de34fd71e60396427d4585ded9484b242aecd042af449f1944ca7b4bbb8ef5b4a - languageName: node - linkType: hard - -"@babel/plugin-transform-async-generator-functions@npm:^7.23.2": - version: 7.23.2 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.23.2" +"@babel/plugin-transform-async-generator-functions@npm:^7.24.3": + version: 7.24.3 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.24.3" dependencies: "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 "@babel/helper-remap-async-to-generator": ^7.22.20 "@babel/plugin-syntax-async-generators": ^7.8.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 16d7bd5dbd67991ab320a46ada19a9a0c8364725603c731f152afc98ee8764dc738c93f081a7560906d265b78c376bccabf3e31b9f99071c8982a6f9c8e2ac45 + checksum: 55ceed059f819dcccbfe69600bfa1c055ada466bd54eda117cfdd2cf773dd85799e2f6556e4a559b076e93b9704abcca2aef9d72aad7dc8a5d3d17886052f1d3 languageName: node linkType: hard -"@babel/plugin-transform-async-to-generator@npm:^7.10.4": +"@babel/plugin-transform-async-to-generator@npm:^7.10.4, @babel/plugin-transform-async-to-generator@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-async-to-generator@npm:7.24.1" dependencies: @@ -2592,20 +1828,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-async-to-generator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-async-to-generator@npm:7.22.5" - dependencies: - "@babel/helper-module-imports": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-remap-async-to-generator": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 2972f22c3a5a56a8b225f4fa1bbdbcf6e989e0da460d5f4e2280652b1433d7c68b6ddc0cc2affc4b59905835133a253a31c24c7ca1bebe1a2f28377d27b4ca1c - languageName: node - linkType: hard - -"@babel/plugin-transform-block-scoped-functions@npm:^7.10.4": +"@babel/plugin-transform-block-scoped-functions@npm:^7.10.4, @babel/plugin-transform-block-scoped-functions@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.24.1" dependencies: @@ -2616,18 +1839,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-block-scoped-functions@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 21878d4f0040f5001c4a14e17759e80bf699cb883a497552fa882dbc05230b100e8572345654b091021d5c4227555ed2bf40c8d6ba16a54d81145abfe0022cf8 - languageName: node - linkType: hard - -"@babel/plugin-transform-block-scoping@npm:^7.10.4": +"@babel/plugin-transform-block-scoping@npm:^7.10.4, @babel/plugin-transform-block-scoping@npm:^7.24.5": version: 7.24.5 resolution: "@babel/plugin-transform-block-scoping@npm:7.24.5" dependencies: @@ -2638,105 +1850,50 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-block-scoping@npm:^7.12.12, @babel/plugin-transform-block-scoping@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-block-scoping@npm:7.22.5" +"@babel/plugin-transform-class-properties@npm:^7.22.5, @babel/plugin-transform-class-properties@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-class-properties@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.24.1 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 68f663d349345b522e1dece9641ee304d8f7db1d4b11998f47ebc5d678d281f76a143fb8603a1c12596962d7a63ffe044cd205a4910c8d74906eae17a605f96f + checksum: 00dff042ac9df4ae67b5ef98b1137cc72e0a24e6d911dc200540a8cb1f00b4cff367a922aeb22da17da662079f0abcd46ee1c5f4cdf37ceebf6ff1639bb9af27 languageName: node linkType: hard -"@babel/plugin-transform-block-scoping@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/plugin-transform-block-scoping@npm:7.23.0" +"@babel/plugin-transform-class-static-block@npm:^7.24.4": + version: 7.24.4 + resolution: "@babel/plugin-transform-class-static-block@npm:7.24.4" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: f5d0822a4e2bb3a0b5172f01f8c107999b880f0e538a9c1bae3c7720e85d8d117a67167f5e8eba909e0ec3db67be3b30e7f5c83211dd4be5c7096222071571be - languageName: node - linkType: hard - -"@babel/plugin-transform-class-properties@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-class-properties@npm:7.22.5" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 707f976d3aea2b52dad36a5695a71af8956f9b1d5dec02c2b8cce7ff3b5e60df4cbe059c71ae0b7983034dc639de654a2c928b97e4e01ebf436d58ea43639e7d - languageName: node - linkType: hard - -"@babel/plugin-transform-class-static-block@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-class-static-block@npm:7.22.11" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.11 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.24.4 + "@babel/helper-plugin-utils": ^7.24.0 "@babel/plugin-syntax-class-static-block": ^7.14.5 peerDependencies: "@babel/core": ^7.12.0 - checksum: 74c06f315dbeb101784682f89d6e40a46b243132b63f430ac9ee5781d3fedff57fc6bf7390aa2b19d44a9d7e49a1e70e572bdde1907480881204ef33163b9630 + checksum: 19dfeaf4a2ac03695034f7211a8b5ad89103b224608ac3e91791055107c5fe4d7ebe5d9fbb31b4a91265694af78762260642eb270f4b239c175984ee4b253f80 languageName: node linkType: hard -"@babel/plugin-transform-class-static-block@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-class-static-block@npm:7.22.5" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-class-static-block": ^7.14.5 - peerDependencies: - "@babel/core": ^7.12.0 - checksum: 23814d00b2966e8dab7a60934622853698b2cb861a8667c006e000d8e5a50aba4d221c52852552562e7f38e32ad5c7778125ef602c2d2f1c4f9d8f790a9f27e9 - languageName: node - linkType: hard - -"@babel/plugin-transform-classes@npm:^7.10.4, @babel/plugin-transform-classes@npm:^7.12.1, @babel/plugin-transform-classes@npm:^7.22.5, @babel/plugin-transform-classes@npm:^7.9.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-classes@npm:7.22.5" +"@babel/plugin-transform-classes@npm:^7.10.4, @babel/plugin-transform-classes@npm:^7.12.1, @babel/plugin-transform-classes@npm:^7.24.5, @babel/plugin-transform-classes@npm:^7.9.5": + version: 7.24.5 + resolution: "@babel/plugin-transform-classes@npm:7.24.5" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-compilation-targets": ^7.22.5 - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-function-name": ^7.22.5 - "@babel/helper-optimise-call-expression": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.5 + "@babel/helper-compilation-targets": ^7.23.6 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-function-name": ^7.23.0 + "@babel/helper-plugin-utils": ^7.24.5 + "@babel/helper-replace-supers": ^7.24.1 + "@babel/helper-split-export-declaration": ^7.24.5 globals: ^11.1.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: c5ac4a3ea8bf7441246e963c35617c1fe8d6515c94a376ef0b724c6950fbb9e5481c51fc4ff13e5afd8949a6bfe1ef20ab937692054772e2376dfeae3b6b99b5 + checksum: 4affcbb7cb01fa4764c7a4b534c30fd24a4b68e680a2d6e242dd7ca8726490f0f1426c44797deff84a38a162e0629718900c68d28daffe2b12adf5b4194156a7 languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-classes@npm:7.22.15" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-compilation-targets": ^7.22.15 - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-function-name": ^7.22.5 - "@babel/helper-optimise-call-expression": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.9 - "@babel/helper-split-export-declaration": ^7.22.6 - globals: ^11.1.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: c9342bcf41e0253d83d9f73c4f9d2c9f885c0412f58ebfe462d57579c8247b949cbb023f15383d18c89fe5d12b537633e2ca4ba906ce47238615bc679beafb55 - languageName: node - linkType: hard - -"@babel/plugin-transform-computed-properties@npm:^7.10.4": +"@babel/plugin-transform-computed-properties@npm:^7.10.4, @babel/plugin-transform-computed-properties@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-computed-properties@npm:7.24.1" dependencies: @@ -2748,19 +1905,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-computed-properties@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-computed-properties@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/template": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 22ecea23c1635083f5473092c5fbca62cbf7a85764bcf3e704c850446d68fe946097f6001c4cbfc92b4aee27ed30b375773ee479f749293e41fdb8f1fb8fcb67 - languageName: node - linkType: hard - -"@babel/plugin-transform-destructuring@npm:^7.10.4": +"@babel/plugin-transform-destructuring@npm:^7.10.4, @babel/plugin-transform-destructuring@npm:^7.24.5": version: 7.24.5 resolution: "@babel/plugin-transform-destructuring@npm:7.24.5" dependencies: @@ -2771,29 +1916,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-destructuring@npm:^7.12.1, @babel/plugin-transform-destructuring@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-destructuring@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: bffd0069f44165e101368f34ab34d4bb810ef3dc16a5bf5e55e633a60b0c3aca948dccc15d04e6d6996a2a467f4a52d7224a82efc4be175836cc6e3a3702efa5 - languageName: node - linkType: hard - -"@babel/plugin-transform-destructuring@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/plugin-transform-destructuring@npm:7.23.0" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 038505eabdde2e1bb3bb904e50292b263d61d35e18660f751e7753b5723e2a5a5903a493290d772c8598da98c2c904b7cf45552ad1c11636fcb78f60754abd53 - languageName: node - linkType: hard - -"@babel/plugin-transform-dotall-regex@npm:^7.10.4": +"@babel/plugin-transform-dotall-regex@npm:^7.10.4, @babel/plugin-transform-dotall-regex@npm:^7.24.1, @babel/plugin-transform-dotall-regex@npm:^7.4.4": version: 7.24.1 resolution: "@babel/plugin-transform-dotall-regex@npm:7.24.1" dependencies: @@ -2805,19 +1928,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-dotall-regex@npm:^7.22.5, @babel/plugin-transform-dotall-regex@npm:^7.4.4": - version: 7.22.5 - resolution: "@babel/plugin-transform-dotall-regex@npm:7.22.5" - dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: e0d7b95380483ef563c13f7c0a2122f575c58708cfb56494d6265ebb31753cf46ee0b3f5126fa6bbea5af392b3a2da05bf1e028d0b2b4d1dc279edd67cf3c3d9 - languageName: node - linkType: hard - -"@babel/plugin-transform-duplicate-keys@npm:^7.10.4": +"@babel/plugin-transform-duplicate-keys@npm:^7.10.4, @babel/plugin-transform-duplicate-keys@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-duplicate-keys@npm:7.24.1" dependencies: @@ -2828,42 +1939,19 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-duplicate-keys@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-duplicate-keys@npm:7.22.5" +"@babel/plugin-transform-dynamic-import@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 82772fdcc1301358bc722c1316bea071ad0cd5893ca95b08e183748e044277a93ee90f9c641ac7873a00e4b31a8df7cf8c0981ca98d01becb4864a11b22c09d1 - languageName: node - linkType: hard - -"@babel/plugin-transform-dynamic-import@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-dynamic-import@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 "@babel/plugin-syntax-dynamic-import": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: cf0dd2d3da42ae18ccfa54bef7c80bf26b3bcc48751fc38dd41ad47bc14cc76ca8ec692f39f8b1ef54b3f48eff8db79e6397e4653033bb3a64e433f3c3a43edf + checksum: 7e2834780e9b5251ef341854043a89c91473b83c335358620ca721554877e64e416aeb3288a35f03e825c4958e07d5d00ead08c4490fadc276a21fe151d812f1 languageName: node linkType: hard -"@babel/plugin-transform-dynamic-import@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-dynamic-import@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-dynamic-import": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 82fb6fa0b6f7c7760ac21ebcb856a01579c9e64a325d5bb8841591b58b2d92024169f10f4ca2b34b45376999b352974138c94fc1d5cc330e00beeeb1bda51425 - languageName: node - linkType: hard - -"@babel/plugin-transform-exponentiation-operator@npm:^7.10.4": +"@babel/plugin-transform-exponentiation-operator@npm:^7.10.4, @babel/plugin-transform-exponentiation-operator@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.24.1" dependencies: @@ -2875,55 +1963,31 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-exponentiation-operator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.22.5" +"@babel/plugin-transform-export-namespace-from@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.24.1" dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: e8832460cfc9e087561fa42a796bb4eb181e6983d6db85c6dcec15f98af4ae3d13fcab18a262252a43b075d79ac93aaa38d33022bc5a870d2760c6888ba5d211 - languageName: node - linkType: hard - -"@babel/plugin-transform-export-namespace-from@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-export-namespace-from@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 "@babel/plugin-syntax-export-namespace-from": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2b65ddf9ab4cfa8ffc72983c689b99d9ce0fe74846c2e518a1955f703e1fe073d0865810959164800613c3235a29cf9cae3567a46bf9cb53a2384469d3913e85 + checksum: 510bb23b2423d5fbffef69b356e4050929c21a7627e8194b1506dd935c7d9cbbd696c9ae9d7c3bcd7e6e7b69561b0b290c2d72d446327b40fc20ce40bbca6712 languageName: node linkType: hard -"@babel/plugin-transform-export-namespace-from@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-export-namespace-from@npm:7.22.5" +"@babel/plugin-transform-flow-strip-types@npm:^7.12.10, @babel/plugin-transform-flow-strip-types@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-flow-strip-types@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + "@babel/helper-plugin-utils": ^7.24.0 + "@babel/plugin-syntax-flow": ^7.24.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d5d301dde2d6e7f9e4db12ac70e19153f0e8d17406ad733a8f7d01de77d123588fe90c7f5b8cc086420594ec1e7d20abc5e08323f9ad9704a19c6c87ca03eb59 + checksum: e6aa9cbad0441867598d390d4df65bc8c6b797574673e4eedbdae0cc528e81e00f4b2cd38f7d138b0f04bcdd2540384a9812d5d76af5abfa06aee1c7fc20ca58 languageName: node linkType: hard -"@babel/plugin-transform-flow-strip-types@npm:^7.12.10, @babel/plugin-transform-flow-strip-types@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-flow-strip-types@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-flow": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 5949a8e5214e3fc65d31dab0551423cea9d9eef35faa5d0004707ba7347baf96166aa400907ce7498f754db4e1e9d039ca434a508546b0dc9fdae9a42e814c1a - languageName: node - linkType: hard - -"@babel/plugin-transform-for-of@npm:^7.10.4": +"@babel/plugin-transform-for-of@npm:^7.10.4, @babel/plugin-transform-for-of@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-for-of@npm:7.24.1" dependencies: @@ -2935,29 +1999,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-for-of@npm:^7.12.1, @babel/plugin-transform-for-of@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-for-of@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 08bd2d14f10b8ae421e61b55c28232547044149b8ef62c99c54561ce93a5067f9654d701d798871e733543359748e1b093f5c450b69705ec1db674175ee9fcdb - languageName: node - linkType: hard - -"@babel/plugin-transform-for-of@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-for-of@npm:7.22.15" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 64182292f4be8cdf1fff06fe62ba110bf5e5dbb5d966d5e8871ef40a673cd934217da51b9f4a4ba303ca936be787f30e3d13a91fe410339de79e0fe9f0807e15 - languageName: node - linkType: hard - -"@babel/plugin-transform-function-name@npm:^7.10.4": +"@babel/plugin-transform-function-name@npm:^7.10.4, @babel/plugin-transform-function-name@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-function-name@npm:7.24.1" dependencies: @@ -2970,55 +2012,30 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-function-name@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-function-name@npm:7.22.5" - dependencies: - "@babel/helper-compilation-targets": ^7.22.5 - "@babel/helper-function-name": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 206bdef2ff91c29a7d94c77778ad79f18bdb2cd6a30179449f2b95af04637cb68d96625dc673d9a0961b6b7088bd325bbed7540caf9aa8f69e5b003d6ba20456 - languageName: node - linkType: hard - "@babel/plugin-transform-instanceof@npm:^7.10.4, @babel/plugin-transform-instanceof@npm:^7.12.1, @babel/plugin-transform-instanceof@npm:^7.8.3": - version: 7.22.5 - resolution: "@babel/plugin-transform-instanceof@npm:7.22.5" + version: 7.24.1 + resolution: "@babel/plugin-transform-instanceof@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 085351dc55fdc5f5c4047344b963408e8f31fd8334a295b8ddc83c92696aef7dc69cf4c8b70364cda9ee9a491a1a08a2b3e44b931902ea6b28c98a8073f24bf2 + checksum: e984e29bd113d5430a4206ff6687789839348843698a2a33a0e1d0dfc68db77627f1efeaa1dc52b10716059146856b10db34134c65b7653171f609527ada7730 languageName: node linkType: hard -"@babel/plugin-transform-json-strings@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-json-strings@npm:7.22.11" +"@babel/plugin-transform-json-strings@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-json-strings@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 "@babel/plugin-syntax-json-strings": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 90f46a99c4136187d16f30f1f5f51e479c919edb6f6b4ce43fe81fdae2c89a556a0a6f6f2ec7ea3de7014a504f6df2220e3bc19dd7011f76bd275c195842f886 + checksum: 13d9b6a3c31ab4be853b3d49d8d1171f9bd8198562fd75da8f31e7de31398e1cfa6eb1d073bed93c9746e4f9c47a53b20f8f4c255ece3f88c90852ad3181dc2d languageName: node linkType: hard -"@babel/plugin-transform-json-strings@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-json-strings@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-json-strings": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 64ee0f3497822d312b609d3b8a5a2617337d1624292e89f5e90fd25b5bc91a20beadfa91730b5b199b5a027284ced5d59748d99e8ab81ee7bdac38236e6b61ca - languageName: node - linkType: hard - -"@babel/plugin-transform-literals@npm:^7.10.4": +"@babel/plugin-transform-literals@npm:^7.10.4, @babel/plugin-transform-literals@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-literals@npm:7.24.1" dependencies: @@ -3029,42 +2046,19 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-literals@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-literals@npm:7.22.5" +"@babel/plugin-transform-logical-assignment-operators@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 1003d0cf98e9ae432889bcf5f3d5f7d463f777fc2c74b0d4a1a93b51e83606c263a16146e34f0a06b291300aa5f2001d6e8bf65ed1bf478ab071b714bf158aa5 - languageName: node - linkType: hard - -"@babel/plugin-transform-logical-assignment-operators@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9810f7918514bd59579ccc0950b4f352569abb40959569d38931e57f11e6b9aa920bdef403ffd8cd5d4e0243e0bbf7a1ebb445f3428c8b7a2421568ff2f681be + checksum: 98a2e0843ddfe51443c1bfcf08ba40ad8856fd4f8e397b392a5390a54f257c8c1b9a99d8ffc0fc7e8c55cce45e2cd9c2795a4450303f48f501bcbd662de44554 languageName: node linkType: hard -"@babel/plugin-transform-logical-assignment-operators@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: bfacdafa8018d1607897015e1ea0f98edbefee16b4409d5f37c37df0d2058dde2e55586dd79f8479a0cd603ff06272216de077f071bc49c96014edfe1629bd26 - languageName: node - linkType: hard - -"@babel/plugin-transform-member-expression-literals@npm:^7.10.4": +"@babel/plugin-transform-member-expression-literals@npm:^7.10.4, @babel/plugin-transform-member-expression-literals@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-member-expression-literals@npm:7.24.1" dependencies: @@ -3075,18 +2069,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-member-expression-literals@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-member-expression-literals@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 731a341b17511809ae435b64822d4d093e86fd928b572028e6742bdfba271c57070860b0f3da080a76c5574d58c4f369fac3f7bf0f450b37920c0fc6fe27bb4e - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-amd@npm:^7.10.4": +"@babel/plugin-transform-modules-amd@npm:^7.10.4, @babel/plugin-transform-modules-amd@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-modules-amd@npm:7.24.1" dependencies: @@ -3098,31 +2081,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-modules-amd@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-modules-amd@npm:7.22.5" - dependencies: - "@babel/helper-module-transforms": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 157ae3b58a50ca52e361860ecab2b608bc9228ea6c760112a35302990976f8936b8d75a2b21925797eed7b3bab4930a3f447193127afef9a21b7b6463ff0b422 - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-amd@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/plugin-transform-modules-amd@npm:7.23.0" - dependencies: - "@babel/helper-module-transforms": ^7.23.0 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: dda02864029ff66955e21d19c3d245aad69792b75e748de1391403bc86c8e9720b4f320b0db8413a29c11ba63b168146cf849180b5677bc6a74bfd085d20376d - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-commonjs@npm:^7.10.4": +"@babel/plugin-transform-modules-commonjs@npm:^7.10.4, @babel/plugin-transform-modules-commonjs@npm:^7.23.0, @babel/plugin-transform-modules-commonjs@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.1" dependencies: @@ -3135,33 +2094,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-modules-commonjs@npm:^7.13.8, @babel/plugin-transform-modules-commonjs@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.23.0" - dependencies: - "@babel/helper-module-transforms": ^7.23.0 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-simple-access": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 1f015764c2e63445d46660e7a2eb9002c20def04daf98fa93c9dadb5bd55adbefefd1ccdc11bcafa5e2f04275939d2414482703bc35bc60d6ca2bf1f67b720e3 - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-commonjs@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.22.5" - dependencies: - "@babel/helper-module-transforms": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-simple-access": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 818317363cc96a1ab28cd0691bdb86fe06f452d210e2cef7ef4708f2c2c80cbe3c76bca23c2ab4b1bb200d44e508eae71f627c7cb27299a41be56fc7e3aaced0 - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-systemjs@npm:^7.10.4": +"@babel/plugin-transform-modules-systemjs@npm:^7.10.4, @babel/plugin-transform-modules-systemjs@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-modules-systemjs@npm:7.24.1" dependencies: @@ -3175,35 +2108,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-modules-systemjs@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.22.5" - dependencies: - "@babel/helper-hoist-variables": ^7.22.5 - "@babel/helper-module-transforms": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-identifier": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 25d7ada275039523541cfc3efd91cd3d9cfc77e7b9dd6a51e7d9ad842d2cb3e0f26aee29426aa56ac72f61247268369680f2bdc1171bb00a16cfd00bbb325a6c - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-systemjs@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.23.0" - dependencies: - "@babel/helper-hoist-variables": ^7.22.5 - "@babel/helper-module-transforms": ^7.23.0 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-identifier": ^7.22.20 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 04c5cef7d6921bb9c9073cea389289099124e78cd1e3b7e020e3c085d486b48efadd9a42c0c0d963a9b1c3d5465c3151229092ea719997e53427f36935c84178 - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-umd@npm:^7.10.4": +"@babel/plugin-transform-modules-umd@npm:^7.10.4, @babel/plugin-transform-modules-umd@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-modules-umd@npm:7.24.1" dependencies: @@ -3215,18 +2120,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-modules-umd@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-modules-umd@npm:7.22.5" - dependencies: - "@babel/helper-module-transforms": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: f4a40e18986182a2b1be6af949aaff67a7d112af3d26bbd4319d05b50f323a62a10b32b5584148e4630bdffbd4d85b31c0d571fe4f601354898b837b87afca4c - languageName: node - linkType: hard - "@babel/plugin-transform-named-capturing-groups-regex@npm:^7.10.4, @babel/plugin-transform-named-capturing-groups-regex@npm:^7.22.5": version: 7.22.5 resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.22.5" @@ -3239,7 +2132,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-new-target@npm:^7.10.4": +"@babel/plugin-transform-new-target@npm:^7.10.4, @babel/plugin-transform-new-target@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-new-target@npm:7.24.1" dependencies: @@ -3250,96 +2143,45 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-new-target@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-new-target@npm:7.22.5" +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.11, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 22ead0668bfd8db9166a4a47579d9f44726b59f21104561a6dd851156336741abdc5c576558e042c58c4b4fd577d3e29e4bd836021007f3381c33fe3c88dca19 - languageName: node - linkType: hard - -"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 328c0ebfbbc82256af00252fb795996b093f57b528a57afcb30843ca52d24a6d824029ad6d22f042f3af336bb4dc1963b4841c2ad774424b02d14ae7cfff2701 + checksum: c8532951506fb031287280cebeef10aa714f8a7cea2b62a13c805f0e0af945ba77a7c87e4bbbe4c37fe973e0e5d5e649cfac7f0374f57efc54cdf9656362a392 languageName: node linkType: hard -"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.22.5" +"@babel/plugin-transform-numeric-separator@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 66f7237d59060954fc0ba0c5d9e7081580421014b446080b3efedb3d4be9a4346f50974c5886a4ec7962db9992e5e1c5e26cb76801728b4d9626ac2eb09c26f7 - languageName: node - linkType: hard - -"@babel/plugin-transform-numeric-separator@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-numeric-separator@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 "@babel/plugin-syntax-numeric-separator": ^7.10.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: fcde065002948c9c39f853be99c38b02aa1a1eb453e70ab1a164feb250c1fcbf1edd38071e28ed8bde6840b8a394af8b291b2ab2d793f283872ba43f89cf6dd2 + checksum: 15e2b83292e586fb4f5b4b4021d4821a806ca6de2b77d5ad6c4e07aa7afa23704e31b4d683dac041afc69ac51b2461b96e8c98e46311cc1faba54c73f235044f languageName: node linkType: hard -"@babel/plugin-transform-numeric-separator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-numeric-separator@npm:7.22.5" +"@babel/plugin-transform-object-rest-spread@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.24.5" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-numeric-separator": ^7.10.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 921d6ff2165eb782c28a6c06e9eb0dc17400c9476b000a7f8b8dfa95c122c22be4adee7bc15f035a1e4269842b3a68b0a2f20e4437025a6e0fbe16e479a879b8 - languageName: node - linkType: hard - -"@babel/plugin-transform-object-rest-spread@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-object-rest-spread@npm:7.22.15" - dependencies: - "@babel/compat-data": ^7.22.9 - "@babel/helper-compilation-targets": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-compilation-targets": ^7.23.6 + "@babel/helper-plugin-utils": ^7.24.5 "@babel/plugin-syntax-object-rest-spread": ^7.8.3 - "@babel/plugin-transform-parameters": ^7.22.15 + "@babel/plugin-transform-parameters": ^7.24.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: c485084360607a4392227d8af461e0f313953a6088221826668f90e92df6e16da04e2b3424e283c2980586095430d1068ae6e549b828dfa3891e2d1a397bd034 + checksum: 91d7303af9b5744b8f569c1b8e45c9c9322ded05e7ee94e71b9ff2327f0d2c7b5aa87e040697a6baacc2dcb5c5e5e00913087c36f24c006bdaa4f958fd5bfd2d languageName: node linkType: hard -"@babel/plugin-transform-object-rest-spread@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-object-rest-spread@npm:7.22.5" - dependencies: - "@babel/compat-data": ^7.22.5 - "@babel/helper-compilation-targets": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-object-rest-spread": ^7.8.3 - "@babel/plugin-transform-parameters": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: ab93b8f84e4ed6629ea258d94b597976598a1990035b4d5178c8d117908a48a36f0f03dd2f4a3375393a23a588ecc7817c099ac88a80f8307475b9a25e4d08e0 - languageName: node - linkType: hard - -"@babel/plugin-transform-object-super@npm:^7.10.4": +"@babel/plugin-transform-object-super@npm:^7.10.4, @babel/plugin-transform-object-super@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-object-super@npm:7.24.1" dependencies: @@ -3351,69 +2193,32 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-object-super@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-object-super@npm:7.22.5" +"@babel/plugin-transform-optional-catch-binding@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 062a78ff897c095a71f0db577bd4e4654659d542cb9ef79ec0fda7873ee6fefe31a0cb8a6c2e307e16dacaae1f50d48572184a59e1235b8d9d9cb2f38c4259ce - languageName: node - linkType: hard - -"@babel/plugin-transform-optional-catch-binding@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.22.11" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 6a731f4fee93397634b088ef7de990c150ea1c29e2cf681b2520d9196888d79a4252cbcc497d9b0db0453160ea2267043036fee4ccea8964864ef1b55a40d76f + checksum: 68408b9ef772d9aa5dccf166c86dc4d2505990ce93e03dcfc65c73fb95c2511248e009ba9ccf5b96405fb85de1c16ad8291016b1cc5689ee4becb1e3050e0ae7 languageName: node linkType: hard -"@babel/plugin-transform-optional-catch-binding@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.22.5" +"@babel/plugin-transform-optional-chaining@npm:^7.23.0, @babel/plugin-transform-optional-chaining@npm:^7.24.1, @babel/plugin-transform-optional-chaining@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.5" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: a15bfa5b36f5f1f61521cc1c73e1e394fbd08aef82a416e2e43f5fc7b43830f17d4c9a5605f1b69ed2bbbacd6f49f5e4f9a3e8e0b7a83841bc95e8ef2116f0a9 - languageName: node - linkType: hard - -"@babel/plugin-transform-optional-chaining@npm:^7.22.15, @babel/plugin-transform-optional-chaining@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.23.0" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.5 "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 "@babel/plugin-syntax-optional-chaining": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2bf605b908c75f8d7616e8be52e4656983f2b027032260fbf5279f28297a67a1a28ec3ed60cd5760537dbd08a021246b8092ce06fb2418884390230b807142b3 + checksum: f4e9446ec69f58f40b7843ce7603cfc50332976e6e794d4ddbe6b24670cd50ebc7766c4e3cbaecf0fbb744e98cbfbb54146f4e966314b1d58511b8bbf3d2722b languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - "@babel/plugin-syntax-optional-chaining": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 73c62d707d47a8a483e81700beef9119e8af7290623b8ac2cf4918fadd7286a700c8fdb846e66b0fb795d4dc67c8e60b13dfed3fa2311129c67314bbe173b82a - languageName: node - linkType: hard - -"@babel/plugin-transform-parameters@npm:^7.10.4": +"@babel/plugin-transform-parameters@npm:^7.10.4, @babel/plugin-transform-parameters@npm:^7.20.7, @babel/plugin-transform-parameters@npm:^7.24.5": version: 7.24.5 resolution: "@babel/plugin-transform-parameters@npm:7.24.5" dependencies: @@ -3424,69 +2229,33 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-parameters@npm:^7.12.1, @babel/plugin-transform-parameters@npm:^7.20.7, @babel/plugin-transform-parameters@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-parameters@npm:7.22.5" +"@babel/plugin-transform-private-methods@npm:^7.22.5, @babel/plugin-transform-private-methods@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-private-methods@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.24.1 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 7d6a76dd1ac02373bc5542076c97fadcb18a9ebbcd4047e15f7a83d64efcff2baef1060a4bcfb9372d8ea18e5b1970f09514c58cece4145beb31d8b8d45d2e5f + checksum: d8e18587d2a8b71a795da5e8841b0e64f1525a99ad73ea8b9caa331bc271d69646e2e1e749fd634321f3df9d126070208ddac22a27ccf070566b2efb74fecd99 languageName: node linkType: hard -"@babel/plugin-transform-parameters@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/plugin-transform-parameters@npm:7.22.15" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 9b9faf55b20aea4755a66db75e1195f7a203b4cfeef0ed5ceb25d6364bbb7a5bd0b5c587489c37ab339c4e4e7275406d0db0c05c25aa731a3cf6b4cc51e97c8d - languageName: node - linkType: hard - -"@babel/plugin-transform-private-methods@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-private-methods@npm:7.22.5" - dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: a62f2e47ca30f6b8043201483c5a505e3d54416e6ddfbe7cb696a1db853a4281b1fffee9f883fe26ac72ba02bba0db5832d69e02f2eb4746e9811b8779287cc1 - languageName: node - linkType: hard - -"@babel/plugin-transform-private-property-in-object@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/plugin-transform-private-property-in-object@npm:7.22.11" +"@babel/plugin-transform-private-property-in-object@npm:^7.24.5": + version: 7.24.5 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.24.5" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-create-class-features-plugin": ^7.22.11 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.24.5 + "@babel/helper-plugin-utils": ^7.24.5 "@babel/plugin-syntax-private-property-in-object": ^7.14.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: ec1ed8cc5483b8661e2cf7c020ffefe2a85e793a353d580c4174686923e465cdfaf13fc344ebb2eead4a1dbecd49baba93e342a9de400a29abedb79dcc6745a2 + checksum: de7182bfde298e56c08a5d7ee1156f83c9af8c856bbe2248438848846a4ce544e050666bd0482e16a6006195e8be4923abd14650bef51fa0edd7f82014c2efcd languageName: node linkType: hard -"@babel/plugin-transform-private-property-in-object@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-private-property-in-object@npm:7.22.5" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-create-class-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-private-property-in-object": ^7.14.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: f178191da005d986fdeb30ef74ea0d28878e6225d305d931ce925d87b7df432f5bb29e32173cff2a5c408cee7abc9f25fab09530d4f419ce5cc29a44a89f7a55 - languageName: node - linkType: hard - -"@babel/plugin-transform-property-literals@npm:^7.10.4": +"@babel/plugin-transform-property-literals@npm:^7.10.4, @babel/plugin-transform-property-literals@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-property-literals@npm:7.24.1" dependencies: @@ -3497,25 +2266,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-property-literals@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-property-literals@npm:7.22.5" +"@babel/plugin-transform-react-display-name@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-react-display-name@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 8d25b7b01b5f487cfc1a296555273c1ddad45276f01039130f57eb9ab0fafa0560d10d972323071042e73ac3b8bab596543c9d1a877229624a52e6535084ea51 - languageName: node - linkType: hard - -"@babel/plugin-transform-react-display-name@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-react-display-name@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 41e0167ecd8e5281e427556146b1d3bee8652bcd0664be013f16ffeeb4d61b7ab0b1e59bcc2c923774f0d265f78012628d5277880f758f3675893226f9be012e + checksum: adf1a3cb0df8134533a558a9072a67e34127fd489dfe431c3348a86dd41f3e74861d5d5134bbb68f61a9cdb3f7e79b2acea1346be94ce4d3328a64e5a9e09be1 languageName: node linkType: hard @@ -3530,78 +2288,56 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-jsx-self@npm:^7.18.6, @babel/plugin-transform-react-jsx-self@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-react-jsx-self@npm:7.22.5" +"@babel/plugin-transform-react-jsx-self@npm:^7.18.6, @babel/plugin-transform-react-jsx-self@npm:^7.23.3": + version: 7.24.5 + resolution: "@babel/plugin-transform-react-jsx-self@npm:7.24.5" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 263091bdede1f448cb2c59b84eb69972c15d3f022c929a75337bd20d8b65551ac38cd26dad1946eaa93289643506b10ddaea3445a28cb8fca5a773a22a0df90b + checksum: 66537821496c752bdfc5ef05ed590590aaf87f8b060a3cabe800c0681711bf9dbea57d09cab02c77340f48cb779beeb346f6af775c590aa37159a19026b619c5 languageName: node linkType: hard -"@babel/plugin-transform-react-jsx-self@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-react-jsx-self@npm:7.23.3" +"@babel/plugin-transform-react-jsx-source@npm:^7.19.6, @babel/plugin-transform-react-jsx-source@npm:^7.23.3": + version: 7.24.1 + resolution: "@babel/plugin-transform-react-jsx-source@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 6b586508fc58998483d4ee93a7e784c4f4d2350e2633739cf1990b7ad172e13906f72382fdaf7f07b4e3c7e7555342634d392bdeb1a079bb64762c6368ca9a32 + checksum: ea8e3263c0dc51fbc97c156cc647150a757cc56de10781287353d0ce9b2dcd6b6d93d573c0142d7daf5d6fb554c74fa1971ae60764924ea711161d8458739b63 languageName: node linkType: hard -"@babel/plugin-transform-react-jsx-source@npm:^7.19.6, @babel/plugin-transform-react-jsx-source@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-react-jsx-source@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: defc9debb76b4295e3617ef7795a0533dbbecef6f51bf5ba4bfc162df892a84fd39e14d5f1b9a5aad7b09b97074fef4c6756f9d2036eef5a9874acabe198f75a - languageName: node - linkType: hard - -"@babel/plugin-transform-react-jsx-source@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-react-jsx-source@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: a3aad7cf738e9bfaddc26cdbb83bb9684c2e689d26fb0793d772af0c8da0cd25bb02523d192fbc6946c32143e56b472c1d33fa82466b3f2d3346e1ce8fe83cf6 - languageName: node - linkType: hard - -"@babel/plugin-transform-react-jsx@npm:^7.12.11, @babel/plugin-transform-react-jsx@npm:^7.12.12, @babel/plugin-transform-react-jsx@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-react-jsx@npm:7.22.5" +"@babel/plugin-transform-react-jsx@npm:^7.12.11, @babel/plugin-transform-react-jsx@npm:^7.22.5, @babel/plugin-transform-react-jsx@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-react-jsx@npm:7.23.4" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-module-imports": ^7.22.5 + "@babel/helper-module-imports": ^7.22.15 "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-jsx": ^7.22.5 - "@babel/types": ^7.22.5 + "@babel/plugin-syntax-jsx": ^7.23.3 + "@babel/types": ^7.23.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: fa4e5b32233c41686a420ad97b07a8a8b6cec7d484e93d5917db460887ded5179a8a20867a5d56d962b5452535830c0c0f8bfdc7d55853369be1e51b6a79a14a + checksum: 8851b3adc515cd91bdb06ff3a23a0f81f0069cfef79dfb3fa744da4b7a82e3555ccb6324c4fa71ecf22508db13b9ff6a0ed96675f95fc87903b9fc6afb699580 languageName: node linkType: hard -"@babel/plugin-transform-react-pure-annotations@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.22.5" +"@babel/plugin-transform-react-pure-annotations@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.24.1" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 18db2e2346d79ebe4a3f85f51fa7757a63a09bc6da7f339e6ce9e7534de68b5165fe7d49ac363dee6ba3f81eb904d44bf9c13653331805f9b236a1d9fec7e018 + checksum: 9eb3056fcaadd63d404fd5652b2a3f693bc4758ba753fee5b5c580c7a64346eeeb94e5a4f77a99c76f3cf06d1f1ad6c227647cd0b1219efe3d00cafa5a6e7b2a languageName: node linkType: hard -"@babel/plugin-transform-regenerator@npm:^7.10.4": +"@babel/plugin-transform-regenerator@npm:^7.10.4, @babel/plugin-transform-regenerator@npm:^7.12.1, @babel/plugin-transform-regenerator@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-regenerator@npm:7.24.1" dependencies: @@ -3613,31 +2349,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-regenerator@npm:^7.12.1, @babel/plugin-transform-regenerator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-regenerator@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - regenerator-transform: ^0.15.1 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 5d9f42f831323db7e148cd9c47f61f3f667d283dba95f3221715871f52dec39868be1aa81dd834c27a2993602e5e396bb44bdfa563573a0d86b3883a58660004 - languageName: node - linkType: hard - -"@babel/plugin-transform-regenerator@npm:^7.22.10": - version: 7.22.10 - resolution: "@babel/plugin-transform-regenerator@npm:7.22.10" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - regenerator-transform: ^0.15.2 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: b903bfc1e849ca956a981a199b4913c0998877b6ba759f6d64530c5106610f89a818d61471a9c1bdabb6d94ba4ba150febeb4d196f6a8e67fcdc44207bb8fef6 - languageName: node - linkType: hard - -"@babel/plugin-transform-reserved-words@npm:^7.10.4": +"@babel/plugin-transform-reserved-words@npm:^7.10.4, @babel/plugin-transform-reserved-words@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-reserved-words@npm:7.24.1" dependencies: @@ -3648,34 +2360,23 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-reserved-words@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-reserved-words@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 3ee861941b1d3f9e50f1bb97a2067f33c868b8cd5fd3419a610b2ad5f3afef5f9e4b3740d26a617dc1a9e169a33477821d96b6917c774ea87cac6790d341abbd - languageName: node - linkType: hard - "@babel/plugin-transform-runtime@npm:^7.11.5, @babel/plugin-transform-runtime@npm:^7.12.1, @babel/plugin-transform-runtime@npm:^7.7.6": - version: 7.22.5 - resolution: "@babel/plugin-transform-runtime@npm:7.22.5" + version: 7.24.3 + resolution: "@babel/plugin-transform-runtime@npm:7.24.3" dependencies: - "@babel/helper-module-imports": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - babel-plugin-polyfill-corejs2: ^0.4.3 - babel-plugin-polyfill-corejs3: ^0.8.1 - babel-plugin-polyfill-regenerator: ^0.5.0 - semver: ^6.3.0 + "@babel/helper-module-imports": ^7.24.3 + "@babel/helper-plugin-utils": ^7.24.0 + babel-plugin-polyfill-corejs2: ^0.4.10 + babel-plugin-polyfill-corejs3: ^0.10.1 + babel-plugin-polyfill-regenerator: ^0.6.1 + semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2dcd59bbf14622c2cc088a311a16073b777e34abe733a940c4df6d48fd58900fb7cb22aa2a4645939162cc717618f8e55e96c227ad61f9ae9bca098078aa7345 + checksum: ee01967bf405d84bd95ca4089166a18fb23fe9851a6da53dcf712a7f8ba003319996f21f320d568ec76126e18adfaee978206ccda86eef7652d47cc9a052e75e languageName: node linkType: hard -"@babel/plugin-transform-shorthand-properties@npm:^7.10.4": +"@babel/plugin-transform-shorthand-properties@npm:^7.10.4, @babel/plugin-transform-shorthand-properties@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-shorthand-properties@npm:7.24.1" dependencies: @@ -3686,18 +2387,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-shorthand-properties@npm:^7.12.1, @babel/plugin-transform-shorthand-properties@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-shorthand-properties@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: d2dd6b7033f536dd74569d7343bf3ca88c4bc12575e572a2c5446f42a1ebc8e69cec5e38fc0e63ac7c4a48b944a3225e4317d5db94287b9a5b381a5045c0cdb2 - languageName: node - linkType: hard - -"@babel/plugin-transform-spread@npm:^7.11.0": +"@babel/plugin-transform-spread@npm:^7.11.0, @babel/plugin-transform-spread@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-spread@npm:7.24.1" dependencies: @@ -3709,19 +2399,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-spread@npm:^7.12.1, @babel/plugin-transform-spread@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-spread@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: f8896b00d69557a4aafb3f48b7db6fbaa8462588e733afc4eabfdf79b12a6aed7d20341d160d704205591f0a43d04971d391fa80328f61240d1edc918079a1b0 - languageName: node - linkType: hard - -"@babel/plugin-transform-sticky-regex@npm:^7.10.4": +"@babel/plugin-transform-sticky-regex@npm:^7.10.4, @babel/plugin-transform-sticky-regex@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-sticky-regex@npm:7.24.1" dependencies: @@ -3732,18 +2410,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-sticky-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-sticky-regex@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 42d9295d357415b55c04967ff1cd124cdcbabf2635614f9ad4f8b372d9ae35f6c02bf7473a5418b91e75235960cb1e61493e2c0581cb55bf9719b0986bcd22a5 - languageName: node - linkType: hard - -"@babel/plugin-transform-template-literals@npm:^7.10.4": +"@babel/plugin-transform-template-literals@npm:^7.10.4, @babel/plugin-transform-template-literals@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-template-literals@npm:7.24.1" dependencies: @@ -3754,18 +2421,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-template-literals@npm:^7.12.1, @babel/plugin-transform-template-literals@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-template-literals@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 1fc597716edf9f5c7bc74e2fead4d7751467500486dd17092af90ccbd65c5fc4a1db2e9c86e9ed1a9f206f6a3403bbc07eab50b0c2b8e50f819b4118f2cf71ef - languageName: node - linkType: hard - -"@babel/plugin-transform-typeof-symbol@npm:^7.10.4": +"@babel/plugin-transform-typeof-symbol@npm:^7.10.4, @babel/plugin-transform-typeof-symbol@npm:^7.24.5": version: 7.24.5 resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.5" dependencies: @@ -3776,18 +2432,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-typeof-symbol@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-typeof-symbol@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 277084dd3e873d62541f683173c7cf33b8317f7714335b7e861cc5b4b76f09acbf532a4c9dfbcf7756d29bc07b94b48bd9356af478f424865a86c7d5798be7c0 - languageName: node - linkType: hard - -"@babel/plugin-transform-typescript@npm:^7.18.6": +"@babel/plugin-transform-typescript@npm:^7.18.6, @babel/plugin-transform-typescript@npm:^7.24.1": version: 7.24.5 resolution: "@babel/plugin-transform-typescript@npm:7.24.5" dependencies: @@ -3801,21 +2446,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-typescript@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-typescript@npm:7.22.5" - dependencies: - "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-create-class-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/plugin-syntax-typescript": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 1ee79ead40f8a299dd643d433a514e2bc970f954d27c3a92d62f2139a19128c31d76d094df7e1c1789a70528f349ba536f271a0b47117c77ca49cd26f8b1c66d - languageName: node - linkType: hard - -"@babel/plugin-transform-unicode-escapes@npm:^7.10.4": +"@babel/plugin-transform-unicode-escapes@npm:^7.10.4, @babel/plugin-transform-unicode-escapes@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-unicode-escapes@npm:7.24.1" dependencies: @@ -3826,41 +2457,19 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-unicode-escapes@npm:^7.22.10": - version: 7.22.10 - resolution: "@babel/plugin-transform-unicode-escapes@npm:7.22.10" +"@babel/plugin-transform-unicode-property-regex@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-create-regexp-features-plugin": ^7.22.15 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 68425d56698650087faa33fe40adf8bde32efc1d05ce564f02b62526e7f5b2f4633278b0a10ee2e7e36fb89c79c3330c730d96b8a872acea4702c5645cee98f8 + checksum: d9d9752df7d51bf9357c0bf3762fe16b8c841fca9ecf4409a16f15ccc34be06e8e71abfaee1251b7d451227e70e6b873b36f86b090efdb20f6f7de5fdb6c7a05 languageName: node linkType: hard -"@babel/plugin-transform-unicode-escapes@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-unicode-escapes@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: e9005b2ca102d75e77154a9a7aa2a716d27f5fede04d98fc5f5bfc63390922da9e0112dac0e3c4df9145d30421131a8a79eeb3c6d51435cb7a6595bb692976f7 - languageName: node - linkType: hard - -"@babel/plugin-transform-unicode-property-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.22.5" - dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: da424c1e99af0e920d21f7f121fb9503d0771597a4bd14130fb5f116407be29e9340c049d04733b3d8a132effe4f4585fe3cc9630ae3294a2df9199c8dfd7075 - languageName: node - linkType: hard - -"@babel/plugin-transform-unicode-regex@npm:^7.10.4": +"@babel/plugin-transform-unicode-regex@npm:^7.10.4, @babel/plugin-transform-unicode-regex@npm:^7.24.1": version: 7.24.1 resolution: "@babel/plugin-transform-unicode-regex@npm:7.24.1" dependencies: @@ -3872,27 +2481,15 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-unicode-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-unicode-regex@npm:7.22.5" +"@babel/plugin-transform-unicode-sets-regex@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.24.1" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 4cfaf4bb724a5c55a6fb5b0ee6ebbeba78dc700b9bc0043715d4b37409d90b43c888735c613690a1ec0d8d8e41a500b9d3f0395aa9f55b174449c8407663684b - languageName: node - linkType: hard - -"@babel/plugin-transform-unicode-sets-regex@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.22.5" - dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-create-regexp-features-plugin": ^7.22.15 + "@babel/helper-plugin-utils": ^7.24.0 peerDependencies: "@babel/core": ^7.0.0 - checksum: af37b468332db051f0aaa144adbfab39574e570f613e121b58a551e3cbb7083c9f8c32a83ba2641172a4065128052643468438c19ad098cd62b2d97140dc483e + checksum: b6c1f6b90afeeddf97e5713f72575787fcb7179be7b4c961869bfbc66915f66540dc49da93e4369da15596bd44b896d1eb8a50f5e1fd907abd7a1a625901006b languageName: node linkType: hard @@ -3974,24 +2571,26 @@ __metadata: languageName: node linkType: hard -"@babel/preset-env@npm:^7.11.5, @babel/preset-env@npm:^7.12.11, @babel/preset-env@npm:^7.12.7, @babel/preset-env@npm:^7.7.5": - version: 7.22.5 - resolution: "@babel/preset-env@npm:7.22.5" +"@babel/preset-env@npm:^7.11.5, @babel/preset-env@npm:^7.12.11, @babel/preset-env@npm:^7.12.7, @babel/preset-env@npm:^7.23.2, @babel/preset-env@npm:^7.7.5": + version: 7.24.5 + resolution: "@babel/preset-env@npm:7.24.5" dependencies: - "@babel/compat-data": ^7.22.5 - "@babel/helper-compilation-targets": ^7.22.5 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-option": ^7.22.5 - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.22.5 - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.22.5 + "@babel/compat-data": ^7.24.4 + "@babel/helper-compilation-targets": ^7.23.6 + "@babel/helper-plugin-utils": ^7.24.5 + "@babel/helper-validator-option": ^7.23.5 + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ^7.24.5 + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.24.1 + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.24.1 + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ^7.24.1 "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2 "@babel/plugin-syntax-async-generators": ^7.8.4 "@babel/plugin-syntax-class-properties": ^7.12.13 "@babel/plugin-syntax-class-static-block": ^7.14.5 "@babel/plugin-syntax-dynamic-import": ^7.8.3 "@babel/plugin-syntax-export-namespace-from": ^7.8.3 - "@babel/plugin-syntax-import-assertions": ^7.22.5 - "@babel/plugin-syntax-import-attributes": ^7.22.5 + "@babel/plugin-syntax-import-assertions": ^7.24.1 + "@babel/plugin-syntax-import-attributes": ^7.24.1 "@babel/plugin-syntax-import-meta": ^7.10.4 "@babel/plugin-syntax-json-strings": ^7.8.3 "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 @@ -4003,180 +2602,76 @@ __metadata: "@babel/plugin-syntax-private-property-in-object": ^7.14.5 "@babel/plugin-syntax-top-level-await": ^7.14.5 "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 - "@babel/plugin-transform-arrow-functions": ^7.22.5 - "@babel/plugin-transform-async-generator-functions": ^7.22.5 - "@babel/plugin-transform-async-to-generator": ^7.22.5 - "@babel/plugin-transform-block-scoped-functions": ^7.22.5 - "@babel/plugin-transform-block-scoping": ^7.22.5 - "@babel/plugin-transform-class-properties": ^7.22.5 - "@babel/plugin-transform-class-static-block": ^7.22.5 - "@babel/plugin-transform-classes": ^7.22.5 - "@babel/plugin-transform-computed-properties": ^7.22.5 - "@babel/plugin-transform-destructuring": ^7.22.5 - "@babel/plugin-transform-dotall-regex": ^7.22.5 - "@babel/plugin-transform-duplicate-keys": ^7.22.5 - "@babel/plugin-transform-dynamic-import": ^7.22.5 - "@babel/plugin-transform-exponentiation-operator": ^7.22.5 - "@babel/plugin-transform-export-namespace-from": ^7.22.5 - "@babel/plugin-transform-for-of": ^7.22.5 - "@babel/plugin-transform-function-name": ^7.22.5 - "@babel/plugin-transform-json-strings": ^7.22.5 - "@babel/plugin-transform-literals": ^7.22.5 - "@babel/plugin-transform-logical-assignment-operators": ^7.22.5 - "@babel/plugin-transform-member-expression-literals": ^7.22.5 - "@babel/plugin-transform-modules-amd": ^7.22.5 - "@babel/plugin-transform-modules-commonjs": ^7.22.5 - "@babel/plugin-transform-modules-systemjs": ^7.22.5 - "@babel/plugin-transform-modules-umd": ^7.22.5 + "@babel/plugin-transform-arrow-functions": ^7.24.1 + "@babel/plugin-transform-async-generator-functions": ^7.24.3 + "@babel/plugin-transform-async-to-generator": ^7.24.1 + "@babel/plugin-transform-block-scoped-functions": ^7.24.1 + "@babel/plugin-transform-block-scoping": ^7.24.5 + "@babel/plugin-transform-class-properties": ^7.24.1 + "@babel/plugin-transform-class-static-block": ^7.24.4 + "@babel/plugin-transform-classes": ^7.24.5 + "@babel/plugin-transform-computed-properties": ^7.24.1 + "@babel/plugin-transform-destructuring": ^7.24.5 + "@babel/plugin-transform-dotall-regex": ^7.24.1 + "@babel/plugin-transform-duplicate-keys": ^7.24.1 + "@babel/plugin-transform-dynamic-import": ^7.24.1 + "@babel/plugin-transform-exponentiation-operator": ^7.24.1 + "@babel/plugin-transform-export-namespace-from": ^7.24.1 + "@babel/plugin-transform-for-of": ^7.24.1 + "@babel/plugin-transform-function-name": ^7.24.1 + "@babel/plugin-transform-json-strings": ^7.24.1 + "@babel/plugin-transform-literals": ^7.24.1 + "@babel/plugin-transform-logical-assignment-operators": ^7.24.1 + "@babel/plugin-transform-member-expression-literals": ^7.24.1 + "@babel/plugin-transform-modules-amd": ^7.24.1 + "@babel/plugin-transform-modules-commonjs": ^7.24.1 + "@babel/plugin-transform-modules-systemjs": ^7.24.1 + "@babel/plugin-transform-modules-umd": ^7.24.1 "@babel/plugin-transform-named-capturing-groups-regex": ^7.22.5 - "@babel/plugin-transform-new-target": ^7.22.5 - "@babel/plugin-transform-nullish-coalescing-operator": ^7.22.5 - "@babel/plugin-transform-numeric-separator": ^7.22.5 - "@babel/plugin-transform-object-rest-spread": ^7.22.5 - "@babel/plugin-transform-object-super": ^7.22.5 - "@babel/plugin-transform-optional-catch-binding": ^7.22.5 - "@babel/plugin-transform-optional-chaining": ^7.22.5 - "@babel/plugin-transform-parameters": ^7.22.5 - "@babel/plugin-transform-private-methods": ^7.22.5 - "@babel/plugin-transform-private-property-in-object": ^7.22.5 - "@babel/plugin-transform-property-literals": ^7.22.5 - "@babel/plugin-transform-regenerator": ^7.22.5 - "@babel/plugin-transform-reserved-words": ^7.22.5 - "@babel/plugin-transform-shorthand-properties": ^7.22.5 - "@babel/plugin-transform-spread": ^7.22.5 - "@babel/plugin-transform-sticky-regex": ^7.22.5 - "@babel/plugin-transform-template-literals": ^7.22.5 - "@babel/plugin-transform-typeof-symbol": ^7.22.5 - "@babel/plugin-transform-unicode-escapes": ^7.22.5 - "@babel/plugin-transform-unicode-property-regex": ^7.22.5 - "@babel/plugin-transform-unicode-regex": ^7.22.5 - "@babel/plugin-transform-unicode-sets-regex": ^7.22.5 - "@babel/preset-modules": ^0.1.5 - "@babel/types": ^7.22.5 - babel-plugin-polyfill-corejs2: ^0.4.3 - babel-plugin-polyfill-corejs3: ^0.8.1 - babel-plugin-polyfill-regenerator: ^0.5.0 - core-js-compat: ^3.30.2 - semver: ^6.3.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: dd2b70e96102fc2a64f57c3ab177abeb5aac3f71f47701787b6264d91d7d3ea3d38526d8e1133eb667ca88e87c997ed4a1b8d498ca8be2af07ae4995dfac1b83 - languageName: node - linkType: hard - -"@babel/preset-env@npm:^7.22.9": - version: 7.23.2 - resolution: "@babel/preset-env@npm:7.23.2" - dependencies: - "@babel/compat-data": ^7.23.2 - "@babel/helper-compilation-targets": ^7.22.15 - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-option": ^7.22.15 - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.22.15 - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.22.15 - "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2 - "@babel/plugin-syntax-async-generators": ^7.8.4 - "@babel/plugin-syntax-class-properties": ^7.12.13 - "@babel/plugin-syntax-class-static-block": ^7.14.5 - "@babel/plugin-syntax-dynamic-import": ^7.8.3 - "@babel/plugin-syntax-export-namespace-from": ^7.8.3 - "@babel/plugin-syntax-import-assertions": ^7.22.5 - "@babel/plugin-syntax-import-attributes": ^7.22.5 - "@babel/plugin-syntax-import-meta": ^7.10.4 - "@babel/plugin-syntax-json-strings": ^7.8.3 - "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 - "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 - "@babel/plugin-syntax-numeric-separator": ^7.10.4 - "@babel/plugin-syntax-object-rest-spread": ^7.8.3 - "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 - "@babel/plugin-syntax-optional-chaining": ^7.8.3 - "@babel/plugin-syntax-private-property-in-object": ^7.14.5 - "@babel/plugin-syntax-top-level-await": ^7.14.5 - "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 - "@babel/plugin-transform-arrow-functions": ^7.22.5 - "@babel/plugin-transform-async-generator-functions": ^7.23.2 - "@babel/plugin-transform-async-to-generator": ^7.22.5 - "@babel/plugin-transform-block-scoped-functions": ^7.22.5 - "@babel/plugin-transform-block-scoping": ^7.23.0 - "@babel/plugin-transform-class-properties": ^7.22.5 - "@babel/plugin-transform-class-static-block": ^7.22.11 - "@babel/plugin-transform-classes": ^7.22.15 - "@babel/plugin-transform-computed-properties": ^7.22.5 - "@babel/plugin-transform-destructuring": ^7.23.0 - "@babel/plugin-transform-dotall-regex": ^7.22.5 - "@babel/plugin-transform-duplicate-keys": ^7.22.5 - "@babel/plugin-transform-dynamic-import": ^7.22.11 - "@babel/plugin-transform-exponentiation-operator": ^7.22.5 - "@babel/plugin-transform-export-namespace-from": ^7.22.11 - "@babel/plugin-transform-for-of": ^7.22.15 - "@babel/plugin-transform-function-name": ^7.22.5 - "@babel/plugin-transform-json-strings": ^7.22.11 - "@babel/plugin-transform-literals": ^7.22.5 - "@babel/plugin-transform-logical-assignment-operators": ^7.22.11 - "@babel/plugin-transform-member-expression-literals": ^7.22.5 - "@babel/plugin-transform-modules-amd": ^7.23.0 - "@babel/plugin-transform-modules-commonjs": ^7.23.0 - "@babel/plugin-transform-modules-systemjs": ^7.23.0 - "@babel/plugin-transform-modules-umd": ^7.22.5 - "@babel/plugin-transform-named-capturing-groups-regex": ^7.22.5 - "@babel/plugin-transform-new-target": ^7.22.5 - "@babel/plugin-transform-nullish-coalescing-operator": ^7.22.11 - "@babel/plugin-transform-numeric-separator": ^7.22.11 - "@babel/plugin-transform-object-rest-spread": ^7.22.15 - "@babel/plugin-transform-object-super": ^7.22.5 - "@babel/plugin-transform-optional-catch-binding": ^7.22.11 - "@babel/plugin-transform-optional-chaining": ^7.23.0 - "@babel/plugin-transform-parameters": ^7.22.15 - "@babel/plugin-transform-private-methods": ^7.22.5 - "@babel/plugin-transform-private-property-in-object": ^7.22.11 - "@babel/plugin-transform-property-literals": ^7.22.5 - "@babel/plugin-transform-regenerator": ^7.22.10 - "@babel/plugin-transform-reserved-words": ^7.22.5 - "@babel/plugin-transform-shorthand-properties": ^7.22.5 - "@babel/plugin-transform-spread": ^7.22.5 - "@babel/plugin-transform-sticky-regex": ^7.22.5 - "@babel/plugin-transform-template-literals": ^7.22.5 - "@babel/plugin-transform-typeof-symbol": ^7.22.5 - "@babel/plugin-transform-unicode-escapes": ^7.22.10 - "@babel/plugin-transform-unicode-property-regex": ^7.22.5 - "@babel/plugin-transform-unicode-regex": ^7.22.5 - "@babel/plugin-transform-unicode-sets-regex": ^7.22.5 + "@babel/plugin-transform-new-target": ^7.24.1 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.24.1 + "@babel/plugin-transform-numeric-separator": ^7.24.1 + "@babel/plugin-transform-object-rest-spread": ^7.24.5 + "@babel/plugin-transform-object-super": ^7.24.1 + "@babel/plugin-transform-optional-catch-binding": ^7.24.1 + "@babel/plugin-transform-optional-chaining": ^7.24.5 + "@babel/plugin-transform-parameters": ^7.24.5 + "@babel/plugin-transform-private-methods": ^7.24.1 + "@babel/plugin-transform-private-property-in-object": ^7.24.5 + "@babel/plugin-transform-property-literals": ^7.24.1 + "@babel/plugin-transform-regenerator": ^7.24.1 + "@babel/plugin-transform-reserved-words": ^7.24.1 + "@babel/plugin-transform-shorthand-properties": ^7.24.1 + "@babel/plugin-transform-spread": ^7.24.1 + "@babel/plugin-transform-sticky-regex": ^7.24.1 + "@babel/plugin-transform-template-literals": ^7.24.1 + "@babel/plugin-transform-typeof-symbol": ^7.24.5 + "@babel/plugin-transform-unicode-escapes": ^7.24.1 + "@babel/plugin-transform-unicode-property-regex": ^7.24.1 + "@babel/plugin-transform-unicode-regex": ^7.24.1 + "@babel/plugin-transform-unicode-sets-regex": ^7.24.1 "@babel/preset-modules": 0.1.6-no-external-plugins - "@babel/types": ^7.23.0 - babel-plugin-polyfill-corejs2: ^0.4.6 - babel-plugin-polyfill-corejs3: ^0.8.5 - babel-plugin-polyfill-regenerator: ^0.5.3 + babel-plugin-polyfill-corejs2: ^0.4.10 + babel-plugin-polyfill-corejs3: ^0.10.4 + babel-plugin-polyfill-regenerator: ^0.6.1 core-js-compat: ^3.31.0 semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b5912f09dc92a8f6b93420f3274499e30255af6dbe5673075a30a5bfead1a651e5eb362c6b95e3ba48c6e6bd4e38b7a5aceebba99997ec7c83833e2e6af9abde + checksum: 2cc0edae09205d6409a75d02e53aaa1c590e89adbb7b389019c7b75e4c47b6b63eeb1a816df5c42b672ce410747e7ddc23b6747e8e41a6c95d6fa00c665509e2 languageName: node linkType: hard -"@babel/preset-flow@npm:^7.12.1": - version: 7.22.5 - resolution: "@babel/preset-flow@npm:7.22.5" +"@babel/preset-flow@npm:^7.12.1, @babel/preset-flow@npm:^7.22.15": + version: 7.24.1 + resolution: "@babel/preset-flow@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-option": ^7.22.5 - "@babel/plugin-transform-flow-strip-types": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 + "@babel/helper-validator-option": ^7.23.5 + "@babel/plugin-transform-flow-strip-types": ^7.24.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d3a54fbaa6da304bedc08847876f23c4bd6f9b13eb8b675ae48c45c678066f7610437b16a8972209c5250bdb205bde8800b8055a844922488b899fdbfe295f31 - languageName: node - linkType: hard - -"@babel/preset-flow@npm:^7.13.13": - version: 7.22.15 - resolution: "@babel/preset-flow@npm:7.22.15" - dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-option": ^7.22.15 - "@babel/plugin-transform-flow-strip-types": ^7.22.5 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 7eef0c84ec1889d6c4f7a67d7d1a81703420eed123a8c23f25af148eead77907f0bd701f3e729fdb37d3ddb2a373bf43938b36a9ba17f546111ddb9521466b92 + checksum: e2209158d68a456b8f9d6cd6c810e692f3ab8ca28edba99afcecaacd657ace7cc905e566f84d6da06e537836a2f830bc6ddf4cb34006d57303ff9a40a94fa433 languageName: node linkType: hard @@ -4208,34 +2703,19 @@ __metadata: languageName: node linkType: hard -"@babel/preset-modules@npm:^0.1.5": - version: 0.1.5 - resolution: "@babel/preset-modules@npm:0.1.5" - dependencies: - "@babel/helper-plugin-utils": ^7.0.0 - "@babel/plugin-proposal-unicode-property-regex": ^7.4.4 - "@babel/plugin-transform-dotall-regex": ^7.4.4 - "@babel/types": ^7.4.4 - esutils: ^2.0.2 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: bd90081d96b746c1940dc1ce056dee06ed3a128d20936aee1d1795199f789f9a61293ef738343ae10c6d53970c17285d5e147a945dded35423aacb75083b8a89 - languageName: node - linkType: hard - "@babel/preset-react@npm:^7.12.10, @babel/preset-react@npm:^7.18.6": - version: 7.22.5 - resolution: "@babel/preset-react@npm:7.22.5" + version: 7.24.1 + resolution: "@babel/preset-react@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-option": ^7.22.5 - "@babel/plugin-transform-react-display-name": ^7.22.5 - "@babel/plugin-transform-react-jsx": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 + "@babel/helper-validator-option": ^7.23.5 + "@babel/plugin-transform-react-display-name": ^7.24.1 + "@babel/plugin-transform-react-jsx": ^7.23.4 "@babel/plugin-transform-react-jsx-development": ^7.22.5 - "@babel/plugin-transform-react-pure-annotations": ^7.22.5 + "@babel/plugin-transform-react-pure-annotations": ^7.24.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 60c1fde93d5a6bda03b3d2bb61bcbf056925fd0b01e84d789eaf2a06f639d8714e93735a75da0221fd7a8407c6b4fea7b4fbc35de5ff5d5a299aecb1c82fd530 + checksum: a842abc5a024ed68a0ce4c1244607d40165cb6f8cf1817ebda282e470f20302d81c6a61cb41c1a31aa6c4e99ce93df4dd9e998a8ded1417c25d7480f0e14103a languageName: node linkType: hard @@ -4252,48 +2732,33 @@ __metadata: languageName: node linkType: hard -"@babel/preset-typescript@npm:^7.12.7, @babel/preset-typescript@npm:^7.13.0, @babel/preset-typescript@npm:^7.15.0, @babel/preset-typescript@npm:^7.16.0": - version: 7.22.5 - resolution: "@babel/preset-typescript@npm:7.22.5" +"@babel/preset-typescript@npm:^7.13.0, @babel/preset-typescript@npm:^7.15.0, @babel/preset-typescript@npm:^7.16.0, @babel/preset-typescript@npm:^7.23.0": + version: 7.24.1 + resolution: "@babel/preset-typescript@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-validator-option": ^7.22.5 - "@babel/plugin-syntax-jsx": ^7.22.5 - "@babel/plugin-transform-modules-commonjs": ^7.22.5 - "@babel/plugin-transform-typescript": ^7.22.5 + "@babel/helper-plugin-utils": ^7.24.0 + "@babel/helper-validator-option": ^7.23.5 + "@babel/plugin-syntax-jsx": ^7.24.1 + "@babel/plugin-transform-modules-commonjs": ^7.24.1 + "@babel/plugin-transform-typescript": ^7.24.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2d5924be38bdfea693548359dc547e8bb2c51793d6293168a7248d5ac1f5e94c5f8acea115b006bdd6fa4a20a8e92aa87a826a4aeaf143649e1683d0fe1b82d6 + checksum: 0033dc6fbc898ed0d8017c83a2dd5e095c82909e2f83e48cf9f305e3e9287148758c179ad90f27912cf98ca68bfec3643c57c70c0ca34d3a6c50dc8243aef406 languageName: node linkType: hard -"@babel/register@npm:^7.11.5, @babel/register@npm:^7.12.1, @babel/register@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/register@npm:7.22.5" +"@babel/register@npm:^7.11.5, @babel/register@npm:^7.22.15, @babel/register@npm:^7.23.7": + version: 7.23.7 + resolution: "@babel/register@npm:7.23.7" dependencies: clone-deep: ^4.0.1 find-cache-dir: ^2.0.0 make-dir: ^2.1.0 - pirates: ^4.0.5 + pirates: ^4.0.6 source-map-support: ^0.5.16 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 60b04871442fecb2a296fd3acbbab07e45c3e1c1f7972e72f6c61c575c3a0d95140710c52c4aa7a9b4bb8622641af6da00e3767b8fe17999a1daa1543025fc64 - languageName: node - linkType: hard - -"@babel/register@npm:^7.13.16": - version: 7.22.15 - resolution: "@babel/register@npm:7.22.15" - dependencies: - clone-deep: ^4.0.1 - find-cache-dir: ^2.0.0 - make-dir: ^2.1.0 - pirates: ^4.0.5 - source-map-support: ^0.5.16 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 895cc773c3b3eae909478ea2a9735ef6edd634b04b4aaaad2ce576fd591c2b3c70ff8c90423e769a291bee072186e7e4801480c1907e31ba3053c6cdba5571cb + checksum: b2466e41a4394e725b57e139ba45c3f61b88546d3cb443e84ce46cb34071b60c6cdb706a14c58a1443db530691a54f51da1f0c97f6c1aecbb838a2fb7eb5dbb9 languageName: node linkType: hard @@ -4304,43 +2769,16 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.5.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2, @babel/runtime@npm:^7.9.6": - version: 7.22.5 - resolution: "@babel/runtime@npm:7.22.5" - dependencies: - regenerator-runtime: ^0.13.11 - checksum: 11dcaeecd2246857ccf22f939fcae28a58d29e410607bfa28b95d9b03e298a3e3df8a530e22637d5bfccfc1661fb39cc50c06b404b5d53454bd93889c7dd3eb8 - languageName: node - linkType: hard - -"@babel/runtime@npm:^7.22.10": - version: 7.22.10 - resolution: "@babel/runtime@npm:7.22.10" +"@babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.10, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.8, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2, @babel/runtime@npm:^7.9.6": + version: 7.24.5 + resolution: "@babel/runtime@npm:7.24.5" dependencies: regenerator-runtime: ^0.14.0 - checksum: d3a006fe2cbaf4048b935fb18f55d9ed52c26292182537b442cee57bf524dbb483367c57f464b1a5a96648d9d8d0fdcda848d58a8a09e18ed3f8971dcd684c6c + checksum: 05730e43e8ba6550eae9fd4fb5e7d9d3cb91140379425abcb2a1ff9cebad518a280d82c4c4b0f57ada26a863106ac54a748d90c775790c0e2cd0ddd85ccdf346 languageName: node linkType: hard -"@babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2": - version: 7.23.7 - resolution: "@babel/runtime@npm:7.23.7" - dependencies: - regenerator-runtime: ^0.14.0 - checksum: 3e304133ee55b0750e03e53cb4efb47fb2bdcdb5795f85bbffa10595196c34b9be60eb65bd6d833c87f49fc827f0365f86f95f51d85b188004d3128bb5129c93 - languageName: node - linkType: hard - -"@babel/runtime@npm:^7.23.7, @babel/runtime@npm:^7.23.8": - version: 7.23.9 - resolution: "@babel/runtime@npm:7.23.9" - dependencies: - regenerator-runtime: ^0.14.0 - checksum: e71205fdd7082b2656512cc98e647d9ea7e222e4fe5c36e9e5adc026446fcc3ba7b3cdff8b0b694a0b78bb85db83e7b1e3d4c56ef90726682b74f13249cf952d - languageName: node - linkType: hard - -"@babel/template@npm:^7.12.13, @babel/template@npm:^7.24.0": +"@babel/template@npm:^7.12.13, @babel/template@npm:^7.20.7, @babel/template@npm:^7.22.15, @babel/template@npm:^7.24.0, @babel/template@npm:^7.3.3": version: 7.24.0 resolution: "@babel/template@npm:7.24.0" dependencies: @@ -4351,28 +2789,6 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.12.7, @babel/template@npm:^7.22.5, @babel/template@npm:^7.3.3": - version: 7.22.5 - resolution: "@babel/template@npm:7.22.5" - dependencies: - "@babel/code-frame": ^7.22.5 - "@babel/parser": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: dd8fc1b0bfe0128bace25da0e0a708e26320e8030322d3a53bb6366f199b46a277bfa4281dd370d73ab19087c7e27d166070a0659783b4715f7470448c7342b1 - languageName: node - linkType: hard - -"@babel/template@npm:^7.20.7, @babel/template@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/template@npm:7.22.15" - dependencies: - "@babel/code-frame": ^7.22.13 - "@babel/parser": ^7.22.15 - "@babel/types": ^7.22.15 - checksum: 9312edd37cf1311d738907003f2aa321a88a42ba223c69209abe4d7111db019d321805504f606c7fd75f21c6cf9d24d0a8223104cd21ebd207e241b6c551f454 - languageName: node - linkType: hard - "@babel/traverse@npm:7.23.5": version: 7.23.5 resolution: "@babel/traverse@npm:7.23.5" @@ -4391,25 +2807,7 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.1.0, @babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.12.11, @babel/traverse@npm:^7.12.9, @babel/traverse@npm:^7.13.0, @babel/traverse@npm:^7.22.5, @babel/traverse@npm:^7.7.2": - version: 7.22.5 - resolution: "@babel/traverse@npm:7.22.5" - dependencies: - "@babel/code-frame": ^7.22.5 - "@babel/generator": ^7.22.5 - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-function-name": ^7.22.5 - "@babel/helper-hoist-variables": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.5 - "@babel/parser": ^7.22.5 - "@babel/types": ^7.22.5 - debug: ^4.1.0 - globals: ^11.1.0 - checksum: 0217ec5ece6e4e3b6fd39dc4a23903d2d8ec76a7163731ae51a8cca03a450fb592782d620b8525219a5df9268b22901f3328a23440646d5ec2db4e3952817121 - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.14.2, @babel/traverse@npm:^7.24.5": +"@babel/traverse@npm:^7.1.0, @babel/traverse@npm:^7.14.2, @babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.24.5, @babel/traverse@npm:^7.7.2": version: 7.24.5 resolution: "@babel/traverse@npm:7.24.5" dependencies: @@ -4427,43 +2825,7 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.23.2": - version: 7.23.2 - resolution: "@babel/traverse@npm:7.23.2" - dependencies: - "@babel/code-frame": ^7.22.13 - "@babel/generator": ^7.23.0 - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-function-name": ^7.23.0 - "@babel/helper-hoist-variables": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/parser": ^7.23.0 - "@babel/types": ^7.23.0 - debug: ^4.1.0 - globals: ^11.1.0 - checksum: d096c7c4bab9262a2f658298a3c630ae4a15a10755bb257ae91d5ab3e3b2877438934859c8d34018b7727379fe6b26c4fa2efc81cf4c462a7fe00caf79fa02ff - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.23.7": - version: 7.23.7 - resolution: "@babel/traverse@npm:7.23.7" - dependencies: - "@babel/code-frame": ^7.23.5 - "@babel/generator": ^7.23.6 - "@babel/helper-environment-visitor": ^7.22.20 - "@babel/helper-function-name": ^7.23.0 - "@babel/helper-hoist-variables": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/parser": ^7.23.6 - "@babel/types": ^7.23.6 - debug: ^4.3.1 - globals: ^11.1.0 - checksum: e32fceb4249beec2bde83968ddffe17444221c1ee5cd18c543a2feaf94e3ca83f2a4dfbc2dcca87cf226e0105973e0fe3717063a21e982a9de9945615ab3f3f5 - languageName: node - linkType: hard - -"@babel/types@npm:7.22.5, @babel/types@npm:^7.0.0, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.7, @babel/types@npm:^7.2.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.22.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": +"@babel/types@npm:7.22.5": version: 7.22.5 resolution: "@babel/types@npm:7.22.5" dependencies: @@ -4474,7 +2836,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.11.5, @babel/types@npm:^7.14.2, @babel/types@npm:^7.24.0, @babel/types@npm:^7.24.5": +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.11.5, @babel/types@npm:^7.14.2, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.21.5, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.4, @babel/types@npm:^7.23.5, @babel/types@npm:^7.24.0, @babel/types@npm:^7.24.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": version: 7.24.5 resolution: "@babel/types@npm:7.24.5" dependencies: @@ -4485,28 +2847,6 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.18.9, @babel/types@npm:^7.21.5, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/types@npm:7.23.0" - dependencies: - "@babel/helper-string-parser": ^7.22.5 - "@babel/helper-validator-identifier": ^7.22.20 - to-fast-properties: ^2.0.0 - checksum: 70e4db41acb6793d0eb8d81a2fa88f19ee661219b84bd5f703dbdb54eb3a4d3c0dfc55e69034c945b479df9f43fd4b1376480aaccfc19797ce5af1c5d2576b36 - languageName: node - linkType: hard - -"@babel/types@npm:^7.23.5, @babel/types@npm:^7.23.6": - version: 7.23.6 - resolution: "@babel/types@npm:7.23.6" - dependencies: - "@babel/helper-string-parser": ^7.23.4 - "@babel/helper-validator-identifier": ^7.22.20 - to-fast-properties: ^2.0.0 - checksum: 42cefce8a68bd09bb5828b4764aa5586c53c60128ac2ac012e23858e1c179347a4aac9c66fc577994fbf57595227611c5ec8270bf0cfc94ff033bbfac0550b70 - languageName: node - linkType: hard - "@base2/pretty-print-object@npm:1.0.1": version: 1.0.1 resolution: "@base2/pretty-print-object@npm:1.0.1" @@ -4521,15 +2861,15 @@ __metadata: languageName: node linkType: hard -"@changesets/apply-release-plan@npm:^6.1.4": - version: 6.1.4 - resolution: "@changesets/apply-release-plan@npm:6.1.4" +"@changesets/apply-release-plan@npm:^7.0.0": + version: 7.0.0 + resolution: "@changesets/apply-release-plan@npm:7.0.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/config": ^2.3.1 - "@changesets/get-version-range-type": ^0.3.2 - "@changesets/git": ^2.0.0 - "@changesets/types": ^5.2.1 + "@changesets/config": ^3.0.0 + "@changesets/get-version-range-type": ^0.4.0 + "@changesets/git": ^3.0.0 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 detect-indent: ^6.0.0 fs-extra: ^7.0.1 @@ -4538,30 +2878,30 @@ __metadata: prettier: ^2.7.1 resolve-from: ^5.0.0 semver: ^7.5.3 - checksum: 880f0980965df33875f1152e991fe1b3f54fa3f6c8427d5b8336980fb702ebd7c48a79d24c1a0ff5a5110862e2740dbee2a8f7baef8433b098ab751190f6eb86 + checksum: 5f4c2d6b500d0ade51b31bc03b2475dd0bcaf3a31995f2ad953a6c3b05d3fb588568470bad3093d052f351ecdc6f8e2124d38941210361692b81bf62afbba7d7 languageName: node linkType: hard -"@changesets/assemble-release-plan@npm:^5.2.4": - version: 5.2.4 - resolution: "@changesets/assemble-release-plan@npm:5.2.4" +"@changesets/assemble-release-plan@npm:^6.0.0": + version: 6.0.0 + resolution: "@changesets/assemble-release-plan@npm:6.0.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/errors": ^0.1.4 - "@changesets/get-dependents-graph": ^1.3.6 - "@changesets/types": ^5.2.1 + "@changesets/errors": ^0.2.0 + "@changesets/get-dependents-graph": ^2.0.0 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 semver: ^7.5.3 - checksum: 603299bd6476b05d19c66a0f3236ea87a7cd1082b651ed95e5e68fb8b81120d089c523252eda09a4f0faf51755789f96ac5086b96198548c5e84fd5ca8644bbb + checksum: 7ccff4dba07fd5c7d219b69d6f5e5ec4ea942b3f3482a76be6f9caa072ae5b2128b4d6c561030cb488ca1bc23416a2f8f638daa784f4ae9792c89c9b571231b3 languageName: node linkType: hard -"@changesets/changelog-git@npm:^0.1.14": - version: 0.1.14 - resolution: "@changesets/changelog-git@npm:0.1.14" +"@changesets/changelog-git@npm:^0.2.0": + version: 0.2.0 + resolution: "@changesets/changelog-git@npm:0.2.0" dependencies: - "@changesets/types": ^5.2.1 - checksum: 0d97b789fc68710e30265721ca1454c1038f701c756dac5a500035e6faea27b3755ffd2167f556684bf7bd4d3cebb5cfeefa5dcb322615503afad01b85d8dc31 + "@changesets/types": ^6.0.0 + checksum: d94df555656ac4ac9698d87a173b1955227ac0f1763d59b9b4d4f149ab3f879ca67603e48407b1dfdadaef4e7882ae7bbc7b7be160a45a55f05442004bdc61bd languageName: node linkType: hard @@ -4577,33 +2917,32 @@ __metadata: linkType: hard "@changesets/cli@npm:^2.26.0": - version: 2.26.2 - resolution: "@changesets/cli@npm:2.26.2" + version: 2.27.1 + resolution: "@changesets/cli@npm:2.27.1" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/apply-release-plan": ^6.1.4 - "@changesets/assemble-release-plan": ^5.2.4 - "@changesets/changelog-git": ^0.1.14 - "@changesets/config": ^2.3.1 - "@changesets/errors": ^0.1.4 - "@changesets/get-dependents-graph": ^1.3.6 - "@changesets/get-release-plan": ^3.0.17 - "@changesets/git": ^2.0.0 - "@changesets/logger": ^0.0.5 - "@changesets/pre": ^1.0.14 - "@changesets/read": ^0.5.9 - "@changesets/types": ^5.2.1 - "@changesets/write": ^0.2.3 + "@changesets/apply-release-plan": ^7.0.0 + "@changesets/assemble-release-plan": ^6.0.0 + "@changesets/changelog-git": ^0.2.0 + "@changesets/config": ^3.0.0 + "@changesets/errors": ^0.2.0 + "@changesets/get-dependents-graph": ^2.0.0 + "@changesets/get-release-plan": ^4.0.0 + "@changesets/git": ^3.0.0 + "@changesets/logger": ^0.1.0 + "@changesets/pre": ^2.0.0 + "@changesets/read": ^0.6.0 + "@changesets/types": ^6.0.0 + "@changesets/write": ^0.3.0 "@manypkg/get-packages": ^1.1.3 - "@types/is-ci": ^3.0.0 "@types/semver": ^7.5.0 ansi-colors: ^4.1.3 chalk: ^2.1.0 + ci-info: ^3.7.0 enquirer: ^2.3.0 external-editor: ^3.1.0 fs-extra: ^7.0.1 human-id: ^1.0.2 - is-ci: ^3.0.1 meow: ^6.0.0 outdent: ^0.5.0 p-limit: ^2.2.0 @@ -4615,44 +2954,44 @@ __metadata: tty-table: ^4.1.5 bin: changeset: bin.js - checksum: 4f08d87b095ac98660158adc4b676ce0473d0b1126b2fb2568d984981a29434850e7af85627a2fe88386c2b5c16eb7bd44c65434a51d559bb856a3efe2f5fc90 + checksum: c7adc35f22983be9b0f6a8e4c3bc7013208ddf341b637530b88267e78469f0b7af9e36b138bea9f2fe29bb7b44294cd08aa0301a5cba0c6a928824f11d024e04 languageName: node linkType: hard -"@changesets/config@npm:^2.3.1": - version: 2.3.1 - resolution: "@changesets/config@npm:2.3.1" +"@changesets/config@npm:^3.0.0": + version: 3.0.0 + resolution: "@changesets/config@npm:3.0.0" dependencies: - "@changesets/errors": ^0.1.4 - "@changesets/get-dependents-graph": ^1.3.6 - "@changesets/logger": ^0.0.5 - "@changesets/types": ^5.2.1 + "@changesets/errors": ^0.2.0 + "@changesets/get-dependents-graph": ^2.0.0 + "@changesets/logger": ^0.1.0 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 fs-extra: ^7.0.1 micromatch: ^4.0.2 - checksum: 718944f63279222f41c81f544cce5628d689cb67e871297483d93a811625e66083400d3166e506cd24260e5b08275f054e4427ee05a2f2070895bcf27ab89ba2 + checksum: c64463a92b99986e42657c3b8804851aab8b592bb64532177ce35769a7fedfad3ce1395ad0e2ab3e357e3029fd23333bff1ce51bc3634e6f43223724398639d3 languageName: node linkType: hard -"@changesets/errors@npm:^0.1.4": - version: 0.1.4 - resolution: "@changesets/errors@npm:0.1.4" +"@changesets/errors@npm:^0.2.0": + version: 0.2.0 + resolution: "@changesets/errors@npm:0.2.0" dependencies: extendable-error: ^0.1.5 - checksum: 21bec4e599a6833e03e0037f1cb9605c36490615db0741bd6b81063e7f2d98f0e2bdf86109ff519934888581bc77ebf7b2a7554040b10f40b71f55b766048747 + checksum: f2757c752ab04e9733b0dfd7903f1caf873f9e603794c4d9ea2294af4f937c73d07273c24be864ad0c30b6a98424360d5b96a6eab14f97f3cf2cbfd3763b95c1 languageName: node linkType: hard -"@changesets/get-dependents-graph@npm:^1.3.6": - version: 1.3.6 - resolution: "@changesets/get-dependents-graph@npm:1.3.6" +"@changesets/get-dependents-graph@npm:^2.0.0": + version: 2.0.0 + resolution: "@changesets/get-dependents-graph@npm:2.0.0" dependencies: - "@changesets/types": ^5.2.1 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 chalk: ^2.1.0 fs-extra: ^7.0.1 semver: ^7.5.3 - checksum: 0ce46b7a99aa689740e58bb9692f574d25077c012f38eb67002bc7da83c3ceb77906f51de659d868d07a9abf84fa405cef31a5177af57434fab7b000b1ed0118 + checksum: 68ac8f7f0b7b6f671b9809541238798aebe9250b083f6d9dace1305c436b565a71634412e83f642c6b21ed8656f4d548c92f583d2f4c6bf7a8665f6dddf14309 languageName: node linkType: hard @@ -4666,88 +3005,88 @@ __metadata: languageName: node linkType: hard -"@changesets/get-release-plan@npm:^3.0.17": - version: 3.0.17 - resolution: "@changesets/get-release-plan@npm:3.0.17" +"@changesets/get-release-plan@npm:^4.0.0": + version: 4.0.0 + resolution: "@changesets/get-release-plan@npm:4.0.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/assemble-release-plan": ^5.2.4 - "@changesets/config": ^2.3.1 - "@changesets/pre": ^1.0.14 - "@changesets/read": ^0.5.9 - "@changesets/types": ^5.2.1 + "@changesets/assemble-release-plan": ^6.0.0 + "@changesets/config": ^3.0.0 + "@changesets/pre": ^2.0.0 + "@changesets/read": ^0.6.0 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 - checksum: cbc9f804d30c9ec30ca3bd71eb2f3e811a12dc1399abc70fc33fd420a749f75b27eaf866893fd047326db02aba7e9e644537cdc202d2481bf4ee11663b39494d + checksum: d77140ca1d45a6e70c3ed8a3859986a7d1ae40c015a8ca85910acec6455e333311c78e3664d9cee02ed540020f7bacde1846d3cff58ec2ffd64edd55bf8a114b languageName: node linkType: hard -"@changesets/get-version-range-type@npm:^0.3.2": - version: 0.3.2 - resolution: "@changesets/get-version-range-type@npm:0.3.2" - checksum: a32c84cd6e5cdf746b9dde09aac9943141141af3be44c61433c45df0e57da348cd26c257b149f200caedb861a78349ac77130ea40e18a84f2ac68283045979e3 +"@changesets/get-version-range-type@npm:^0.4.0": + version: 0.4.0 + resolution: "@changesets/get-version-range-type@npm:0.4.0" + checksum: e466208c8383489a383f37958d8b5b9aed38539f9287b47fe155a2e8855973f6960fb1724a1ee33b11580d65e1011059045ee654e8ef51e4783017d8989c9d3f languageName: node linkType: hard -"@changesets/git@npm:^2.0.0": - version: 2.0.0 - resolution: "@changesets/git@npm:2.0.0" +"@changesets/git@npm:^3.0.0": + version: 3.0.0 + resolution: "@changesets/git@npm:3.0.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/errors": ^0.1.4 - "@changesets/types": ^5.2.1 + "@changesets/errors": ^0.2.0 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 is-subdir: ^1.1.1 micromatch: ^4.0.2 spawndamnit: ^2.0.0 - checksum: 0f5eb05a062feb8b5877cb90d2463f5cb816c0d39151f5f7be970a2118b2925dae3646ee0f9cffa86a819902b04d86f9150dbde9a071e9aff89fa17cc5628037 + checksum: 75b0ce2d8c52c8141a2d07be1cc05da15463d6f93a8a95351e171c6c3d48345b3134f33bfeb695a11467adbcc51ff3d87487995a61fba99af89063eac4a8ce7a languageName: node linkType: hard -"@changesets/logger@npm:^0.0.5": - version: 0.0.5 - resolution: "@changesets/logger@npm:0.0.5" +"@changesets/logger@npm:^0.1.0": + version: 0.1.0 + resolution: "@changesets/logger@npm:0.1.0" dependencies: chalk: ^2.1.0 - checksum: a4659a86c97e4f0ba5844168d0c8a5fb3f8d8a6b81fcdc986919eef338ea8c847140b30649d860b35a2c06f6fe584c10cfb78e25153977485e9d18d2c6d4b06a + checksum: b40365a4e62be4bf7a75c5900e8f95b1abd8fb9ff9f2cf71a7b567532377ddd5490b0ee1d566189a91e8c8250c9e875d333cfb3e44a34c230a11fd61337f923e languageName: node linkType: hard -"@changesets/parse@npm:^0.3.16": - version: 0.3.16 - resolution: "@changesets/parse@npm:0.3.16" +"@changesets/parse@npm:^0.4.0": + version: 0.4.0 + resolution: "@changesets/parse@npm:0.4.0" dependencies: - "@changesets/types": ^5.2.1 + "@changesets/types": ^6.0.0 js-yaml: ^3.13.1 - checksum: 4fa076ef5ae856b54e62c57b2fae18482ab42a41cc70e059db1f6dade4e28ee796e5b9226af78e975bc9fb004748de5e09947da308fdd1d8bebc887c76f68054 + checksum: 8e76f8540aceb2263eb76c97f027c1990fc069bf275321ad0aabf843cb51bc6711b13118eda35c701a30a36d26f48e75f7afc14e9a5c863f8a98091021fd5d61 languageName: node linkType: hard -"@changesets/pre@npm:^1.0.14": - version: 1.0.14 - resolution: "@changesets/pre@npm:1.0.14" +"@changesets/pre@npm:^2.0.0": + version: 2.0.0 + resolution: "@changesets/pre@npm:2.0.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/errors": ^0.1.4 - "@changesets/types": ^5.2.1 + "@changesets/errors": ^0.2.0 + "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 fs-extra: ^7.0.1 - checksum: 4030c4dc6ec93d97aecccc1c9526e0affc7b65ccac513777a3ead3414e3aa24c71b634be4c9ca71e56b56cb6bef4158b57cf8ce62c893f13837ac08ef199e024 + checksum: 3971fb9b3f8b1719a983b82fcd34aab573151d0765ff38ae44f31d66d040ca40d33e80808b3694ae40331ebf6d654d479352c3bc0a964ad553200ebf5d1ec44f languageName: node linkType: hard -"@changesets/read@npm:^0.5.9": - version: 0.5.9 - resolution: "@changesets/read@npm:0.5.9" +"@changesets/read@npm:^0.6.0": + version: 0.6.0 + resolution: "@changesets/read@npm:0.6.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/git": ^2.0.0 - "@changesets/logger": ^0.0.5 - "@changesets/parse": ^0.3.16 - "@changesets/types": ^5.2.1 + "@changesets/git": ^3.0.0 + "@changesets/logger": ^0.1.0 + "@changesets/parse": ^0.4.0 + "@changesets/types": ^6.0.0 chalk: ^2.1.0 fs-extra: ^7.0.1 p-filter: ^2.1.0 - checksum: deb70f5e21ed5f6618fb79f16f19ccbbec38379613aa960f7c67133f73d3b8ef163b335d07b9d0658a46c9f615199322ab187d0693387791def2db75bf51ca2c + checksum: ec2914fb89de923145a3482e00a2930b011c9c7a7c5690b053e344e8e8941ab06087bd3fe3b6cc01a651656c0438b5f9b96c616c7df1ad146f87b8751701bf5a languageName: node linkType: hard @@ -4765,16 +3104,23 @@ __metadata: languageName: node linkType: hard -"@changesets/write@npm:^0.2.3": - version: 0.2.3 - resolution: "@changesets/write@npm:0.2.3" +"@changesets/types@npm:^6.0.0": + version: 6.0.0 + resolution: "@changesets/types@npm:6.0.0" + checksum: e755f208792547e3b9ece15ce4da22466267da810c6fd87d927a1b8cec4d7fb7f0eea0d1a7585747676238e3e4ba1ffdabe016ccb05cfa537b4e4b03ec399f41 + languageName: node + linkType: hard + +"@changesets/write@npm:^0.3.0": + version: 0.3.0 + resolution: "@changesets/write@npm:0.3.0" dependencies: "@babel/runtime": ^7.20.1 - "@changesets/types": ^5.2.1 + "@changesets/types": ^6.0.0 fs-extra: ^7.0.1 human-id: ^1.0.2 prettier: ^2.7.1 - checksum: 24b7e0258421897a946275093b616529b12fe470aa785f088fb89c5844a5e41916abdbee0909b088e1e204e94725f2482c589ea80c14398e46b1723aee0bbbb4 + checksum: 537f419d854946cce5694696b6a48ffee0ea1f7b5c97c5246836931886db18153c42a7dea1e74b0e8bf571fcded527e2f443ab362fdb1e4129bd95a61b2d0fe5 languageName: node linkType: hard @@ -4797,7 +3143,7 @@ __metadata: languageName: node linkType: hard -"@colors/colors@npm:^1.6.0": +"@colors/colors@npm:1.6.0, @colors/colors@npm:^1.6.0": version: 1.6.0 resolution: "@colors/colors@npm:1.6.0" checksum: 9328a0778a5b0db243af54455b79a69e3fb21122d6c15ef9e9fcc94881d8d17352d8b2b2590f9bdd46fac5c2d6c1636dcfc14358a20c70e22daf89e1a759b629 @@ -4889,22 +3235,6 @@ __metadata: languageName: node linkType: hard -"@emotion/is-prop-valid@npm:^0.8.2": - version: 0.8.8 - resolution: "@emotion/is-prop-valid@npm:0.8.8" - dependencies: - "@emotion/memoize": 0.7.4 - checksum: f6be625f067c7fa56a12a4edaf090715616dc4fc7803c87212831f38c969350107b9709b1be54100e53153b18d9fa068eb4bf4f9ac66a37a8edf1bac9b64e279 - languageName: node - linkType: hard - -"@emotion/memoize@npm:0.7.4": - version: 0.7.4 - resolution: "@emotion/memoize@npm:0.7.4" - checksum: b2376548fc147b43afd1ff005a80a1a025bd7eb4fb759fdb23e96e5ff290ee8ba16628a332848d600fb91c3cdc319eee5395fa33d8875e5d5a8c4ce18cddc18e - languageName: node - linkType: hard - "@emotion/memoize@npm:^0.8.1": version: 0.8.1 resolution: "@emotion/memoize@npm:0.8.1" @@ -4912,10 +3242,10 @@ __metadata: languageName: node linkType: hard -"@emotion/unitless@npm:0.8.0": - version: 0.8.0 - resolution: "@emotion/unitless@npm:0.8.0" - checksum: 1f2cfb7c0ccb83c20b1c6d8d92a74a93da4b2a440f9a0d49ded08647faf299065a2ffde17e1335920fa10397b85f8635bbfe14f3cd29222a59ea81d978478072 +"@emotion/unitless@npm:0.8.1": + version: 0.8.1 + resolution: "@emotion/unitless@npm:0.8.1" + checksum: a1ed508628288f40bfe6dd17d431ed899c067a899fa293a13afe3aed1d70fac0412b8a215fafab0b42829360db687fecd763e5f01a64ddc4a4b58ec3112ff548 languageName: node linkType: hard @@ -4928,20 +3258,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/aix-ppc64@npm:0.19.11" +"@esbuild/aix-ppc64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/aix-ppc64@npm:0.19.12" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/android-arm64@npm:0.17.19" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/android-arm64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/android-arm64@npm:0.18.20" @@ -4949,20 +3272,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/android-arm64@npm:0.19.11" +"@esbuild/android-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/android-arm64@npm:0.19.12" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/android-arm@npm:0.17.19" - conditions: os=android & cpu=arm - languageName: node - linkType: hard - "@esbuild/android-arm@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/android-arm@npm:0.18.20" @@ -4970,20 +3286,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/android-arm@npm:0.19.11" +"@esbuild/android-arm@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/android-arm@npm:0.19.12" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/android-x64@npm:0.17.19" - conditions: os=android & cpu=x64 - languageName: node - linkType: hard - "@esbuild/android-x64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/android-x64@npm:0.18.20" @@ -4991,20 +3300,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-x64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/android-x64@npm:0.19.11" +"@esbuild/android-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/android-x64@npm:0.19.12" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/darwin-arm64@npm:0.17.19" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/darwin-arm64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/darwin-arm64@npm:0.18.20" @@ -5012,20 +3314,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/darwin-arm64@npm:0.19.11" +"@esbuild/darwin-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/darwin-arm64@npm:0.19.12" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/darwin-x64@npm:0.17.19" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - "@esbuild/darwin-x64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/darwin-x64@npm:0.18.20" @@ -5033,20 +3328,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/darwin-x64@npm:0.19.11" +"@esbuild/darwin-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/darwin-x64@npm:0.19.12" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/freebsd-arm64@npm:0.17.19" - conditions: os=freebsd & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/freebsd-arm64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/freebsd-arm64@npm:0.18.20" @@ -5054,20 +3342,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/freebsd-arm64@npm:0.19.11" +"@esbuild/freebsd-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/freebsd-arm64@npm:0.19.12" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/freebsd-x64@npm:0.17.19" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - "@esbuild/freebsd-x64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/freebsd-x64@npm:0.18.20" @@ -5075,20 +3356,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/freebsd-x64@npm:0.19.11" +"@esbuild/freebsd-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/freebsd-x64@npm:0.19.12" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-arm64@npm:0.17.19" - conditions: os=linux & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/linux-arm64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/linux-arm64@npm:0.18.20" @@ -5096,20 +3370,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/linux-arm64@npm:0.19.11" +"@esbuild/linux-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-arm64@npm:0.19.12" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-arm@npm:0.17.19" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - "@esbuild/linux-arm@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/linux-arm@npm:0.18.20" @@ -5117,20 +3384,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/linux-arm@npm:0.19.11" +"@esbuild/linux-arm@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-arm@npm:0.19.12" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-ia32@npm:0.17.19" - conditions: os=linux & cpu=ia32 - languageName: node - linkType: hard - "@esbuild/linux-ia32@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/linux-ia32@npm:0.18.20" @@ -5138,20 +3398,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/linux-ia32@npm:0.19.11" +"@esbuild/linux-ia32@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-ia32@npm:0.19.12" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-loong64@npm:0.17.19" - conditions: os=linux & cpu=loong64 - languageName: node - linkType: hard - "@esbuild/linux-loong64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/linux-loong64@npm:0.18.20" @@ -5159,20 +3412,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/linux-loong64@npm:0.19.11" +"@esbuild/linux-loong64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-loong64@npm:0.19.12" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-mips64el@npm:0.17.19" - conditions: os=linux & cpu=mips64el - languageName: node - linkType: hard - "@esbuild/linux-mips64el@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/linux-mips64el@npm:0.18.20" @@ -5180,20 +3426,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/linux-mips64el@npm:0.19.11" +"@esbuild/linux-mips64el@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-mips64el@npm:0.19.12" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-ppc64@npm:0.17.19" - conditions: os=linux & cpu=ppc64 - languageName: node - linkType: hard - "@esbuild/linux-ppc64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/linux-ppc64@npm:0.18.20" @@ -5201,20 +3440,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/linux-ppc64@npm:0.19.11" +"@esbuild/linux-ppc64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-ppc64@npm:0.19.12" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-riscv64@npm:0.17.19" - conditions: os=linux & cpu=riscv64 - languageName: node - linkType: hard - "@esbuild/linux-riscv64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/linux-riscv64@npm:0.18.20" @@ -5222,20 +3454,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/linux-riscv64@npm:0.19.11" +"@esbuild/linux-riscv64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-riscv64@npm:0.19.12" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-s390x@npm:0.17.19" - conditions: os=linux & cpu=s390x - languageName: node - linkType: hard - "@esbuild/linux-s390x@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/linux-s390x@npm:0.18.20" @@ -5243,20 +3468,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/linux-s390x@npm:0.19.11" +"@esbuild/linux-s390x@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-s390x@npm:0.19.12" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-x64@npm:0.17.19" - conditions: os=linux & cpu=x64 - languageName: node - linkType: hard - "@esbuild/linux-x64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/linux-x64@npm:0.18.20" @@ -5264,20 +3482,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/linux-x64@npm:0.19.11" +"@esbuild/linux-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-x64@npm:0.19.12" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/netbsd-x64@npm:0.17.19" - conditions: os=netbsd & cpu=x64 - languageName: node - linkType: hard - "@esbuild/netbsd-x64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/netbsd-x64@npm:0.18.20" @@ -5285,20 +3496,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/netbsd-x64@npm:0.19.11" +"@esbuild/netbsd-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/netbsd-x64@npm:0.19.12" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/openbsd-x64@npm:0.17.19" - conditions: os=openbsd & cpu=x64 - languageName: node - linkType: hard - "@esbuild/openbsd-x64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/openbsd-x64@npm:0.18.20" @@ -5306,20 +3510,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/openbsd-x64@npm:0.19.11" +"@esbuild/openbsd-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/openbsd-x64@npm:0.19.12" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/sunos-x64@npm:0.17.19" - conditions: os=sunos & cpu=x64 - languageName: node - linkType: hard - "@esbuild/sunos-x64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/sunos-x64@npm:0.18.20" @@ -5327,20 +3524,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/sunos-x64@npm:0.19.11" +"@esbuild/sunos-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/sunos-x64@npm:0.19.12" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/win32-arm64@npm:0.17.19" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - "@esbuild/win32-arm64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/win32-arm64@npm:0.18.20" @@ -5348,20 +3538,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/win32-arm64@npm:0.19.11" +"@esbuild/win32-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/win32-arm64@npm:0.19.12" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/win32-ia32@npm:0.17.19" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - "@esbuild/win32-ia32@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/win32-ia32@npm:0.18.20" @@ -5369,20 +3552,13 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/win32-ia32@npm:0.19.11" +"@esbuild/win32-ia32@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/win32-ia32@npm:0.19.12" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/win32-x64@npm:0.17.19" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - "@esbuild/win32-x64@npm:0.18.20": version: 0.18.20 resolution: "@esbuild/win32-x64@npm:0.18.20" @@ -5390,9 +3566,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.19.11": - version: 0.19.11 - resolution: "@esbuild/win32-x64@npm:0.19.11" +"@esbuild/win32-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/win32-x64@npm:0.19.12" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -5408,13 +3584,6 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.4.0": - version: 4.5.1 - resolution: "@eslint-community/regexpp@npm:4.5.1" - checksum: d79cbd99cc4dcfbb17e8dd30a30bb5aec5da9c60b9471043f886f116615bb15f0d417cb0ca638cefedba0b4c67c339e2011b53d88264a4540775f042a5879e01 - languageName: node - linkType: hard - "@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": version: 4.10.0 resolution: "@eslint-community/regexpp@npm:4.10.0" @@ -5439,23 +3608,6 @@ __metadata: languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.1.0": - version: 2.1.0 - resolution: "@eslint/eslintrc@npm:2.1.0" - dependencies: - ajv: ^6.12.4 - debug: ^4.3.2 - espree: ^9.6.0 - globals: ^13.19.0 - ignore: ^5.2.0 - import-fresh: ^3.2.1 - js-yaml: ^4.1.0 - minimatch: ^3.1.2 - strip-json-comments: ^3.1.1 - checksum: 6ffbc3e7867b377754492539af0e2f5b55645a2c67279a70508fe09080bc76d49ba64b579e59a2a04014f84d0768301736fbcdd94c7b3ad4f0e648c32bf21e43 - languageName: node - linkType: hard - "@eslint/eslintrc@npm:^2.1.4": version: 2.1.4 resolution: "@eslint/eslintrc@npm:2.1.4" @@ -5473,13 +3625,6 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:8.44.0": - version: 8.44.0 - resolution: "@eslint/js@npm:8.44.0" - checksum: ce7b966f8804228e4d5725d44d3c8fb7fc427176f077401323a02e082f628d207133a25704330e610ebe3254fdf1acb186f779d1242fd145a758fdcc4486a660 - languageName: node - linkType: hard - "@eslint/js@npm:8.57.0": version: 8.57.0 resolution: "@eslint/js@npm:8.57.0" @@ -5488,9 +3633,9 @@ __metadata: linkType: hard "@exodus/schemasafe@npm:^1.0.0-rc.2": - version: 1.0.1 - resolution: "@exodus/schemasafe@npm:1.0.1" - checksum: bf1c86034c33e86cd7c0c614648f1ed4864ecb339b419d2c25021e61bc327875ae5e73813b162348962d54a71f4c55170784d60987112770a3b90a9bcd504e18 + version: 1.3.0 + resolution: "@exodus/schemasafe@npm:1.3.0" + checksum: e19397c14db76342154c32a9088536149babfd9b18ecae815add0b2f911d9aa292aa51c6ab33b857b4b6bb371a74ebde845e6f17b2824e73b4e307230f23f86a languageName: node linkType: hard @@ -5502,66 +3647,50 @@ __metadata: linkType: hard "@floating-ui/core@npm:^1.0.0": - version: 1.6.0 - resolution: "@floating-ui/core@npm:1.6.0" + version: 1.6.1 + resolution: "@floating-ui/core@npm:1.6.1" dependencies: - "@floating-ui/utils": ^0.2.1 - checksum: 667a68036f7dd5ed19442c7792a6002ca02d1799221c4396691bbe0b6008b48f6ccad581225e81fa266bb91232f6c66838a5f825f554217e1ec886178b93381b - languageName: node - linkType: hard - -"@floating-ui/core@npm:^1.3.1": - version: 1.3.1 - resolution: "@floating-ui/core@npm:1.3.1" - checksum: 894bc3637c03beda184a4460cb53155fd30c2a0956569e1c714b7df9e3439517b1c34ad9a8114ea15a6c08d1e3f1d40741d259f0f1087fc3ea96fae7dfeb697e + "@floating-ui/utils": ^0.2.0 + checksum: 7d78b3788d438807d3c1a52477ee1693a29b8a4416dd6e13761427925d9fba1d45c849527752d8fd9776842182d919fddf7ecbc34f3bf2de3bafa1717619a56f languageName: node linkType: hard "@floating-ui/dom@npm:^1.0.0": - version: 1.6.3 - resolution: "@floating-ui/dom@npm:1.6.3" + version: 1.6.5 + resolution: "@floating-ui/dom@npm:1.6.5" dependencies: "@floating-ui/core": ^1.0.0 "@floating-ui/utils": ^0.2.0 - checksum: d6cac10877918ce5a8d1a24b21738d2eb130a0191043d7c0dd43bccac507844d3b4dc5d4107d3891d82f6007945ca8fb4207a1252506e91c37e211f0f73cf77e - languageName: node - linkType: hard - -"@floating-ui/dom@npm:^1.3.0": - version: 1.4.3 - resolution: "@floating-ui/dom@npm:1.4.3" - dependencies: - "@floating-ui/core": ^1.3.1 - checksum: 2e649d1e2ffb4edfeadab0ab2c2e2a8424df1d9cdb798d5a09ccc8a65b93574449bdb0d25991773a859c9de70b181b596777e61e6581bf942bdef7fc6d18867a + checksum: ebdc14806f786e60df8e7cc2c30bf9cd4d75fe734f06d755588bbdef2f60d0a0f21dffb14abdc58dea96e5577e2e366feca6d66ba962018efd1bc91a3ece4526 languageName: node linkType: hard "@floating-ui/react-dom@npm:^2.0.0": - version: 2.0.1 - resolution: "@floating-ui/react-dom@npm:2.0.1" + version: 2.0.9 + resolution: "@floating-ui/react-dom@npm:2.0.9" dependencies: - "@floating-ui/dom": ^1.3.0 + "@floating-ui/dom": ^1.0.0 peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 856c0c9de0a9117bcc69b1363fd9fa188133b9714394609db937903ab4330e9851becfd2a83453f40834de1a18377caf329b6b71afc1c69d7c5687f87da80ed4 + checksum: d8cd1fb2b8a5012ca692d6f677a0af923ef81131f69accea8ce8b5413202ab4c3c79e6eda1446f4dad06a2dfd596ece748c562ba28c289678a856755db4f528f languageName: node linkType: hard -"@floating-ui/utils@npm:^0.2.0, @floating-ui/utils@npm:^0.2.1": - version: 0.2.1 - resolution: "@floating-ui/utils@npm:0.2.1" - checksum: ee77756712cf5b000c6bacf11992ffb364f3ea2d0d51cc45197a7e646a17aeb86ea4b192c0b42f3fbb29487aee918a565e84f710b8c3645827767f406a6b4cc9 +"@floating-ui/utils@npm:^0.2.0": + version: 0.2.2 + resolution: "@floating-ui/utils@npm:0.2.2" + checksum: b2becdcafdf395af1641348da0031ff1eaad2bc60c22e14bd3abad4acfe2c8401e03097173d89a2f646a99b75819a78ef21ebb2572cab0042a56dd654b0065cd languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:1.17.0": - version: 1.17.0 - resolution: "@formatjs/ecma402-abstract@npm:1.17.0" +"@formatjs/ecma402-abstract@npm:1.18.2": + version: 1.18.2 + resolution: "@formatjs/ecma402-abstract@npm:1.18.2" dependencies: - "@formatjs/intl-localematcher": 0.4.0 + "@formatjs/intl-localematcher": 0.5.4 tslib: ^2.4.0 - checksum: 256fb048fd888cfbed29e5cb216479337899202f4e759de0078489fe16776ae903123379897522ff7dccc51d2d231b1d27a0933cd8ca46703bc888f23b872b32 + checksum: 87afb37dd937555e712ca85d5142a9083d617c491d1dddf8d660fdfb6186272d2bc75b78809b076388d26f016200c8bddbce73281fd707eb899da2bf3bc9b7ca languageName: node linkType: hard @@ -5574,79 +3703,73 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-messageformat-parser@npm:2.6.0": - version: 2.6.0 - resolution: "@formatjs/icu-messageformat-parser@npm:2.6.0" +"@formatjs/icu-messageformat-parser@npm:2.7.6": + version: 2.7.6 + resolution: "@formatjs/icu-messageformat-parser@npm:2.7.6" dependencies: - "@formatjs/ecma402-abstract": 1.17.0 - "@formatjs/icu-skeleton-parser": 1.6.0 + "@formatjs/ecma402-abstract": 1.18.2 + "@formatjs/icu-skeleton-parser": 1.8.0 tslib: ^2.4.0 - checksum: 979128c974ecd611ef081ee831398325abad8ad4f088f40a4bef1197d0d6cd7d6db17ca75bb8bd6d81e33e7ff8ad4d4dc6d3a5de9d2c3dc249098cdc0daeb348 + checksum: 9fc72c2075333a969601e2be4260638940b1abefd1a5fc15b93b0b10d2319c9df5778aa51fc2a173ce66ca5e8a47b4b64caca85a32d0eb6095e16e8d65cb4b00 languageName: node linkType: hard -"@formatjs/icu-skeleton-parser@npm:1.6.0": - version: 1.6.0 - resolution: "@formatjs/icu-skeleton-parser@npm:1.6.0" +"@formatjs/icu-skeleton-parser@npm:1.8.0": + version: 1.8.0 + resolution: "@formatjs/icu-skeleton-parser@npm:1.8.0" dependencies: - "@formatjs/ecma402-abstract": 1.17.0 + "@formatjs/ecma402-abstract": 1.18.2 tslib: ^2.4.0 - checksum: c6474dff8e35f93874e7333135696de30c12ac1ca34a85528f8cc9fcf3512f1669fbb301d5601c9f28d4b16589a579477e95ec77ad5d7250fbba0dc7b19d233b + checksum: 10956732d70cc67049d216410b5dc3ef048935d1ea2ae76f5755bb9d0243af37ddeabd5d140ddbf5f6c7047068c3d02a05f93c68a89cedfaf7488d5062885ea4 languageName: node linkType: hard -"@formatjs/intl-localematcher@npm:0.4.0": - version: 0.4.0 - resolution: "@formatjs/intl-localematcher@npm:0.4.0" +"@formatjs/intl-localematcher@npm:0.5.4": + version: 0.5.4 + resolution: "@formatjs/intl-localematcher@npm:0.5.4" dependencies: tslib: ^2.4.0 - checksum: 38f5acc71d9eaa6091465ed3e7bedca6829f4eb65978bc50261eb82d19a9e86355c514fa69d1bf91ebf7419a9e71fd12f110a2452dfedc296dc32dd070e09dc7 + checksum: c9ff5d34ca8b6fe59f8f303a3cc31a92d343e095a6987e273e5cc23f0fe99feb557a392a05da95931c7d24106acb6988e588d00ddd05b0934005aafd7fdbafe6 languageName: node linkType: hard -"@gar/promisify@npm:^1.0.1": - version: 1.1.3 - resolution: "@gar/promisify@npm:1.1.3" - checksum: 0b3c9958d3cd17f4add3574975e3115ae05dc7f1298a60810414b16f6f558c137b5fb3cd3905df380bacfd955ec13f67c1e6710cbb5c246a7e8d65a8289b2bff - languageName: node - linkType: hard - -"@graphql-tools/merge@npm:^9.0.0": - version: 9.0.0 - resolution: "@graphql-tools/merge@npm:9.0.0" +"@graphql-tools/merge@npm:^9.0.0, @graphql-tools/merge@npm:^9.0.3": + version: 9.0.4 + resolution: "@graphql-tools/merge@npm:9.0.4" dependencies: - "@graphql-tools/utils": ^10.0.0 + "@graphql-tools/utils": ^10.0.13 tslib: ^2.4.0 peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 10376dbf1b64a3659dfa01d63bdafbb8addac829c0e772fc4596df4b46f249bee179692cc3f06b1157bdc3dccfe3a46caf5499786cce203eb0f7e124c88a5648 + checksum: baf8558955d2f5cefdad298be295e48564bd6d2e691eed1b6d4c62f58cea898c8269443181fe847ca2747ec179c5b2b620be9215323281b2d65afc29591ce52d languageName: node linkType: hard "@graphql-tools/schema@npm:^10.0.0": - version: 10.0.0 - resolution: "@graphql-tools/schema@npm:10.0.0" + version: 10.0.3 + resolution: "@graphql-tools/schema@npm:10.0.3" dependencies: - "@graphql-tools/merge": ^9.0.0 - "@graphql-tools/utils": ^10.0.0 + "@graphql-tools/merge": ^9.0.3 + "@graphql-tools/utils": ^10.0.13 tslib: ^2.4.0 value-or-promise: ^1.0.12 peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: b746c69cefb3b89fad13d56f0abb9e764efe1569836ea9ae5e5c510a6f0bce6e08f324b28aebcb5b2c11ba2ea1c308f18c204e322a188e254e2c7e426d3ccecb + checksum: 420bfa29d00927da085a3e521d7d6de5694f3abcdf5ba18655cc2a6b6145816d74503b13ba3ea15c7c65411023c9d81cfb73e7d49aa35ccfb91943f16ab9db8f languageName: node linkType: hard -"@graphql-tools/utils@npm:^10.0.0": - version: 10.0.6 - resolution: "@graphql-tools/utils@npm:10.0.6" +"@graphql-tools/utils@npm:^10.0.13": + version: 10.2.0 + resolution: "@graphql-tools/utils@npm:10.2.0" dependencies: "@graphql-typed-document-node/core": ^3.1.1 + cross-inspect: 1.0.0 dset: ^3.1.2 tslib: ^2.4.0 peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 85fb8faa73bd548e0dafe1d52710f246c0cacecf0f315488e7530fd3474f9642fc1cb75bd83965de1933cefc5aa5d2e579e4fd703d9113c8d95c0a67f0f401d2 + checksum: 98d452f68d98cbeb749f0c5e475447b5ca826f984651f2a47d5829d0dd8d0008e9f85109a5a451c399a15ac4a58b0ec59d457b89b321385c6e6932ec89d7dd61 languageName: node linkType: hard @@ -5706,13 +3829,13 @@ __metadata: linkType: hard "@hapi/wreck@npm:^18.0.0": - version: 18.0.1 - resolution: "@hapi/wreck@npm:18.0.1" + version: 18.1.0 + resolution: "@hapi/wreck@npm:18.1.0" dependencies: "@hapi/boom": ^10.0.1 "@hapi/bourne": ^3.0.0 "@hapi/hoek": ^11.0.2 - checksum: 46b1b1f750a66c4724964eb6d9192d1d19cfa45e602386aae76f52e3b423c9ae14a03a0f0e9f962e7d973708e1b0b6ab42d2ae77539a691fa77a18c78ccf285c + checksum: eab85afdf24d0c514abada83ef09e5f3b096348bfba36bb6c7a6f7eebd47ab583e07aa1005be7d638b405e4c55ec82a3697ad0cbe1b2db6bb73fa0e66baffde4 languageName: node linkType: hard @@ -5725,17 +3848,6 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.11.10": - version: 0.11.10 - resolution: "@humanwhocodes/config-array@npm:0.11.10" - dependencies: - "@humanwhocodes/object-schema": ^1.2.1 - debug: ^4.1.1 - minimatch: ^3.0.5 - checksum: 9e307a49a5baa28beb243d2c14c145f288fccd6885f4c92a9055707057ec40980242256b2a07c976cfa6c75f7081da111a40a9844d1ca8daeff2302f8b640e76 - languageName: node - linkType: hard - "@humanwhocodes/config-array@npm:^0.11.14": version: 0.11.14 resolution: "@humanwhocodes/config-array@npm:0.11.14" @@ -5772,7 +3884,7 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/object-schema@npm:^1.2.0, @humanwhocodes/object-schema@npm:^1.2.1": +"@humanwhocodes/object-schema@npm:^1.2.0": version: 1.2.1 resolution: "@humanwhocodes/object-schema@npm:1.2.1" checksum: c3c35fdb70c04a569278351c75553e293ae339684ed75895edc79facc7276e351115786946658d78133130c0cca80e57e2203bc07f8fa7fe7980300e8deef7db @@ -5793,40 +3905,40 @@ __metadata: languageName: node linkType: hard -"@internationalized/date@npm:^3.4.0": - version: 3.4.0 - resolution: "@internationalized/date@npm:3.4.0" +"@internationalized/date@npm:^3.5.3": + version: 3.5.3 + resolution: "@internationalized/date@npm:3.5.3" dependencies: "@swc/helpers": ^0.5.0 - checksum: 2a277e93c53c8059a16e620507a6a7f3d8828744835d0ee097006b0de9a61ae585cc73d3ee3f0334f057dbc80969a60ba7f7cbe2cfca35b0d51bbc6ff6931b1b + checksum: 2b517be98f60266445d75644ba091139a63069f9ec4289d3f31c3c0e1f21ee129d7c4905be84c617727d2890148d16e0ecc6804ab0b3e8d6b8eabc7fbb4a8169 languageName: node linkType: hard -"@internationalized/message@npm:^3.1.1": - version: 3.1.1 - resolution: "@internationalized/message@npm:3.1.1" +"@internationalized/message@npm:^3.1.3": + version: 3.1.3 + resolution: "@internationalized/message@npm:3.1.3" dependencies: "@swc/helpers": ^0.5.0 intl-messageformat: ^10.1.0 - checksum: e778de8567e424e00c52f9b69eb65cea817664803add4bc4f76eb0248d12a4a7eaedbc15a290cabe90a070826d25a93438dea99a1bee796deb024b78cd694a92 + checksum: 9a76cdfa0dbee8bb81c81fb30f18ab816477910a780025b6df741aeb5d1bd469c0dfe9a3788365ca7317a0072333ae0f0159fb5ec441228952185683b00c5b3b languageName: node linkType: hard -"@internationalized/number@npm:^3.2.1": - version: 3.2.1 - resolution: "@internationalized/number@npm:3.2.1" +"@internationalized/number@npm:^3.5.2": + version: 3.5.2 + resolution: "@internationalized/number@npm:3.5.2" dependencies: "@swc/helpers": ^0.5.0 - checksum: 0b0ccb776b70aae3d86ca84b53a2a63712b0f9e14ef9c23a61c36c9e1b37b34af3275e709280a685e267718c2e49e2bedad2d79631d23aa024fd23df20be0b29 + checksum: 098c1ade5cc3fbb70f87eae69f30fab995d5137307b735e735bf20ea1a8dd2fc0acbf52028c435ea31c82b8e8dbdcdbd6f919f58385879866afeba6e11235a44 languageName: node linkType: hard -"@internationalized/string@npm:^3.1.1": - version: 3.1.1 - resolution: "@internationalized/string@npm:3.1.1" +"@internationalized/string@npm:^3.2.2": + version: 3.2.2 + resolution: "@internationalized/string@npm:3.2.2" dependencies: "@swc/helpers": ^0.5.0 - checksum: c004037c79b6a42f87f7c15d50a9abc5da796af5f74717569a8576eb4ae9b87aed37fc8eef0d658e65540f21fdbba160dcba2128f78a94b8acd31fc72c966014 + checksum: 6ec68b8bbb9347a1f1fce46cecb5f359a962358e301afc76761d2ace198bad00ab7c0eef189be5124e5bd77b0ef8187c744f8c6eab3727b2f9743d7c08442cb0 languageName: node linkType: hard @@ -5930,34 +4042,6 @@ __metadata: languageName: node linkType: hard -"@jest/console@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/console@npm:29.5.0" - dependencies: - "@jest/types": ^29.5.0 - "@types/node": "*" - chalk: ^4.0.0 - jest-message-util: ^29.5.0 - jest-util: ^29.5.0 - slash: ^3.0.0 - checksum: 59dfbdb6c3c15652f8d7267071f24d6335afbed0b1cf71aed70b6ce8deb1d86e7f4aadb978f639435650107fd22476b59e63a3d3a9ac99b1aca739b795a54410 - languageName: node - linkType: hard - -"@jest/console@npm:^29.6.4": - version: 29.6.4 - resolution: "@jest/console@npm:29.6.4" - dependencies: - "@jest/types": ^29.6.3 - "@types/node": "*" - chalk: ^4.0.0 - jest-message-util: ^29.6.3 - jest-util: ^29.6.3 - slash: ^3.0.0 - checksum: 350092f3b77de6fbaee7b385831c55fed238005fa6e39fcbab46079160c0e24ed7fef2f5118188173fbca361c50fe5c7b1baab28f86f233c50fb97689bb4f7c1 - languageName: node - linkType: hard - "@jest/console@npm:^29.7.0": version: 29.7.0 resolution: "@jest/console@npm:29.7.0" @@ -6085,88 +4169,6 @@ __metadata: languageName: node linkType: hard -"@jest/core@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/core@npm:29.5.0" - dependencies: - "@jest/console": ^29.5.0 - "@jest/reporters": ^29.5.0 - "@jest/test-result": ^29.5.0 - "@jest/transform": ^29.5.0 - "@jest/types": ^29.5.0 - "@types/node": "*" - ansi-escapes: ^4.2.1 - chalk: ^4.0.0 - ci-info: ^3.2.0 - exit: ^0.1.2 - graceful-fs: ^4.2.9 - jest-changed-files: ^29.5.0 - jest-config: ^29.5.0 - jest-haste-map: ^29.5.0 - jest-message-util: ^29.5.0 - jest-regex-util: ^29.4.3 - jest-resolve: ^29.5.0 - jest-resolve-dependencies: ^29.5.0 - jest-runner: ^29.5.0 - jest-runtime: ^29.5.0 - jest-snapshot: ^29.5.0 - jest-util: ^29.5.0 - jest-validate: ^29.5.0 - jest-watcher: ^29.5.0 - micromatch: ^4.0.4 - pretty-format: ^29.5.0 - slash: ^3.0.0 - strip-ansi: ^6.0.0 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - checksum: e4b3e0de48614b2c339083b9159f00a024839984bd89b9afa4cfff4c38f6ce485c2009f2efa1c1e3bb3b87386288bc15798c6aebb7937d7820e8048d75461a4d - languageName: node - linkType: hard - -"@jest/core@npm:^29.6.4": - version: 29.6.4 - resolution: "@jest/core@npm:29.6.4" - dependencies: - "@jest/console": ^29.6.4 - "@jest/reporters": ^29.6.4 - "@jest/test-result": ^29.6.4 - "@jest/transform": ^29.6.4 - "@jest/types": ^29.6.3 - "@types/node": "*" - ansi-escapes: ^4.2.1 - chalk: ^4.0.0 - ci-info: ^3.2.0 - exit: ^0.1.2 - graceful-fs: ^4.2.9 - jest-changed-files: ^29.6.3 - jest-config: ^29.6.4 - jest-haste-map: ^29.6.4 - jest-message-util: ^29.6.3 - jest-regex-util: ^29.6.3 - jest-resolve: ^29.6.4 - jest-resolve-dependencies: ^29.6.4 - jest-runner: ^29.6.4 - jest-runtime: ^29.6.4 - jest-snapshot: ^29.6.4 - jest-util: ^29.6.3 - jest-validate: ^29.6.3 - jest-watcher: ^29.6.4 - micromatch: ^4.0.4 - pretty-format: ^29.6.3 - slash: ^3.0.0 - strip-ansi: ^6.0.0 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - checksum: c1af87534d1e3ee881af413bb16bde9ff6ead0d17e675eafb6fa5020e714cacd5d38b842c9184bffee01d33811695fcc03addc5c02e15ec77e5686bbb9d24496 - languageName: node - linkType: hard - "@jest/core@npm:^29.7.0": version: 29.7.0 resolution: "@jest/core@npm:29.7.0" @@ -6252,30 +4254,6 @@ __metadata: languageName: node linkType: hard -"@jest/environment@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/environment@npm:29.5.0" - dependencies: - "@jest/fake-timers": ^29.5.0 - "@jest/types": ^29.5.0 - "@types/node": "*" - jest-mock: ^29.5.0 - checksum: 1fbe63cbfb9c3f6c9fc9d8f6917a5aceee1828d589569bbffcf5fb4bb56bc021dc3a6f239cde3099144767c97763ae134904ee522f236cd8c0d071bd7f9ef63b - languageName: node - linkType: hard - -"@jest/environment@npm:^29.6.4": - version: 29.6.4 - resolution: "@jest/environment@npm:29.6.4" - dependencies: - "@jest/fake-timers": ^29.6.4 - "@jest/types": ^29.6.3 - "@types/node": "*" - jest-mock: ^29.6.3 - checksum: c5d23384294e775081bd3274e6632f442c09ae988222f3e09e3b3ba7f40cfc0f908815f1feee2960210cf6a88a7e153869773a3921042b9dab7878f1b5df75f7 - languageName: node - linkType: hard - "@jest/environment@npm:^29.7.0": version: 29.7.0 resolution: "@jest/environment@npm:29.7.0" @@ -6288,24 +4266,6 @@ __metadata: languageName: node linkType: hard -"@jest/expect-utils@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/expect-utils@npm:29.5.0" - dependencies: - jest-get-type: ^29.4.3 - checksum: e7f44de651b5ef71c6e1b7a0350a704258167c20b6e8165b3100346d5c7f8eb4cd2c229ea2c048e9161666d1c086fbbc422f111f3b77da3fb89a99d52d4b3690 - languageName: node - linkType: hard - -"@jest/expect-utils@npm:^29.6.4": - version: 29.6.4 - resolution: "@jest/expect-utils@npm:29.6.4" - dependencies: - jest-get-type: ^29.6.3 - checksum: 17d87d551090f6b460fa45605c614b2ad28e257360a5b8152216fe983370f4cfb8482d2d017552c2be43be1caa0ff5594f1381be17798dcad3899e05b297fe83 - languageName: node - linkType: hard - "@jest/expect-utils@npm:^29.7.0": version: 29.7.0 resolution: "@jest/expect-utils@npm:29.7.0" @@ -6315,26 +4275,6 @@ __metadata: languageName: node linkType: hard -"@jest/expect@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/expect@npm:29.5.0" - dependencies: - expect: ^29.5.0 - jest-snapshot: ^29.5.0 - checksum: 447e7450af8ba61ac34d8a2ca11c56c62f6f0fb33ff13130f11a1ec9526a08d756ee72da622316a2c52ecfe726fe14432bdfb46e45aff5676f8d1a8efc8d201c - languageName: node - linkType: hard - -"@jest/expect@npm:^29.6.4": - version: 29.6.4 - resolution: "@jest/expect@npm:29.6.4" - dependencies: - expect: ^29.6.4 - jest-snapshot: ^29.6.4 - checksum: 1215ea06df304941a87f5411516019712809c98b5698551438339fc0f195c75dc6089b904c11c7fb2d468ffad5854dc05ef989ea808730f704703aa68eea4f16 - languageName: node - linkType: hard - "@jest/expect@npm:^29.7.0": version: 29.7.0 resolution: "@jest/expect@npm:29.7.0" @@ -6386,34 +4326,6 @@ __metadata: languageName: node linkType: hard -"@jest/fake-timers@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/fake-timers@npm:29.5.0" - dependencies: - "@jest/types": ^29.5.0 - "@sinonjs/fake-timers": ^10.0.2 - "@types/node": "*" - jest-message-util: ^29.5.0 - jest-mock: ^29.5.0 - jest-util: ^29.5.0 - checksum: dbf52fd302bf6b3d7ec49499f12835b7d7d4069d61adc62dac233021eba61186bbad3add1ceb3225a23a8745dd04fa0dcc2c38d350ecb0f26eec63f2cf5e6aff - languageName: node - linkType: hard - -"@jest/fake-timers@npm:^29.6.4": - version: 29.6.4 - resolution: "@jest/fake-timers@npm:29.6.4" - dependencies: - "@jest/types": ^29.6.3 - "@sinonjs/fake-timers": ^10.0.2 - "@types/node": "*" - jest-message-util: ^29.6.3 - jest-mock: ^29.6.3 - jest-util: ^29.6.3 - checksum: b4ca14ece8fa46d8c0ab64368a95d40c32d920fb270b94d9e0f67b61f11c019cd89e19e4e8a367bdf262337674d48cbfbe489fb01109761fc2ae1b0c34c672c7 - languageName: node - linkType: hard - "@jest/fake-timers@npm:^29.7.0": version: 29.7.0 resolution: "@jest/fake-timers@npm:29.7.0" @@ -6461,30 +4373,6 @@ __metadata: languageName: node linkType: hard -"@jest/globals@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/globals@npm:29.5.0" - dependencies: - "@jest/environment": ^29.5.0 - "@jest/expect": ^29.5.0 - "@jest/types": ^29.5.0 - jest-mock: ^29.5.0 - checksum: 0c25f07d8125e45cf3c21442e625f6a636eaf7f4cf1cf3f9f66bae059aeb31d3dc61dfff9479eb861a5089dca34c95e231ad88b8925bee42387abecbfe5ecbc2 - languageName: node - linkType: hard - -"@jest/globals@npm:^29.6.4": - version: 29.6.4 - resolution: "@jest/globals@npm:29.6.4" - dependencies: - "@jest/environment": ^29.6.4 - "@jest/expect": ^29.6.4 - "@jest/types": ^29.6.3 - jest-mock: ^29.6.3 - checksum: ae167fc518f58dabee6b1852a1631c171383ad75b9aeae3260f18a6cc25ad6e5a1caee3bc9bff5c53b33166df36e9a2395aca728b9ea3b9e881fe15244582e9f - languageName: node - linkType: hard - "@jest/globals@npm:^29.7.0": version: 29.7.0 resolution: "@jest/globals@npm:29.7.0" @@ -6607,80 +4495,6 @@ __metadata: languageName: node linkType: hard -"@jest/reporters@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/reporters@npm:29.5.0" - dependencies: - "@bcoe/v8-coverage": ^0.2.3 - "@jest/console": ^29.5.0 - "@jest/test-result": ^29.5.0 - "@jest/transform": ^29.5.0 - "@jest/types": ^29.5.0 - "@jridgewell/trace-mapping": ^0.3.15 - "@types/node": "*" - chalk: ^4.0.0 - collect-v8-coverage: ^1.0.0 - exit: ^0.1.2 - glob: ^7.1.3 - graceful-fs: ^4.2.9 - istanbul-lib-coverage: ^3.0.0 - istanbul-lib-instrument: ^5.1.0 - istanbul-lib-report: ^3.0.0 - istanbul-lib-source-maps: ^4.0.0 - istanbul-reports: ^3.1.3 - jest-message-util: ^29.5.0 - jest-util: ^29.5.0 - jest-worker: ^29.5.0 - slash: ^3.0.0 - string-length: ^4.0.1 - strip-ansi: ^6.0.0 - v8-to-istanbul: ^9.0.1 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - checksum: 72b771a7749ac2eb9b671f2a886dc98cbe914dfa1a4266854b040e4cc563bf9f5db02b8ff8654b7bfbc3b28caa6d48ca0dde9707454ea4f79d77bd13b6357929 - languageName: node - linkType: hard - -"@jest/reporters@npm:^29.6.4": - version: 29.6.4 - resolution: "@jest/reporters@npm:29.6.4" - dependencies: - "@bcoe/v8-coverage": ^0.2.3 - "@jest/console": ^29.6.4 - "@jest/test-result": ^29.6.4 - "@jest/transform": ^29.6.4 - "@jest/types": ^29.6.3 - "@jridgewell/trace-mapping": ^0.3.18 - "@types/node": "*" - chalk: ^4.0.0 - collect-v8-coverage: ^1.0.0 - exit: ^0.1.2 - glob: ^7.1.3 - graceful-fs: ^4.2.9 - istanbul-lib-coverage: ^3.0.0 - istanbul-lib-instrument: ^6.0.0 - istanbul-lib-report: ^3.0.0 - istanbul-lib-source-maps: ^4.0.0 - istanbul-reports: ^3.1.3 - jest-message-util: ^29.6.3 - jest-util: ^29.6.3 - jest-worker: ^29.6.4 - slash: ^3.0.0 - string-length: ^4.0.1 - strip-ansi: ^6.0.0 - v8-to-istanbul: ^9.0.1 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - checksum: 6c393316518ad64c69a67c3e479f042c4daedb746e591356f9686e5959f1a1c878f3f62f8ea3e49a0d6bf186c49cdc3e11536aa55e51a73ef887834b8c45957e - languageName: node - linkType: hard - "@jest/reporters@npm:^29.7.0": version: 29.7.0 resolution: "@jest/reporters@npm:29.7.0" @@ -6718,15 +4532,6 @@ __metadata: languageName: node linkType: hard -"@jest/schemas@npm:^29.4.3": - version: 29.4.3 - resolution: "@jest/schemas@npm:29.4.3" - dependencies: - "@sinclair/typebox": ^0.25.16 - checksum: 8a35967cec454d1de2d5a58ab99b49a0ff798d1dce2d817bdd9960bb2f070493f767fbbf419e6a263860d3b1ef1e50ab609a76ae21b5f8c09bb0859e8f51a098 - languageName: node - linkType: hard - "@jest/schemas@npm:^29.6.3": version: 29.6.3 resolution: "@jest/schemas@npm:29.6.3" @@ -6769,17 +4574,6 @@ __metadata: languageName: node linkType: hard -"@jest/source-map@npm:^29.4.3": - version: 29.4.3 - resolution: "@jest/source-map@npm:29.4.3" - dependencies: - "@jridgewell/trace-mapping": ^0.3.15 - callsites: ^3.0.0 - graceful-fs: ^4.2.9 - checksum: 353f9989dcb416e8a2559ad2831b4b3e8446a9f8259782cec97f89903b5c00baa76ea3e23a3f1c83c1ccb3999a9e318b8c6a4bab29e4b66a4abdbb760e445a50 - languageName: node - linkType: hard - "@jest/source-map@npm:^29.6.3": version: 29.6.3 resolution: "@jest/source-map@npm:29.6.3" @@ -6827,30 +4621,6 @@ __metadata: languageName: node linkType: hard -"@jest/test-result@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/test-result@npm:29.5.0" - dependencies: - "@jest/console": ^29.5.0 - "@jest/types": ^29.5.0 - "@types/istanbul-lib-coverage": ^2.0.0 - collect-v8-coverage: ^1.0.0 - checksum: 5d637c9935ea0438b2a7c106d48756967e5a96fa4426a9b16ea2a3e73e1538eabd10fd4faa8eb46aa4fee710a165e0fd2ce0603dacde5e8a1bba541100854b1d - languageName: node - linkType: hard - -"@jest/test-result@npm:^29.6.4": - version: 29.6.4 - resolution: "@jest/test-result@npm:29.6.4" - dependencies: - "@jest/console": ^29.6.4 - "@jest/types": ^29.6.3 - "@types/istanbul-lib-coverage": ^2.0.0 - collect-v8-coverage: ^1.0.0 - checksum: 62daf70ceb29f9048fef478b0b47ea93f60017d14726f5c1baeadc9dcb02d4429a7934f4638d32987dcea88b993f7e92141ade7916b65a86c0994e4fc041482e - languageName: node - linkType: hard - "@jest/test-result@npm:^29.7.0": version: 29.7.0 resolution: "@jest/test-result@npm:29.7.0" @@ -6901,30 +4671,6 @@ __metadata: languageName: node linkType: hard -"@jest/test-sequencer@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/test-sequencer@npm:29.5.0" - dependencies: - "@jest/test-result": ^29.5.0 - graceful-fs: ^4.2.9 - jest-haste-map: ^29.5.0 - slash: ^3.0.0 - checksum: 6fb7549a5dbe2da6817eb853134f76cf2b320b283900c5e63c997ecfadc616379372a49ac8c0f4ffdb9616eed4a5908c74cb7a560a395a6e1dc0d072b865657b - languageName: node - linkType: hard - -"@jest/test-sequencer@npm:^29.6.4": - version: 29.6.4 - resolution: "@jest/test-sequencer@npm:29.6.4" - dependencies: - "@jest/test-result": ^29.6.4 - graceful-fs: ^4.2.9 - jest-haste-map: ^29.6.4 - slash: ^3.0.0 - checksum: 2ac9ff9ebea367a41cf923f0229860b2ed691c0080b72395c4afec8882e998086aacb98fe0d780c3b03a724a1d52d856bb2447d0ea777bbaf5841f6b3cd07790 - languageName: node - linkType: hard - "@jest/test-sequencer@npm:^29.7.0": version: 29.7.0 resolution: "@jest/test-sequencer@npm:29.7.0" @@ -7030,52 +4776,6 @@ __metadata: languageName: node linkType: hard -"@jest/transform@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/transform@npm:29.5.0" - dependencies: - "@babel/core": ^7.11.6 - "@jest/types": ^29.5.0 - "@jridgewell/trace-mapping": ^0.3.15 - babel-plugin-istanbul: ^6.1.1 - chalk: ^4.0.0 - convert-source-map: ^2.0.0 - fast-json-stable-stringify: ^2.1.0 - graceful-fs: ^4.2.9 - jest-haste-map: ^29.5.0 - jest-regex-util: ^29.4.3 - jest-util: ^29.5.0 - micromatch: ^4.0.4 - pirates: ^4.0.4 - slash: ^3.0.0 - write-file-atomic: ^4.0.2 - checksum: 113598311d84ec7e4a4aadd340e332bbfbbd66e20eabea8b2f084b80cf97c1bc9e1ff90278c4f04b227afa95e3386d702363715f9923062c370c042c31911d94 - languageName: node - linkType: hard - -"@jest/transform@npm:^29.6.4": - version: 29.6.4 - resolution: "@jest/transform@npm:29.6.4" - dependencies: - "@babel/core": ^7.11.6 - "@jest/types": ^29.6.3 - "@jridgewell/trace-mapping": ^0.3.18 - babel-plugin-istanbul: ^6.1.1 - chalk: ^4.0.0 - convert-source-map: ^2.0.0 - fast-json-stable-stringify: ^2.1.0 - graceful-fs: ^4.2.9 - jest-haste-map: ^29.6.4 - jest-regex-util: ^29.6.3 - jest-util: ^29.6.3 - micromatch: ^4.0.4 - pirates: ^4.0.4 - slash: ^3.0.0 - write-file-atomic: ^4.0.2 - checksum: 75a540f1a5075c57f83afed1caa39ef695ddd8890648d348f9bd94b26c81a872624c9d8feb9e0849d16c222348972dd2f5538bdb00f9e55c0cd07ef3b67e9e84 - languageName: node - linkType: hard - "@jest/types@npm:^25.5.0": version: 25.5.0 resolution: "@jest/types@npm:25.5.0" @@ -7114,20 +4814,6 @@ __metadata: languageName: node linkType: hard -"@jest/types@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/types@npm:29.5.0" - dependencies: - "@jest/schemas": ^29.4.3 - "@types/istanbul-lib-coverage": ^2.0.0 - "@types/istanbul-reports": ^3.0.0 - "@types/node": "*" - "@types/yargs": ^17.0.8 - chalk: ^4.0.0 - checksum: f1cccd2e9b00a985bfdac03517f906cdf7a481be3606c335f8ec08a7272b7cf700b23484ce323a912b374defb90d3ab88c643cf2a2f47635c1c4feacfa1c1b2d - languageName: node - linkType: hard - "@jest/types@npm:^29.6.3": version: 29.6.3 resolution: "@jest/types@npm:29.6.3" @@ -7160,18 +4846,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2": - version: 0.3.3 - resolution: "@jridgewell/gen-mapping@npm:0.3.3" - dependencies: - "@jridgewell/set-array": ^1.0.1 - "@jridgewell/sourcemap-codec": ^1.4.10 - "@jridgewell/trace-mapping": ^0.3.9 - checksum: 376fc11cf5a967318ba3ddd9d8e91be528eab6af66810a713c49b0c3f8dc67e9949452c51c38ab1b19aa618fb5e8594da5a249977e26b1e7fea1ee5a1fcacc74 - languageName: node - linkType: hard - -"@jridgewell/gen-mapping@npm:^0.3.5": +"@jridgewell/gen-mapping@npm:^0.3.2, @jridgewell/gen-mapping@npm:^0.3.5": version: 0.3.5 resolution: "@jridgewell/gen-mapping@npm:0.3.5" dependencies: @@ -7182,24 +4857,10 @@ __metadata: languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:3.1.0": - version: 3.1.0 - resolution: "@jridgewell/resolve-uri@npm:3.1.0" - checksum: 78055e2526108331126366572045355051a930f017d1904a4f753d3f4acee8d92a14854948095626f6163cffc24ea4e3efa30637417bb866b84743dec7ef6fd9 - languageName: node - linkType: hard - "@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": - version: 3.1.1 - resolution: "@jridgewell/resolve-uri@npm:3.1.1" - checksum: 0dbc9e29bc640bbbdc5b9876d2859c69042bfcf1423c1e6421bcca53e826660bff4e41c7d4bcb8dbea696404231a6f902f76ba41835d049e20f2dd6cffb713bf - languageName: node - linkType: hard - -"@jridgewell/set-array@npm:^1.0.1": - version: 1.1.2 - resolution: "@jridgewell/set-array@npm:1.1.2" - checksum: bc7ab4c4c00470de4e7562ecac3c0c84f53e7ee8a711e546d67c47da7febe7c45cd67d4d84ee3c9b2c05ae8e872656cdded8a707a283d30bd54fbc65aef821ab + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e languageName: node linkType: hard @@ -7211,16 +4872,12 @@ __metadata: linkType: hard "@jridgewell/source-map@npm:^0.3.3": - version: 0.3.4 - resolution: "@jridgewell/source-map@npm:0.3.4" - checksum: 4b83e015c3df8552b303f0d7d3f46b9fc297ae08e67dfe621ccbacf2879193e0890c397668a75ec90444de701616905376b02305d1a762c813ca03e86b8d9def - languageName: node - linkType: hard - -"@jridgewell/sourcemap-codec@npm:1.4.14": - version: 1.4.14 - resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" - checksum: 3fbaff1387c1338b097eeb6ff92890d7838f7de0dde259e4983763b44540bfd5ca6a1f7644dc8ad003a57f7e80670d5b96a8402f1386ba9aee074743ae9bad51 + version: 0.3.6 + resolution: "@jridgewell/source-map@npm:0.3.6" + dependencies: + "@jridgewell/gen-mapping": ^0.3.5 + "@jridgewell/trace-mapping": ^0.3.25 + checksum: 6a4ecc713ed246ff8e5bdcc1ef7c49aaa93f7463d948ba5054dda18b02dcc6a055e2828c577bcceee058f302ce1fc95595713d44f5c45e43d459f88d267f2f04 languageName: node linkType: hard @@ -7241,27 +4898,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.15, @jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.8, @jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.18 - resolution: "@jridgewell/trace-mapping@npm:0.3.18" - dependencies: - "@jridgewell/resolve-uri": 3.1.0 - "@jridgewell/sourcemap-codec": 1.4.14 - checksum: e5045775f076022b6c7cc64a7b55742faa5442301cb3389fd0e6712fafc46a2bb13c68fa1ffaf7b8bb665a91196f050b4115885fc802094ebc06a1cf665935ac - languageName: node - linkType: hard - -"@jridgewell/trace-mapping@npm:^0.3.18": - version: 0.3.19 - resolution: "@jridgewell/trace-mapping@npm:0.3.19" - dependencies: - "@jridgewell/resolve-uri": ^3.1.0 - "@jridgewell/sourcemap-codec": ^1.4.14 - checksum: 845e6c6efca621b2b85e4d13fd25c319b6e4ab1ea78d4385ff6c0f78322ea0fcdfec8ac763aa4b56e8378c96d7bef101a2638c7a1a076f7d62f6376230c940a7 - languageName: node - linkType: hard - -"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": +"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": version: 0.3.25 resolution: "@jridgewell/trace-mapping@npm:0.3.25" dependencies: @@ -7321,45 +4958,9 @@ __metadata: linkType: hard "@mdn/browser-compat-data@npm:^5.3.7": - version: 5.3.26 - resolution: "@mdn/browser-compat-data@npm:5.3.26" - checksum: b6e981d51c9c894d4e021b7141cb3ef2da6ad56126b6cd6da8326e09efe4ebe4f936aee57b058eebe2a9a8da3f06707bfd8b672cd26bf9caea3e582ea52e29c3 - languageName: node - linkType: hard - -"@mdx-js/mdx@npm:^1.6.22": - version: 1.6.22 - resolution: "@mdx-js/mdx@npm:1.6.22" - dependencies: - "@babel/core": 7.12.9 - "@babel/plugin-syntax-jsx": 7.12.1 - "@babel/plugin-syntax-object-rest-spread": 7.8.3 - "@mdx-js/util": 1.6.22 - babel-plugin-apply-mdx-type-prop: 1.6.22 - babel-plugin-extract-import-names: 1.6.22 - camelcase-css: 2.0.1 - detab: 2.0.4 - hast-util-raw: 6.0.1 - lodash.uniq: 4.5.0 - mdast-util-to-hast: 10.0.1 - remark-footnotes: 2.0.0 - remark-mdx: 1.6.22 - remark-parse: 8.0.3 - remark-squeeze-paragraphs: 4.0.0 - style-to-object: 0.3.0 - unified: 9.2.0 - unist-builder: 2.0.3 - unist-util-visit: 2.0.3 - checksum: 7f4c38911fc269159834240d3cc9279839145022a992bd61657530750c7ab5d0f674e8d6319b6e2e426d0e1adc6cc5ab1876e57548208783d8a3d1b8ef73ebca - languageName: node - linkType: hard - -"@mdx-js/react@npm:^1.6.22": - version: 1.6.22 - resolution: "@mdx-js/react@npm:1.6.22" - peerDependencies: - react: ^16.13.1 || ^17.0.0 - checksum: ed896671ffab04c1f11cdba45bfb2786acff58cd0b749b0a13d9b7a7022ac75cc036bec067ca946e6540e2934727e0ba8bf174e4ae10c916f30cda6aecac8992 + version: 5.5.25 + resolution: "@mdn/browser-compat-data@npm:5.5.25" + checksum: b25faff468d97dcd78b5918d0bf0638fa243775553023ebd5a97613848e9a4d54949294f7406dd706c13b2f7df28dee53f48331dc8b75c49d89b44f5c1623529 languageName: node linkType: hard @@ -7375,13 +4976,6 @@ __metadata: languageName: node linkType: hard -"@mdx-js/util@npm:1.6.22": - version: 1.6.22 - resolution: "@mdx-js/util@npm:1.6.22" - checksum: 2ee8da6afea0f42297ea31f52b1d50d228744d2895cce7cc9571b7d5ce97c7c96037c80b6dbcded9caa8099c9a994eda62980099eabe1c000aaa792816c66f10 - languageName: node - linkType: hard - "@medusajs/admin-bundler@workspace:packages/admin-next/admin-bundler": version: 0.0.0-use.local resolution: "@medusajs/admin-bundler@workspace:packages/admin-next/admin-bundler" @@ -7559,7 +5153,7 @@ __metadata: languageName: unknown linkType: soft -"@medusajs/currency@workspace:^, @medusajs/currency@workspace:packages/modules/currency": +"@medusajs/currency@workspace:packages/modules/currency": version: 0.0.0-use.local resolution: "@medusajs/currency@workspace:packages/modules/currency" dependencies: @@ -7645,7 +5239,7 @@ __metadata: i18next-browser-languagedetector: 7.2.0 i18next-http-backend: 2.4.2 match-sorter: ^6.3.4 - medusa-react: "workspace:^" + medusa-react: latest postcss: ^8.4.33 prettier: ^3.1.1 qs: ^6.12.0 @@ -7742,7 +5336,7 @@ __metadata: awilix: ^8.0.0 cross-env: ^5.2.1 dotenv: ^16.4.5 - faker: ^6.6.6 + faker: ^5.5.3 jest: ^29.6.3 knex: 2.4.2 lodash: ^4.17.21 @@ -7933,25 +5527,20 @@ __metadata: languageName: unknown linkType: soft -"@medusajs/medusa-js@*, @medusajs/medusa-js@workspace:packages/medusa-js": - version: 0.0.0-use.local - resolution: "@medusajs/medusa-js@workspace:packages/medusa-js" +"@medusajs/medusa-js@npm:*": + version: 6.1.8 + resolution: "@medusajs/medusa-js@npm:6.1.8" dependencies: - "@medusajs/medusa": ^1.20.3 - "@types/uuid": ^9.0.0 axios: ^0.24.0 cross-env: ^5.2.1 - jest: ^27.4.7 qs: ^6.10.3 retry-axios: ^2.6.0 - ts-jest: ^27.1.5 - tsup: 6.7.0 - typescript: ^4.9.5 uuid: ^9.0.0 peerDependencies: "@medusajs/medusa": ^1.17.2 - languageName: unknown - linkType: soft + checksum: ee43f60c083a7fe5116405e57f86189b720e47019a2a991002e86fdb7ed438171ba428088bd19169ba1d07c20095605bef6d867a793d985362e7dfc181b6c0af + languageName: node + linkType: hard "@medusajs/medusa-oas-cli@0.3.2, @medusajs/medusa-oas-cli@workspace:packages/cli/oas/medusa-oas-cli": version: 0.0.0-use.local @@ -7983,7 +5572,7 @@ __metadata: languageName: unknown linkType: soft -"@medusajs/medusa@^1.20.3, @medusajs/medusa@^1.20.4, @medusajs/medusa@^1.20.5, @medusajs/medusa@workspace:*, @medusajs/medusa@workspace:^, @medusajs/medusa@workspace:packages/medusa": +"@medusajs/medusa@^1.20.3, @medusajs/medusa@^1.20.4, @medusajs/medusa@workspace:*, @medusajs/medusa@workspace:^, @medusajs/medusa@workspace:packages/medusa": version: 0.0.0-use.local resolution: "@medusajs/medusa@workspace:packages/medusa" dependencies: @@ -8264,7 +5853,7 @@ __metadata: awilix: ^8.0.0 cross-env: ^5.2.1 dotenv: ^16.4.5 - faker: ^6.6.6 + faker: ^5.5.3 jest: ^29.6.3 knex: 2.4.2 lodash: ^4.17.21 @@ -8386,18 +5975,6 @@ __metadata: languageName: unknown linkType: soft -"@medusajs/stock-location@npm:latest": - version: 1.11.5 - resolution: "@medusajs/stock-location@npm:1.11.5" - dependencies: - "@medusajs/modules-sdk": ^1.12.8 - "@medusajs/utils": ^1.11.5 - awilix: ^8.0.0 - typeorm: ^0.3.16 - checksum: 812e5b5f82b4e41e39bddc6148de8b45815c00dfff64d66972b1e61258c98c1c5da037b17df910db06ac7409cd6ea81777b130d025034ec6f14aeb9fc45994bd - languageName: node - linkType: hard - "@medusajs/store@workspace:^, @medusajs/store@workspace:packages/modules/store": version: 0.0.0-use.local resolution: "@medusajs/store@workspace:packages/modules/store" @@ -8515,10 +6092,10 @@ __metadata: "@medusajs/icons": ^1.2.1 "@medusajs/ui-preset": ^1.1.3 "@radix-ui/react-accordion": ^1.1.2 - "@radix-ui/react-alert-dialog": ^1.0.4 + "@radix-ui/react-alert-dialog": 1.0.4 "@radix-ui/react-avatar": ^1.0.3 "@radix-ui/react-checkbox": ^1.0.4 - "@radix-ui/react-dialog": ^1.0.4 + "@radix-ui/react-dialog": 1.0.4 "@radix-ui/react-dropdown-menu": ^2.0.5 "@radix-ui/react-label": ^2.0.2 "@radix-ui/react-popover": ^1.0.6 @@ -8896,16 +6473,6 @@ __metadata: languageName: node linkType: hard -"@mrmlnc/readdir-enhanced@npm:^2.2.1": - version: 2.2.1 - resolution: "@mrmlnc/readdir-enhanced@npm:2.2.1" - dependencies: - call-me-maybe: ^1.0.1 - glob-to-regexp: ^0.3.0 - checksum: 01840f3c85e9a7cd0ed5e038cc00e7518809b9edda950598e22b1c9804832e39a75707aaa6eb0b023e72182a85e00041c7a01483e425b16257bd3d5e4c788d86 - languageName: node - linkType: hard - "@msgpackr-extract/msgpackr-extract-darwin-arm64@npm:3.0.2": version: 3.0.2 resolution: "@msgpackr-extract/msgpackr-extract-darwin-arm64@npm:3.0.2" @@ -8948,30 +6515,6 @@ __metadata: languageName: node linkType: hard -"@mswjs/cookies@npm:^0.1.6": - version: 0.1.7 - resolution: "@mswjs/cookies@npm:0.1.7" - dependencies: - "@types/set-cookie-parser": ^2.4.0 - set-cookie-parser: ^2.4.6 - checksum: 647e97c1cd970be0b49c359faa4798a1eaa9cbf3ad7e88b184bcec5c6ee183e45b720708d3084b3a3ca8c797d86a64cd57e04d553fc10ef28b1f3d3e3929582e - languageName: node - linkType: hard - -"@mswjs/interceptors@npm:^0.12.6": - version: 0.12.7 - resolution: "@mswjs/interceptors@npm:0.12.7" - dependencies: - "@open-draft/until": ^1.0.3 - "@xmldom/xmldom": ^0.7.2 - debug: ^4.3.2 - headers-utils: ^3.0.2 - outvariant: ^1.2.0 - strict-event-emitter: ^0.2.0 - checksum: f5fb4cf3bcb6325a0f2fdf90e2d030572529781e9b2e04b4c4dc40bb9b74dfd276cac1d44f0ba05cb674629ab5da34c087ddc845d39fe774b984ff4f54af04e3 - languageName: node - linkType: hard - "@ndelangen/get-tarball@npm:^3.0.7": version: 3.0.9 resolution: "@ndelangen/get-tarball@npm:3.0.9" @@ -9035,13 +6578,6 @@ __metadata: languageName: node linkType: hard -"@nodelib/fs.stat@npm:^1.1.2": - version: 1.1.3 - resolution: "@nodelib/fs.stat@npm:1.1.3" - checksum: dc28ccae626e817a61b1544285b0f86c4e94a4a23db777c2949f78866ec57b1e1ccd5554bc3ed8e965df0646b1019e184315d32e98428c15eef7409974b17598 - languageName: node - linkType: hard - "@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": version: 1.2.8 resolution: "@nodelib/fs.walk@npm:1.2.8" @@ -9052,13 +6588,16 @@ __metadata: languageName: node linkType: hard -"@npmcli/fs@npm:^1.0.0": - version: 1.1.1 - resolution: "@npmcli/fs@npm:1.1.1" +"@npmcli/agent@npm:^2.0.0": + version: 2.2.2 + resolution: "@npmcli/agent@npm:2.2.2" dependencies: - "@gar/promisify": ^1.0.1 - semver: ^7.3.5 - checksum: 4143c317a7542af9054018b71601e3c3392e6704e884561229695f099a71336cbd580df9a9ffb965d0024bf0ed593189ab58900fd1714baef1c9ee59c738c3e2 + agent-base: ^7.1.0 + http-proxy-agent: ^7.0.0 + https-proxy-agent: ^7.0.1 + lru-cache: ^10.0.1 + socks-proxy-agent: ^8.0.3 + checksum: 325e0db7b287d4154ecd164c0815c08007abfb07653cc57bceded17bb7fd240998a3cbdbe87d700e30bef494885eccc725ab73b668020811d56623d145b524ae languageName: node linkType: hard @@ -9071,43 +6610,33 @@ __metadata: languageName: node linkType: hard -"@npmcli/move-file@npm:^1.0.1": - version: 1.1.2 - resolution: "@npmcli/move-file@npm:1.1.2" - dependencies: - mkdirp: ^1.0.4 - rimraf: ^3.0.2 - checksum: 02e946f3dafcc6743132fe2e0e2b585a96ca7265653a38df5a3e53fcf26c7c7a57fc0f861d7c689a23fdb6d6836c7eea5050c8086abf3c994feb2208d1514ff0 - languageName: node - linkType: hard - "@oclif/command@npm:^1, @oclif/command@npm:^1.8.15": - version: 1.8.30 - resolution: "@oclif/command@npm:1.8.30" + version: 1.8.36 + resolution: "@oclif/command@npm:1.8.36" dependencies: "@oclif/config": ^1.18.2 "@oclif/errors": ^1.3.6 "@oclif/help": ^1.0.1 - "@oclif/parser": ^3.8.13 + "@oclif/parser": ^3.8.17 debug: ^4.1.1 - semver: ^7.5.3 + semver: ^7.5.4 peerDependencies: "@oclif/config": ^1 - checksum: a65257fc3e0dccff72cb088355bd824faedbfcc10137c117a11c5608f06ecd6b0e5b010502dc77f2fa20b34a2dd25df7c79e7d704bcaa7f6afc7205ebfab8e66 + checksum: 5513d9b3ab3ed9a46a525db1dd42ee8a580fc70324fd6416ed4c4f2d7c046c874684b991a808236c1f2b2c7291bc63addc0a14a7df4a1d166f4944f4de59b657 languageName: node linkType: hard -"@oclif/config@npm:1.18.10": - version: 1.18.10 - resolution: "@oclif/config@npm:1.18.10" +"@oclif/config@npm:1.18.16": + version: 1.18.16 + resolution: "@oclif/config@npm:1.18.16" dependencies: "@oclif/errors": ^1.3.6 - "@oclif/parser": ^3.8.12 + "@oclif/parser": ^3.8.16 debug: ^4.3.4 globby: ^11.1.0 is-wsl: ^2.1.1 - tslib: ^2.5.0 - checksum: 4ae21db7fb8b09f9090a2d9bc43208b1f3f88058fdd8434e3c80a4518f4b76438bae784aa3b66efe0f6b6864205f905f9af05cde12aa208666b4d862bb950285 + tslib: ^2.6.1 + checksum: 65300cd8bf90fefe250dac57de3c07e79601542d76f5a59d602c226945a7b2edfe4b42bf25a84f44432f444d1b0e41a7ca5b244c3cb28d5ee88fe68b8c16e74d languageName: node linkType: hard @@ -9126,16 +6655,16 @@ __metadata: linkType: hard "@oclif/config@npm:^1, @oclif/config@npm:^1.18.2": - version: 1.18.11 - resolution: "@oclif/config@npm:1.18.11" + version: 1.18.17 + resolution: "@oclif/config@npm:1.18.17" dependencies: "@oclif/errors": ^1.3.6 - "@oclif/parser": ^3.8.13 + "@oclif/parser": ^3.8.17 debug: ^4.3.4 globby: ^11.1.0 is-wsl: ^2.1.1 - tslib: ^2.5.0 - checksum: 540673036ddc8712ea88a89262a0fd82f297da716bfc8a1b0346a85b2bdbe3c00cffa5f4b965b169e61256b14d3f3323a7e2c229d266c44bbb5ba020935037cc + tslib: ^2.6.1 + checksum: 6f261d9eb07e3a0f5c493eb929231787bbe6f99f68e6a7c84e68f60a58c5c5f31a03d0a593b0a74c9a6611be1f2e40ae4dcdaa2c4d231fefa096ade0cc5b4089 languageName: node linkType: hard @@ -9166,10 +6695,10 @@ __metadata: linkType: hard "@oclif/help@npm:^1.0.1": - version: 1.0.8 - resolution: "@oclif/help@npm:1.0.8" + version: 1.0.15 + resolution: "@oclif/help@npm:1.0.15" dependencies: - "@oclif/config": 1.18.10 + "@oclif/config": 1.18.16 "@oclif/errors": 1.3.6 chalk: ^4.1.2 indent-string: ^4.0.0 @@ -9178,7 +6707,7 @@ __metadata: strip-ansi: ^6.0.0 widest-line: ^3.1.0 wrap-ansi: ^6.2.0 - checksum: 2c1e65a9f459550b0c8d651282d59e1e35c49a59d2345f31a46e0ec67704ac73a582d3c8729e2d5581d1d4b66e52fb9b3e43315b67b28171dd540ea4fb184254 + checksum: 433b722f0a97e1ab617261f917b0ff126a8a3e33c622de60dc00730a6b81f6f38bc7e9e2a9730b4b8a2ce8138ac8f59b9f07871d913eb5ef23419dccdbcf4486 languageName: node linkType: hard @@ -9189,15 +6718,15 @@ __metadata: languageName: node linkType: hard -"@oclif/parser@npm:^3.8.0, @oclif/parser@npm:^3.8.12, @oclif/parser@npm:^3.8.13": - version: 3.8.13 - resolution: "@oclif/parser@npm:3.8.13" +"@oclif/parser@npm:^3.8.0, @oclif/parser@npm:^3.8.16, @oclif/parser@npm:^3.8.17": + version: 3.8.17 + resolution: "@oclif/parser@npm:3.8.17" dependencies: "@oclif/errors": ^1.3.6 "@oclif/linewrap": ^1.0.0 chalk: ^4.1.0 - tslib: ^2.6.0 - checksum: 45004ae47321444160194846e477392937996f7b31ae1ae8554ac488a77e02a1386f887a4dc781226df8d2c65bc9032fd092b1c77c26dcf26f95ac012ea367b9 + tslib: ^2.6.2 + checksum: 93bb593d8ec03391d90c0736d43cf97b27cd88c17242e01d1f71d8bae3cbac08ff976a02488220f20f867b4d2c0a9592fa8a4358cca1fd9b67fe580acaa35956 languageName: node linkType: hard @@ -9227,13 +6756,6 @@ __metadata: languageName: node linkType: hard -"@open-draft/until@npm:^1.0.3": - version: 1.0.3 - resolution: "@open-draft/until@npm:1.0.3" - checksum: f88bcd774b55359d14a4fa80f7bfe7d9d6d26a5995e94e823e43b211656daae3663e983f0a996937da286d22f6f5da2087b661845302f236ba27f8529dcd14fb - languageName: node - linkType: hard - "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -9241,45 +6763,6 @@ __metadata: languageName: node linkType: hard -"@pmmmwh/react-refresh-webpack-plugin@npm:^0.5.3": - version: 0.5.10 - resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.10" - dependencies: - ansi-html-community: ^0.0.8 - common-path-prefix: ^3.0.0 - core-js-pure: ^3.23.3 - error-stack-parser: ^2.0.6 - find-up: ^5.0.0 - html-entities: ^2.1.0 - loader-utils: ^2.0.4 - schema-utils: ^3.0.0 - source-map: ^0.7.3 - peerDependencies: - "@types/webpack": 4.x || 5.x - react-refresh: ">=0.10.0 <1.0.0" - sockjs-client: ^1.4.0 - type-fest: ">=0.17.0 <4.0.0" - webpack: ">=4.43.0 <6.0.0" - webpack-dev-server: 3.x || 4.x - webpack-hot-middleware: 2.x - webpack-plugin-serve: 0.x || 1.x - peerDependenciesMeta: - "@types/webpack": - optional: true - sockjs-client: - optional: true - type-fest: - optional: true - webpack-dev-server: - optional: true - webpack-hot-middleware: - optional: true - webpack-plugin-serve: - optional: true - checksum: e470b543c5e8d73eeaa73636e1976e6719db6ae29c93fa62818f5796c1883051f379a3cb1ff85d909ef2c6bb9ef13ca46c36f1878c48d143b1355fea6660e547 - languageName: node - linkType: hard - "@radix-ui/number@npm:1.0.1": version: 1.0.1 resolution: "@radix-ui/number@npm:1.0.1" @@ -9335,7 +6818,7 @@ __metadata: languageName: node linkType: hard -"@radix-ui/react-alert-dialog@npm:^1.0.4": +"@radix-ui/react-alert-dialog@npm:1.0.4": version: 1.0.4 resolution: "@radix-ui/react-alert-dialog@npm:1.0.4" dependencies: @@ -9381,8 +6864,8 @@ __metadata: linkType: hard "@radix-ui/react-avatar@npm:^1.0.3": - version: 1.0.3 - resolution: "@radix-ui/react-avatar@npm:1.0.3" + version: 1.0.4 + resolution: "@radix-ui/react-avatar@npm:1.0.4" dependencies: "@babel/runtime": ^7.13.10 "@radix-ui/react-context": 1.0.1 @@ -9399,7 +6882,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: f6f8965c6133f635ad51a8448e333276a7bfac3ee845ff2f7f7330a8c76f5bd49da7ca4167125a9879e0611b09b0ebfb1c30ccc10838e413fd23c4b25a0ffe98 + checksum: 608494c53968085bfcf9b987d80c3ec6720bdb65f78591d53e8bba3b360e86366d48a7dee11405dd443f5a3565432184b95bb9d4954bca1922cc9385a942caaf languageName: node linkType: hard @@ -9558,7 +7041,7 @@ __metadata: languageName: node linkType: hard -"@radix-ui/react-dialog@npm:1.0.4, @radix-ui/react-dialog@npm:^1.0.4": +"@radix-ui/react-dialog@npm:1.0.4": version: 1.0.4 resolution: "@radix-ui/react-dialog@npm:1.0.4" dependencies: @@ -9672,15 +7155,15 @@ __metadata: linkType: hard "@radix-ui/react-dropdown-menu@npm:^2.0.5": - version: 2.0.5 - resolution: "@radix-ui/react-dropdown-menu@npm:2.0.5" + version: 2.0.6 + resolution: "@radix-ui/react-dropdown-menu@npm:2.0.6" dependencies: "@babel/runtime": ^7.13.10 "@radix-ui/primitive": 1.0.1 "@radix-ui/react-compose-refs": 1.0.1 "@radix-ui/react-context": 1.0.1 "@radix-ui/react-id": 1.0.1 - "@radix-ui/react-menu": 2.0.5 + "@radix-ui/react-menu": 2.0.6 "@radix-ui/react-primitive": 1.0.3 "@radix-ui/react-use-controllable-state": 1.0.1 peerDependencies: @@ -9693,7 +7176,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: fdc163b07894101a88bd2b0a6a425838b5e4164fb0dcf306e215120ebe034c7f2c114f7d4c2b20eb48d90402fb1caefb61a22b2c2084b40d63fa551429fe6e86 + checksum: 525cab53547d2ce2904518b1f66b62179d656c57c8d6dd7dbe863cc05025d8bad535f44011e2735b07fc500579c3d64d89a9a39593d4c8f91f31052d75b729e1 languageName: node linkType: hard @@ -9858,9 +7341,9 @@ __metadata: languageName: node linkType: hard -"@radix-ui/react-menu@npm:2.0.5": - version: 2.0.5 - resolution: "@radix-ui/react-menu@npm:2.0.5" +"@radix-ui/react-menu@npm:2.0.6": + version: 2.0.6 + resolution: "@radix-ui/react-menu@npm:2.0.6" dependencies: "@babel/runtime": ^7.13.10 "@radix-ui/primitive": 1.0.1 @@ -9868,12 +7351,12 @@ __metadata: "@radix-ui/react-compose-refs": 1.0.1 "@radix-ui/react-context": 1.0.1 "@radix-ui/react-direction": 1.0.1 - "@radix-ui/react-dismissable-layer": 1.0.4 + "@radix-ui/react-dismissable-layer": 1.0.5 "@radix-ui/react-focus-guards": 1.0.1 - "@radix-ui/react-focus-scope": 1.0.3 + "@radix-ui/react-focus-scope": 1.0.4 "@radix-ui/react-id": 1.0.1 - "@radix-ui/react-popper": 1.1.2 - "@radix-ui/react-portal": 1.0.3 + "@radix-ui/react-popper": 1.1.3 + "@radix-ui/react-portal": 1.0.4 "@radix-ui/react-presence": 1.0.1 "@radix-ui/react-primitive": 1.0.3 "@radix-ui/react-roving-focus": 1.0.4 @@ -9891,24 +7374,24 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: 9b21a5fb159dc106ea7b45c64cf08487fb4cc1bba2e8696d70320f3e4173f2a0098eeeef16bc846391f569fd2abb5fe7b2ef40de929b9625e18a27f702743705 + checksum: 06926fa59cb8f5614f2e1a085ea1cbf09631ae28fb6e5d6e6d2a0a84d24979e3aca311cdb19dfdb254c1823ff85fd5250c29d4463f8f7622dd523e35df3fce1d languageName: node linkType: hard "@radix-ui/react-popover@npm:^1.0.6": - version: 1.0.6 - resolution: "@radix-ui/react-popover@npm:1.0.6" + version: 1.0.7 + resolution: "@radix-ui/react-popover@npm:1.0.7" dependencies: "@babel/runtime": ^7.13.10 "@radix-ui/primitive": 1.0.1 "@radix-ui/react-compose-refs": 1.0.1 "@radix-ui/react-context": 1.0.1 - "@radix-ui/react-dismissable-layer": 1.0.4 + "@radix-ui/react-dismissable-layer": 1.0.5 "@radix-ui/react-focus-guards": 1.0.1 - "@radix-ui/react-focus-scope": 1.0.3 + "@radix-ui/react-focus-scope": 1.0.4 "@radix-ui/react-id": 1.0.1 - "@radix-ui/react-popper": 1.1.2 - "@radix-ui/react-portal": 1.0.3 + "@radix-ui/react-popper": 1.1.3 + "@radix-ui/react-portal": 1.0.4 "@radix-ui/react-presence": 1.0.1 "@radix-ui/react-primitive": 1.0.3 "@radix-ui/react-slot": 1.0.2 @@ -9925,7 +7408,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: 1b9fd21f6b73a74af88c5cd151f7de2a8dcc46a4d7ac7bee1104d5a45869f170bcb2490c3205b18597457b9153e71016bc1f71077938317e07eca5cf45fca7ae + checksum: ed7abbd61df1e15d62072e214fafbdc4e31942e0ce49665f2045d8279944a0a37762bcd70a36389ed9e43c95797d5acb57f6f5ca5a15b688b1928cfc2b9ce196 languageName: node linkType: hard @@ -10000,7 +7483,7 @@ __metadata: languageName: node linkType: hard -"@radix-ui/react-portal@npm:1.0.3, @radix-ui/react-portal@npm:^1.0.3": +"@radix-ui/react-portal@npm:1.0.3": version: 1.0.3 resolution: "@radix-ui/react-portal@npm:1.0.3" dependencies: @@ -10020,7 +7503,7 @@ __metadata: languageName: node linkType: hard -"@radix-ui/react-portal@npm:1.0.4": +"@radix-ui/react-portal@npm:1.0.4, @radix-ui/react-portal@npm:^1.0.3": version: 1.0.4 resolution: "@radix-ui/react-portal@npm:1.0.4" dependencies: @@ -10166,8 +7649,8 @@ __metadata: linkType: hard "@radix-ui/react-scroll-area@npm:^1.0.4": - version: 1.0.4 - resolution: "@radix-ui/react-scroll-area@npm:1.0.4" + version: 1.0.5 + resolution: "@radix-ui/react-scroll-area@npm:1.0.5" dependencies: "@babel/runtime": ^7.13.10 "@radix-ui/number": 1.0.1 @@ -10189,7 +7672,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: 719ee9908b63d1059da8b0dc8161d6ae635371cbc5101bfb6fc940aa017171bd03184db1e0a5c54370294e6936c6779fe5671dd7599f638899dcfc8e197bb7aa + checksum: a08818aeeb15920a02e708699a8bdc85c26eab0579ab741129b464a799b5d9a04f81810a2d200f1cf4aef03452067770e87b0f81593a689350fcd7e51819e4cb languageName: node linkType: hard @@ -10449,17 +7932,17 @@ __metadata: linkType: hard "@radix-ui/react-tooltip@npm:^1.0.6": - version: 1.0.6 - resolution: "@radix-ui/react-tooltip@npm:1.0.6" + version: 1.0.7 + resolution: "@radix-ui/react-tooltip@npm:1.0.7" dependencies: "@babel/runtime": ^7.13.10 "@radix-ui/primitive": 1.0.1 "@radix-ui/react-compose-refs": 1.0.1 "@radix-ui/react-context": 1.0.1 - "@radix-ui/react-dismissable-layer": 1.0.4 + "@radix-ui/react-dismissable-layer": 1.0.5 "@radix-ui/react-id": 1.0.1 - "@radix-ui/react-popper": 1.1.2 - "@radix-ui/react-portal": 1.0.3 + "@radix-ui/react-popper": 1.1.3 + "@radix-ui/react-portal": 1.0.4 "@radix-ui/react-presence": 1.0.1 "@radix-ui/react-primitive": 1.0.3 "@radix-ui/react-slot": 1.0.2 @@ -10475,7 +7958,7 @@ __metadata: optional: true "@types/react-dom": optional: true - checksum: b6c4f448c7f7f4016dbc5f93ba7e933037327ba5a34cb5296e8b07e07d8eb23e2a5908cc0054d7d40549292d43d11685bf2c176869effe8e98b25c391c76630c + checksum: 915524ea9d102eb26e656c550a084ca460219041c0e7cec0e72b522ee52a43b4d725f4ad3352212f4ae88b3672ef7b23bad07844275cafea075ada590678d873 languageName: node linkType: hard @@ -10664,263 +8147,281 @@ __metadata: linkType: hard "@react-aria/datepicker@npm:^3.5.0": - version: 3.6.0 - resolution: "@react-aria/datepicker@npm:3.6.0" + version: 3.10.0 + resolution: "@react-aria/datepicker@npm:3.10.0" dependencies: - "@internationalized/date": ^3.4.0 - "@internationalized/number": ^3.2.1 - "@internationalized/string": ^3.1.1 - "@react-aria/focus": ^3.14.0 - "@react-aria/i18n": ^3.8.1 - "@react-aria/interactions": ^3.17.0 - "@react-aria/label": ^3.6.1 - "@react-aria/spinbutton": ^3.5.1 - "@react-aria/utils": ^3.19.0 - "@react-stately/datepicker": ^3.6.0 - "@react-types/button": ^3.7.4 - "@react-types/calendar": ^3.3.1 - "@react-types/datepicker": ^3.5.0 - "@react-types/dialog": ^3.5.4 - "@react-types/shared": ^3.19.0 + "@internationalized/date": ^3.5.3 + "@internationalized/number": ^3.5.2 + "@internationalized/string": ^3.2.2 + "@react-aria/focus": ^3.17.0 + "@react-aria/form": ^3.0.4 + "@react-aria/i18n": ^3.11.0 + "@react-aria/interactions": ^3.21.2 + "@react-aria/label": ^3.7.7 + "@react-aria/spinbutton": ^3.6.4 + "@react-aria/utils": ^3.24.0 + "@react-stately/datepicker": ^3.9.3 + "@react-stately/form": ^3.0.2 + "@react-types/button": ^3.9.3 + "@react-types/calendar": ^3.4.5 + "@react-types/datepicker": ^3.7.3 + "@react-types/dialog": ^3.5.9 + "@react-types/shared": ^3.23.0 "@swc/helpers": ^0.5.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: b923ae7b04108724f12c3a248d33000490e9e1f8217971557f0b20ac2375e58b1c8d1f713d7e40a97270eb5702a4c2dcd2898dc99cc0d58f48090f9b75905a8a + checksum: 4f8ef1fb8ea2b6aa57f5298cc1b48fa904fb2bbd7643b06b3c7577227008e3c7076e4ae9d8545a50cce28b545fb5868dced1bf2df35cf1a0d5f15ad8e050c2bf languageName: node linkType: hard -"@react-aria/focus@npm:^3.14.0": - version: 3.14.0 - resolution: "@react-aria/focus@npm:3.14.0" - dependencies: - "@react-aria/interactions": ^3.17.0 - "@react-aria/utils": ^3.19.0 - "@react-types/shared": ^3.19.0 - "@swc/helpers": ^0.5.0 - clsx: ^1.1.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 64ae1f37395b132b0a8fb866c171f8796139177254babff41480c132187ccb712b21697b22f6c227670fa78b2d4998b1892d9179e56d203e8e99f86be67951ed - languageName: node - linkType: hard - -"@react-aria/i18n@npm:^3.8.1": - version: 3.8.1 - resolution: "@react-aria/i18n@npm:3.8.1" - dependencies: - "@internationalized/date": ^3.4.0 - "@internationalized/message": ^3.1.1 - "@internationalized/number": ^3.2.1 - "@internationalized/string": ^3.1.1 - "@react-aria/ssr": ^3.7.1 - "@react-aria/utils": ^3.19.0 - "@react-types/shared": ^3.19.0 - "@swc/helpers": ^0.5.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: e2a94b8e6e4250d60f70c3f63e5adae0a90f5f88ecc8bd54b0980effe0d53cbb4a765978573aa591100a22124f6f28e434c7fa94c9eda59f7c040bdaea542160 - languageName: node - linkType: hard - -"@react-aria/interactions@npm:^3.17.0": +"@react-aria/focus@npm:^3.17.0": version: 3.17.0 - resolution: "@react-aria/interactions@npm:3.17.0" + resolution: "@react-aria/focus@npm:3.17.0" dependencies: - "@react-aria/ssr": ^3.7.1 - "@react-aria/utils": ^3.19.0 - "@react-types/shared": ^3.19.0 + "@react-aria/interactions": ^3.21.2 + "@react-aria/utils": ^3.24.0 + "@react-types/shared": ^3.23.0 + "@swc/helpers": ^0.5.0 + clsx: ^2.0.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + checksum: 7e9cb239c0a39f8c9397b295b7f4ba4c3c21f613ed53cdf814ceb913f8356f633c1c0dd3d6470956da69571f887542526142d264ccf0ad89e2faeec5f7562e3c + languageName: node + linkType: hard + +"@react-aria/form@npm:^3.0.4": + version: 3.0.4 + resolution: "@react-aria/form@npm:3.0.4" + dependencies: + "@react-aria/interactions": ^3.21.2 + "@react-aria/utils": ^3.24.0 + "@react-stately/form": ^3.0.2 + "@react-types/shared": ^3.23.0 "@swc/helpers": ^0.5.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 8b2791ae03a16103e15cc482a3e532b8b794506d3ee7602daf736177b57d0ed915156a5574c39c243c04cd4fd59fd7fc4e07e7408da5062c912f1eb49577bc2d + checksum: ced781730a298270feb458eaafd92ce51c00e0c12cce059f92dffc4c9d0f1ff67139d0a9979c39c3cd446bf4d04deea1b3fd1b149a43c5e868a6ab0176d1b463 languageName: node linkType: hard -"@react-aria/label@npm:^3.6.1": - version: 3.6.1 - resolution: "@react-aria/label@npm:3.6.1" +"@react-aria/i18n@npm:^3.11.0": + version: 3.11.0 + resolution: "@react-aria/i18n@npm:3.11.0" dependencies: - "@react-aria/utils": ^3.19.0 - "@react-types/label": ^3.7.5 - "@react-types/shared": ^3.19.0 + "@internationalized/date": ^3.5.3 + "@internationalized/message": ^3.1.3 + "@internationalized/number": ^3.5.2 + "@internationalized/string": ^3.2.2 + "@react-aria/ssr": ^3.9.3 + "@react-aria/utils": ^3.24.0 + "@react-types/shared": ^3.23.0 "@swc/helpers": ^0.5.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: cb1f7ef1c467d5392ffd19c07988358a472b1379767d192b2645a00c7a3e4d5291c4b886e4132d1b20052bf98697e44ca8f19aad8f7aac125eef0a375d6d9588 + checksum: ac520438e951fe9d61c9086815e2e8b39df3c275698e155e670bd771a2381cc1be15de946608671fd79bdc7cb547e80903492b4fb446d04fc167a91cf60b1934 languageName: node linkType: hard -"@react-aria/live-announcer@npm:^3.3.1": - version: 3.3.1 - resolution: "@react-aria/live-announcer@npm:3.3.1" +"@react-aria/interactions@npm:^3.21.2": + version: 3.21.2 + resolution: "@react-aria/interactions@npm:3.21.2" + dependencies: + "@react-aria/ssr": ^3.9.3 + "@react-aria/utils": ^3.24.0 + "@react-types/shared": ^3.23.0 + "@swc/helpers": ^0.5.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + checksum: 135b14891c4c6a72b1d61a0e231d3f0111e5549cae17b27a8accb8d18bc7af8bd9886932040f65d756488da5a0555b3de9bc4a870cccbd39f4e56ae3fb28374e + languageName: node + linkType: hard + +"@react-aria/label@npm:^3.7.7": + version: 3.7.7 + resolution: "@react-aria/label@npm:3.7.7" + dependencies: + "@react-aria/utils": ^3.24.0 + "@react-types/shared": ^3.23.0 + "@swc/helpers": ^0.5.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + checksum: f8e2c222627df4da6b18cbff15508b87205e9830f4612fc94fd9270b620aa65c482a94fa5c13e9687142bcca6c2b73405ed5c0288b6329f44e9ba241bab506d3 + languageName: node + linkType: hard + +"@react-aria/live-announcer@npm:^3.3.3": + version: 3.3.3 + resolution: "@react-aria/live-announcer@npm:3.3.3" dependencies: "@swc/helpers": ^0.5.0 - checksum: c105324714f8d2a2f0a4837913e9dc59cf39405659e6ec65997c591cc4d3e43d39f1c65ff3a8150e86c067f76dd39177332d2dc8d8d5d75a02bbd331be4499b3 + checksum: 99e46a37dfa621168ab7108ee4cf13ddbc36dcbc3d75030985ab9c2f78ec4eb5e992cd9a6a8e57f61abde3291b9b51efd32551a1adcfb43691df2b8dac70f922 languageName: node linkType: hard -"@react-aria/spinbutton@npm:^3.5.1": - version: 3.5.1 - resolution: "@react-aria/spinbutton@npm:3.5.1" +"@react-aria/spinbutton@npm:^3.6.4": + version: 3.6.4 + resolution: "@react-aria/spinbutton@npm:3.6.4" dependencies: - "@react-aria/i18n": ^3.8.1 - "@react-aria/live-announcer": ^3.3.1 - "@react-aria/utils": ^3.19.0 - "@react-types/button": ^3.7.4 - "@react-types/shared": ^3.19.0 + "@react-aria/i18n": ^3.11.0 + "@react-aria/live-announcer": ^3.3.3 + "@react-aria/utils": ^3.24.0 + "@react-types/button": ^3.9.3 + "@react-types/shared": ^3.23.0 "@swc/helpers": ^0.5.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 15e4bcdb3ac46480f439a0a969aeb95bb98249c9fdfcee040713fd79abd7bda7b87bc3174d569168746507252d708adcdfe19429c2d56be0e2eb083d01aded0a + checksum: 130aea4ce21e3d5eb840f116dfd76ff016696e8516d51f16febbd815aa8a2c0f71f4218b8cfe9e29fff151819b1172f7e5a253323ffeeff8533093de5a22688e languageName: node linkType: hard -"@react-aria/ssr@npm:^3.7.1": - version: 3.7.1 - resolution: "@react-aria/ssr@npm:3.7.1" +"@react-aria/ssr@npm:^3.9.3": + version: 3.9.3 + resolution: "@react-aria/ssr@npm:3.9.3" dependencies: "@swc/helpers": ^0.5.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 04a7b3a01bfca7841eb80fdc21ec10e908cfb1f500fc8c4466e23b5309f095ee6f87fd52e4e200778a2db2c491046b0e85aa085f63bf8ee1d75923254bc47e6b + checksum: 3243c64390aba4a1fc25db02bb5a9794e767480bf01945834a61f2c1ec6e11dd9c3c8c20355264ec83a46d1004031be93b421bbbc23c7f0a71351a094cefc5e1 languageName: node linkType: hard -"@react-aria/utils@npm:^3.19.0": - version: 3.19.0 - resolution: "@react-aria/utils@npm:3.19.0" +"@react-aria/utils@npm:^3.24.0": + version: 3.24.0 + resolution: "@react-aria/utils@npm:3.24.0" dependencies: - "@react-aria/ssr": ^3.7.1 - "@react-stately/utils": ^3.7.0 - "@react-types/shared": ^3.19.0 + "@react-aria/ssr": ^3.9.3 + "@react-stately/utils": ^3.10.0 + "@react-types/shared": ^3.23.0 "@swc/helpers": ^0.5.0 - clsx: ^1.1.1 + clsx: ^2.0.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 881acd7a88a7850b9c1843c029a718d7497c1aca8c7e04aaf54293303c66785f91511f50ff86505e5a43a9ed4eddb30c7575f829891672ede700225d099cfec6 + checksum: 8b79ee7a470032a598774d8ed45f0577cb21558e05188cd1c2628ade33082746d70b197fc6a0afb9ecaa924e6604eac649184031daeb9c2f763e296ffacdfad9 languageName: node linkType: hard -"@react-stately/datepicker@npm:^3.5.0, @react-stately/datepicker@npm:^3.6.0": - version: 3.6.0 - resolution: "@react-stately/datepicker@npm:3.6.0" +"@react-stately/datepicker@npm:^3.5.0, @react-stately/datepicker@npm:^3.9.3": + version: 3.9.3 + resolution: "@react-stately/datepicker@npm:3.9.3" dependencies: - "@internationalized/date": ^3.4.0 - "@internationalized/string": ^3.1.1 - "@react-stately/overlays": ^3.6.1 - "@react-stately/utils": ^3.7.0 - "@react-types/datepicker": ^3.5.0 - "@react-types/shared": ^3.19.0 + "@internationalized/date": ^3.5.3 + "@internationalized/string": ^3.2.2 + "@react-stately/form": ^3.0.2 + "@react-stately/overlays": ^3.6.6 + "@react-stately/utils": ^3.10.0 + "@react-types/datepicker": ^3.7.3 + "@react-types/shared": ^3.23.0 "@swc/helpers": ^0.5.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: bce61fdead1487f2b03a86e1d99ad2ce36859d3f09d2b4bb1e5a2ecb2b61d3ab1cbce2831c7993575e5c21d64aaa90b2061364de03ea1bd4b133c48d6d6c8b4a + checksum: c523a72901422c942ec2e6926745d8984a3915427df476ff1ef2d59e9cefddb23b0292879d7f99bb91ed01026e3184941cabccc89f3231d84ebbed26987f1873 languageName: node linkType: hard -"@react-stately/overlays@npm:^3.6.1": - version: 3.6.1 - resolution: "@react-stately/overlays@npm:3.6.1" +"@react-stately/form@npm:^3.0.2": + version: 3.0.2 + resolution: "@react-stately/form@npm:3.0.2" dependencies: - "@react-stately/utils": ^3.7.0 - "@react-types/overlays": ^3.8.1 + "@react-types/shared": ^3.23.0 "@swc/helpers": ^0.5.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 59986fbd006457052867c6bd53a17bac32c74210631e14bd8018bca2dfee941ffdb3eb6d912ea0e4486fafcba62f6d56bbc35686560b3b7491fef2f8c9b607d8 + checksum: 83f3174859e1199d87816c85d7e6ffc76af726ae63e413fd6d19bc588c6b649684d8af7f7903bf2e0649d320899e6ba22e02ef7106a4f08a9d803f63cec3c0d8 languageName: node linkType: hard -"@react-stately/utils@npm:^3.7.0": - version: 3.7.0 - resolution: "@react-stately/utils@npm:3.7.0" +"@react-stately/overlays@npm:^3.6.6": + version: 3.6.6 + resolution: "@react-stately/overlays@npm:3.6.6" + dependencies: + "@react-stately/utils": ^3.10.0 + "@react-types/overlays": ^3.8.6 + "@swc/helpers": ^0.5.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + checksum: 1438bef13516d1c2a4957ca3a76a0a355ac821de803ee1dc6b0a7354dcab6c172d46fcf931d12f1a74be8c6af111cab77da5fa34af014a6b44f5cd6baa614228 + languageName: node + linkType: hard + +"@react-stately/utils@npm:^3.10.0": + version: 3.10.0 + resolution: "@react-stately/utils@npm:3.10.0" dependencies: "@swc/helpers": ^0.5.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 8a7c191d64d0474e304c041222977ece44da4af7d0c49364d67bc23d0a5a1c2665f086c5c570aa5e372f97b791bef0a7d8de236ee5e40d3d3517ee51030b0066 + checksum: 5d231c8393dba617c1ff84fb5fca0478af9474ccafec1012abd50c69c9f24c091ded6ec6a2f955a4f4d0fe130ea987728cd9b916e18831a2dab1d37ac2407967 languageName: node linkType: hard -"@react-types/button@npm:^3.7.4": - version: 3.7.4 - resolution: "@react-types/button@npm:3.7.4" +"@react-types/button@npm:^3.9.3": + version: 3.9.3 + resolution: "@react-types/button@npm:3.9.3" dependencies: - "@react-types/shared": ^3.19.0 + "@react-types/shared": ^3.23.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 1905a78468e36eb384e4da3b3fd65ee211d5507b444b744a39aee584435814883dcfd29a000d6ec2e2dc93fec5452ba1115372ba6e5b265115197cb635f8a4f0 + checksum: 4447f16762573248f809f7602034da4562116a8d0e2d2213bb7eb91f0b23f161440959e482c280eb424c73013bfecc63b83cdd60939438852b3cb68c16073272 languageName: node linkType: hard -"@react-types/calendar@npm:^3.3.1": - version: 3.3.1 - resolution: "@react-types/calendar@npm:3.3.1" +"@react-types/calendar@npm:^3.4.5": + version: 3.4.5 + resolution: "@react-types/calendar@npm:3.4.5" dependencies: - "@internationalized/date": ^3.4.0 - "@react-types/shared": ^3.19.0 + "@internationalized/date": ^3.5.3 + "@react-types/shared": ^3.23.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 0141b8112fc285fa39c09645193e0044d3a7f5a2f0c93078e5d9679a55a7016a45e534764d461e52ad116061d23d286788d5e6f6f61c7f65eb2e63fb61b07b83 + checksum: 45e92fdbcbe72cf01acaab93bee1d8c44d8cbcb0dd4f771bed10217b562ed9fb4a61674dab0d7ad0145c71e4dda57891f3b43ffb5aece43c7982679a1ffd98ce languageName: node linkType: hard -"@react-types/datepicker@npm:^3.5.0": - version: 3.5.0 - resolution: "@react-types/datepicker@npm:3.5.0" +"@react-types/datepicker@npm:^3.7.3": + version: 3.7.3 + resolution: "@react-types/datepicker@npm:3.7.3" dependencies: - "@internationalized/date": ^3.4.0 - "@react-types/calendar": ^3.3.1 - "@react-types/overlays": ^3.8.1 - "@react-types/shared": ^3.19.0 + "@internationalized/date": ^3.5.3 + "@react-types/calendar": ^3.4.5 + "@react-types/overlays": ^3.8.6 + "@react-types/shared": ^3.23.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: e4acd7a33567e8c945efedb3c4abeba3dec35085ef9cfccd7ed4131ab443f83aeddf4e639f11927df022bde45e9119cd1c787509307d2173af0ee2890b078721 + checksum: 1f001cb716c18a41490015bd413a6ea234d78af4e26554113e5ebd71785506cbf588bd8121f0a7eda9b9b9ccd9d5d867922fdcdf19b5391e5ca76e52c262abc3 languageName: node linkType: hard -"@react-types/dialog@npm:^3.5.4": - version: 3.5.4 - resolution: "@react-types/dialog@npm:3.5.4" +"@react-types/dialog@npm:^3.5.9": + version: 3.5.9 + resolution: "@react-types/dialog@npm:3.5.9" dependencies: - "@react-types/overlays": ^3.8.1 - "@react-types/shared": ^3.19.0 + "@react-types/overlays": ^3.8.6 + "@react-types/shared": ^3.23.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 547ebdc6417afc74639fc2081bb245ee8fb1cad56bdb0e54385b58e635c8e5e8773fd3223c4f4d765159cf42c4bb779eb0b58eab738d84a5cf3b7febb67ee47f + checksum: a3c60c85c529e29932a5d7f9f56da21f6862c2869ce9898a34bd9a8e800212a135f873fbf1fdc5aaff9eab800a851069adfca988ccb50e09ae4eece02dd569db languageName: node linkType: hard -"@react-types/label@npm:^3.7.5": - version: 3.7.5 - resolution: "@react-types/label@npm:3.7.5" +"@react-types/overlays@npm:^3.8.6": + version: 3.8.6 + resolution: "@react-types/overlays@npm:3.8.6" dependencies: - "@react-types/shared": ^3.19.0 + "@react-types/shared": ^3.23.0 peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: e8e776dc0dec4efb2065733499152cea581068b3afb2cd5bb40076745155e90f85eb3f2ed0671dafa6ef9a782a023970fa94550260923d30fb2cebc8ef80a8fd + checksum: d2efbe26c47254941195249e2f600ba0d0f85b326e120d7ad7b08665af3cbfc7f1cf223b18a2a0058c909bdc7f8a1fd466c71884b8de50e2aa76e5c8f685bd04 languageName: node linkType: hard -"@react-types/overlays@npm:^3.8.1": - version: 3.8.1 - resolution: "@react-types/overlays@npm:3.8.1" - dependencies: - "@react-types/shared": ^3.19.0 +"@react-types/shared@npm:^3.23.0": + version: 3.23.0 + resolution: "@react-types/shared@npm:3.23.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 690917049157712ff63e0af74f22714a83bcbec68950239053ef2568284fdebe697f00598e5944ac786cf84439d9baad1ce36273de01b85ef332fc3aae8ad939 - languageName: node - linkType: hard - -"@react-types/shared@npm:^3.19.0": - version: 3.19.0 - resolution: "@react-types/shared@npm:3.19.0" - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - checksum: 1d259c22485a4b271d560a35fa93bd6d3ffb3899cf493b7fb16122d48cba1507b8ea657b71ac0509eede7dd8c7a30826b8153104b7ae9d2e86f69aa518aa97fa + checksum: f2c76b51b065a277516d7342697bb06e3f0cb22204ddd034da699405c79acbf1752bfb005298ef9c7a79dc9a068d7c756cffcfb920bb591624803a7ab29ef7b6 languageName: node linkType: hard @@ -10942,20 +8443,20 @@ __metadata: linkType: hard "@readme/json-schema-ref-parser@npm:^1.2.0": - version: 1.2.0 - resolution: "@readme/json-schema-ref-parser@npm:1.2.0" + version: 1.2.1 + resolution: "@readme/json-schema-ref-parser@npm:1.2.1" dependencies: "@jsdevtools/ono": ^7.1.3 - "@types/json-schema": ^7.0.6 + "@types/json-schema": ^7.0.12 call-me-maybe: ^1.0.1 js-yaml: ^4.1.0 - checksum: 3a1d3dd7b5a8bcde2ca2ff894fcfebd1752fe633c24a6b6a9ad673dfb61a28e565bdb4beaeb3ac4dd022abeddd28833ac9e52adebe4e44254eede3b685157313 + checksum: e9487c8af051733dd4e54648009cd9dd43be2abcfc6fd0abe19bae788f944153df67caff560898c1d6bdf90ec2d3b63a24596dc7c4b37baa6293fa982eb8335c languageName: node linkType: hard "@readme/openapi-parser@npm:^2.4.0": - version: 2.5.0 - resolution: "@readme/openapi-parser@npm:2.5.0" + version: 2.5.1 + resolution: "@readme/openapi-parser@npm:2.5.1" dependencies: "@apidevtools/openapi-schemas": ^2.1.0 "@apidevtools/swagger-methods": ^3.0.2 @@ -10967,7 +8468,7 @@ __metadata: call-me-maybe: ^1.0.1 peerDependencies: openapi-types: ">=7" - checksum: 4a70eae10c79f5a26ca0df8c558daf6547d0089c111b6b68e4bf6ee251be6f4fe0c4b6c7cbb731a90aaccdee4c21ed89a081bc28cbc464dce2fd7fa4add87661 + checksum: d6c28d2a6369de749862184f8a68e8ff8d7689c15fac55a15e2f474172a63ad0679657ceec7a9c49efd6f7545dc29da6772c6cdc88e60529ad6793e527b5eaf0 languageName: node linkType: hard @@ -10984,13 +8485,15 @@ __metadata: linkType: hard "@redocly/cli@npm:^1.7.0": - version: 1.7.0 - resolution: "@redocly/cli@npm:1.7.0" + version: 1.12.0 + resolution: "@redocly/cli@npm:1.12.0" dependencies: - "@redocly/openapi-core": 1.7.0 + "@redocly/openapi-core": 1.12.0 + abort-controller: ^3.0.0 chokidar: ^3.5.1 colorette: ^1.2.0 core-js: ^3.32.1 + form-data: ^4.0.0 get-port-please: ^3.0.1 glob: ^7.1.6 handlebars: ^4.7.6 @@ -11006,15 +8509,23 @@ __metadata: bin: openapi: bin/cli.js redocly: bin/cli.js - checksum: 9aacefbe3e23239ed0ed419797fdfaf988a850b4a57b08ca23c031a19ce6553f7f7b32118c5e47fb3515a5c4e62d95bc43046e5d2dab08c12ec14fbbb11d483a + checksum: 92f863587bf89170574e8e97f2f65df316da0ddd59756df5eca9f9a07b9902016ad3b731a9aafdf34ac6df99b6956147da086a3e3c6c76137a8567bbf999b461 languageName: node linkType: hard -"@redocly/openapi-core@npm:1.7.0, @redocly/openapi-core@npm:^1.0.0-rc.2": - version: 1.7.0 - resolution: "@redocly/openapi-core@npm:1.7.0" +"@redocly/config@npm:^0.2.0": + version: 0.2.0 + resolution: "@redocly/config@npm:0.2.0" + checksum: 8d41a393734f3681c1df778095753666c6dd30ca03c873fbad1417e461093a8b86688c67023a83faab55d9ea1550eedf7435822f0f487b46b3762719de74b12f + languageName: node + linkType: hard + +"@redocly/openapi-core@npm:1.12.0, @redocly/openapi-core@npm:^1.4.0": + version: 1.12.0 + resolution: "@redocly/openapi-core@npm:1.12.0" dependencies: "@redocly/ajv": ^8.11.0 + "@redocly/config": ^0.2.0 colorette: ^1.2.0 js-levenshtein: ^1.1.6 js-yaml: ^4.1.0 @@ -11023,7 +8534,7 @@ __metadata: node-fetch: ^2.6.1 pluralize: ^8.0.0 yaml-ast-parser: 0.0.43 - checksum: f90e3fc481847fdb9849c689914b8741fca2366c2581830dd2c9228f4d19f6da53bf964089749094e0a5ff41ce7acd1ab7126261af040827099fb71b4ef4d128 + checksum: 0061ee818ece25f1cbc63e8f30beef08b8afee25c6b4524e7dd50a213e726bbe3680a3097772fd1a9e439b28137f1cea2bdf376eecee664d780bf6823a9c182b languageName: node linkType: hard @@ -11164,8 +8675,8 @@ __metadata: linkType: hard "@rollup/plugin-replace@npm:^5.0.2": - version: 5.0.4 - resolution: "@rollup/plugin-replace@npm:5.0.4" + version: 5.0.5 + resolution: "@rollup/plugin-replace@npm:5.0.5" dependencies: "@rollup/pluginutils": ^5.0.1 magic-string: ^0.30.3 @@ -11174,7 +8685,7 @@ __metadata: peerDependenciesMeta: rollup: optional: true - checksum: d84cb5f8422263407a93500375c4e8e64fcaa455f4ef0d32a609cb0779f65aa0c64b0a1bf3196e9d3777f92b504033771930896b6eeb98699978a3aab3150228 + checksum: a896ebc67e0aeb59102dd3cc8647cfeaac6d37cf337f2e2ae412a83e14dace2bb65b52271a1186f8d1c1ea151a7f9d387a3d89d03012802af40543481571ea0a languageName: node linkType: hard @@ -11210,25 +8721,9 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^5.0.1": - version: 5.0.2 - resolution: "@rollup/pluginutils@npm:5.0.2" - dependencies: - "@types/estree": ^1.0.0 - estree-walker: ^2.0.2 - picomatch: ^2.3.1 - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 - peerDependenciesMeta: - rollup: - optional: true - checksum: b06f73c15bb59418aa6fbfead5675bab2d6922e15663525ffc2eb8429530bc5add516600adb251cfbf9b60f3d12fb821cde155cb5103415154a476bd0f163432 - languageName: node - linkType: hard - -"@rollup/pluginutils@npm:^5.0.2": - version: 5.0.5 - resolution: "@rollup/pluginutils@npm:5.0.5" +"@rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.0.2": + version: 5.1.0 + resolution: "@rollup/pluginutils@npm:5.1.0" dependencies: "@types/estree": ^1.0.0 estree-walker: ^2.0.2 @@ -11238,119 +8733,165 @@ __metadata: peerDependenciesMeta: rollup: optional: true - checksum: 18a1f5a9afa993a76663cc2102169cd546786b39a3e92bdc8a2a0b408b509d070a02b20970a30daa9d5d0b1b591b5e7734add84b3aaf263178aef5a26cfab2cf + checksum: c7bed15711f942d6fdd3470fef4105b73991f99a478605e13d41888963330a6f9e32be37e6ddb13f012bc7673ff5e54f06f59fd47109436c1c513986a8a7612d languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.9.2" +"@rollup/rollup-android-arm-eabi@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.17.2" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-android-arm64@npm:4.9.2" +"@rollup/rollup-android-arm64@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-android-arm64@npm:4.17.2" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-darwin-arm64@npm:4.9.2" +"@rollup/rollup-darwin-arm64@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-darwin-arm64@npm:4.17.2" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-darwin-x64@npm:4.9.2" +"@rollup/rollup-darwin-x64@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-darwin-x64@npm:4.17.2" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.9.2" - conditions: os=linux & cpu=arm +"@rollup/rollup-linux-arm-gnueabihf@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.17.2" + conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.9.2" +"@rollup/rollup-linux-arm-musleabihf@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.17.2" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.17.2" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.9.2" +"@rollup/rollup-linux-arm64-musl@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.17.2" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.9.2" +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.17.2" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.17.2" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.9.2" +"@rollup/rollup-linux-s390x-gnu@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.17.2" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.17.2" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.9.2" +"@rollup/rollup-linux-x64-musl@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.17.2" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.9.2" +"@rollup/rollup-win32-arm64-msvc@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.17.2" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.9.2" +"@rollup/rollup-win32-ia32-msvc@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.17.2" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.9.2": - version: 4.9.2 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.9.2" +"@rollup/rollup-win32-x64-msvc@npm:4.17.2": + version: 4.17.2 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.17.2" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@rushstack/ts-command-line@npm:^4.12.2": - version: 4.15.1 - resolution: "@rushstack/ts-command-line@npm:4.15.1" +"@rushstack/node-core-library@npm:4.2.0": + version: 4.2.0 + resolution: "@rushstack/node-core-library@npm:4.2.0" dependencies: - "@types/argparse": 1.0.38 - argparse: ~1.0.9 - colors: ~1.2.1 - string-argv: ~0.3.1 - checksum: cd1bb74b9d9c0ae67a328535722f9a39c8622c4f6b549d3f23ff3db42b4714008feb4e707b86c25853c54c4d19a97396f0441a3ef2d2dd249d75a062fc044f8d + fs-extra: ~7.0.1 + import-lazy: ~4.0.0 + jju: ~1.4.0 + resolve: ~1.22.1 + semver: ~7.5.4 + z-schema: ~5.0.2 + peerDependencies: + "@types/node": "*" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: b3f76688452b72ecbd5bef3eb92d86d8c143760bf32d95fc4c4cb71e565ee1f971c3d6dc5f229deb7aece70888f5896547c73a0acf97fa64dfb0564aa0c43bf2 languageName: node linkType: hard -"@sideway/address@npm:^4.1.4": - version: 4.1.4 - resolution: "@sideway/address@npm:4.1.4" +"@rushstack/terminal@npm:0.10.2": + version: 0.10.2 + resolution: "@rushstack/terminal@npm:0.10.2" dependencies: - "@hapi/hoek": ^9.0.0 - checksum: c6fad7d87fb016053e9e9b69c2f2d1f23036d5f1696df141e64c3c58bcf8c7d2a4133348adc2d246682410364d5922c6271ae556122741025794fb7c19814aae + "@rushstack/node-core-library": 4.2.0 + supports-color: ~8.1.1 + peerDependencies: + "@types/node": "*" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 030a5314524294c6a594390da4fa70e59e48cdeee94e3bf683ab83e267cd017e9c4bbfa0674b5ea2d4cfa261cfbceeaaf5aba902fc6db9c43efef08711b3729f + languageName: node + linkType: hard + +"@rushstack/ts-command-line@npm:^4.12.2": + version: 4.19.3 + resolution: "@rushstack/ts-command-line@npm:4.19.3" + dependencies: + "@rushstack/terminal": 0.10.2 + "@types/argparse": 1.0.38 + argparse: ~1.0.9 + string-argv: ~0.3.1 + checksum: 0e64533d7e25044f2e12eefe9cd81b4a69cfa315aed9c402a36128e4212c7f10b7ce99de588696824c6723f6465751b0302ec8f08f84e2da2c18d9e9a3accece languageName: node linkType: hard @@ -11377,13 +8918,6 @@ __metadata: languageName: node linkType: hard -"@sinclair/typebox@npm:^0.25.16": - version: 0.25.24 - resolution: "@sinclair/typebox@npm:0.25.24" - checksum: 2faf9878f3a65a1f2855add80b0fe8c6fe83f084ea1ab432fa7506e7c85c55ae121c4af516d089b5737f5fad23b3628fcc83a6a5df29030c3f611185ce0388ac - languageName: node - linkType: hard - "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" @@ -11408,11 +8942,11 @@ __metadata: linkType: hard "@sinonjs/commons@npm:^3.0.0": - version: 3.0.0 - resolution: "@sinonjs/commons@npm:3.0.0" + version: 3.0.1 + resolution: "@sinonjs/commons@npm:3.0.1" dependencies: type-detect: 4.0.8 - checksum: 1df9cd257942f4e4960dfb9fd339d9e97b6a3da135f3d5b8646562918e863809cb8e00268535f4f4723535d2097881c8fc03d545c414d8555183376cfc54ee84 + checksum: 1227a7b5bd6c6f9584274db996d7f8cee2c8c350534b9d0141fc662eaf1f292ea0ae3ed19e5e5271c8fd390d27e492ca2803acd31a1978be2cdc6be0da711403 languageName: node linkType: hard @@ -11833,15 +9367,6 @@ __metadata: languageName: node linkType: hard -"@smithy/types@npm:^2.2.2": - version: 2.2.2 - resolution: "@smithy/types@npm:2.2.2" - dependencies: - tslib: ^2.5.0 - checksum: d80d03ed59df6784a7b302db5943fa5ac09fe2594784c8895725f831c550d8a1edcdc005a444b74ae67c18f65f70414e70477580fc686a1030ae08774e22c8da - languageName: node - linkType: hard - "@smithy/url-parser@npm:^2.2.0": version: 2.2.0 resolution: "@smithy/url-parser@npm:2.2.0" @@ -12023,250 +9548,61 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-actions@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/addon-actions@npm:6.5.16" +"@storybook/addon-actions@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/addon-actions@npm:7.6.19" dependencies: - "@storybook/addons": 6.5.16 - "@storybook/api": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/components": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/theming": 6.5.16 - core-js: ^3.8.2 - fast-deep-equal: ^3.1.3 - global: ^4.4.0 - lodash: ^4.17.21 - polished: ^4.2.2 - prop-types: ^15.7.2 - react-inspector: ^5.1.0 - regenerator-runtime: ^0.13.7 - telejson: ^6.0.8 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - uuid-browser: ^3.1.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 72d193f7068db610093e08bfedd6dfacf398fac43a1a10ec3aeddc0c7203e9487e5bb71aa83866ef28720230c21e8cc0b6185c4802edc799159da002afe0b2e1 - languageName: node - linkType: hard - -"@storybook/addon-actions@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/addon-actions@npm:7.5.1" - dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/components": 7.5.1 - "@storybook/core-events": 7.5.1 + "@storybook/core-events": 7.6.19 "@storybook/global": ^5.0.0 - "@storybook/manager-api": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/theming": 7.5.1 - "@storybook/types": 7.5.1 + "@types/uuid": ^9.0.1 dequal: ^2.0.2 - lodash: ^4.17.21 polished: ^4.2.2 - prop-types: ^15.7.2 - react-inspector: ^6.0.0 - telejson: ^7.2.0 - ts-dedent: ^2.0.0 uuid: ^9.0.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 9248c4c9e32a6fedd73a370b4b255ba36cbb8f253da910a7892270cc1010d9eadf3f8154efc4c2b46a8e82f03ee3ee42e7fb845d8d829adc513f686ffa7c7877 + checksum: 9a3b8c84088f78c7a9c2178fe0c741615e76abc89ab5a37d35fc2943c92371653a5feb6fca49ca9ed651fecbad47c50d7a8577105e6046ab5f8a433a4c5b6f13 languageName: node linkType: hard -"@storybook/addon-backgrounds@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/addon-backgrounds@npm:6.5.16" +"@storybook/addon-backgrounds@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/addon-backgrounds@npm:7.6.19" dependencies: - "@storybook/addons": 6.5.16 - "@storybook/api": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/components": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/theming": 6.5.16 - core-js: ^3.8.2 - global: ^4.4.0 - memoizerific: ^1.11.3 - regenerator-runtime: ^0.13.7 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: a69a2d80e05664360039953e0effb3af9bdfeddcf6734fb3332854b505506f02914cd079c5571d1101f5c4f7d708b5c7efc71b243434a0a385701f42e0555a67 - languageName: node - linkType: hard - -"@storybook/addon-backgrounds@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/addon-backgrounds@npm:7.5.1" - dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/components": 7.5.1 - "@storybook/core-events": 7.5.1 "@storybook/global": ^5.0.0 - "@storybook/manager-api": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/theming": 7.5.1 - "@storybook/types": 7.5.1 memoizerific: ^1.11.3 ts-dedent: ^2.0.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 6701e538983007f8c8b6c63f496c3639945d0336e3e14ae1cff885cff84c0b2dab4b8e9d6bdc5a8a8a9d51693796ffed95334b2ca4f6dee8d8a3cf50d02f20b2 + checksum: 62dc38c7e36034f998d851860b5c9b2d6bc5847506ab53e63292d3a6c817847ae95e7608daad541ab120583e29213f38c038b314ea07636ee8ac12a1df5bcf63 languageName: node linkType: hard -"@storybook/addon-controls@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/addon-controls@npm:6.5.16" +"@storybook/addon-controls@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/addon-controls@npm:7.6.19" dependencies: - "@storybook/addons": 6.5.16 - "@storybook/api": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/components": 6.5.16 - "@storybook/core-common": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/node-logger": 6.5.16 - "@storybook/store": 6.5.16 - "@storybook/theming": 6.5.16 - core-js: ^3.8.2 + "@storybook/blocks": 7.6.19 lodash: ^4.17.21 ts-dedent: ^2.0.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: a2c9745dce4f646eb2ffa98f57a5618e567a2598fb94f8cca362c27d3fedeb5821902e89b0ed6185032dd0918012f2c5dab8b3914aa5c9b12e810c87642465bc + checksum: 308ac14d8b479e9e105459e40185162351ccbad23b46467d2dc901fc8a4f844fef3e2c6d2731384e9fb54ce5fad28769971fc2aa4b926666a071b3d41d7e90cc languageName: node linkType: hard -"@storybook/addon-controls@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/addon-controls@npm:7.5.1" - dependencies: - "@storybook/blocks": 7.5.1 - "@storybook/client-logger": 7.5.1 - "@storybook/components": 7.5.1 - "@storybook/core-common": 7.5.1 - "@storybook/core-events": 7.5.1 - "@storybook/manager-api": 7.5.1 - "@storybook/node-logger": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/theming": 7.5.1 - "@storybook/types": 7.5.1 - lodash: ^4.17.21 - ts-dedent: ^2.0.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: ae4b7cdd547845820ab877ffb529c69cc1123776608bf84c673e7d5a10d6f2a6f3dc4e0e96514bfbbc261cca6274d9e5d931ce9e27b07dfc429953b37c59c707 - languageName: node - linkType: hard - -"@storybook/addon-docs@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/addon-docs@npm:6.5.16" - dependencies: - "@babel/plugin-transform-react-jsx": ^7.12.12 - "@babel/preset-env": ^7.12.11 - "@jest/transform": ^26.6.2 - "@mdx-js/react": ^1.6.22 - "@storybook/addons": 6.5.16 - "@storybook/api": 6.5.16 - "@storybook/components": 6.5.16 - "@storybook/core-common": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/docs-tools": 6.5.16 - "@storybook/mdx1-csf": ^0.0.1 - "@storybook/node-logger": 6.5.16 - "@storybook/postinstall": 6.5.16 - "@storybook/preview-web": 6.5.16 - "@storybook/source-loader": 6.5.16 - "@storybook/store": 6.5.16 - "@storybook/theming": 6.5.16 - babel-loader: ^8.0.0 - core-js: ^3.8.2 - fast-deep-equal: ^3.1.3 - global: ^4.4.0 - lodash: ^4.17.21 - regenerator-runtime: ^0.13.7 - remark-external-links: ^8.0.0 - remark-slug: ^6.0.0 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - peerDependencies: - "@storybook/mdx2-csf": ^0.0.3 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - "@storybook/mdx2-csf": - optional: true - react: - optional: true - react-dom: - optional: true - checksum: 5bec6eb51b75394ad3508ed1978999c46b6d45a9b76391916512dd22b3be470488c3deb5d5730b72034d1e2f8a57d46142555c5742a11ff0ced4c259d2fdc638 - languageName: node - linkType: hard - -"@storybook/addon-docs@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/addon-docs@npm:7.5.1" +"@storybook/addon-docs@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/addon-docs@npm:7.6.19" dependencies: "@jest/transform": ^29.3.1 "@mdx-js/react": ^2.1.5 - "@storybook/blocks": 7.5.1 - "@storybook/client-logger": 7.5.1 - "@storybook/components": 7.5.1 - "@storybook/csf-plugin": 7.5.1 - "@storybook/csf-tools": 7.5.1 + "@storybook/blocks": 7.6.19 + "@storybook/client-logger": 7.6.19 + "@storybook/components": 7.6.19 + "@storybook/csf-plugin": 7.6.19 + "@storybook/csf-tools": 7.6.19 "@storybook/global": ^5.0.0 "@storybook/mdx2-csf": ^1.0.0 - "@storybook/node-logger": 7.5.1 - "@storybook/postinstall": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/react-dom-shim": 7.5.1 - "@storybook/theming": 7.5.1 - "@storybook/types": 7.5.1 + "@storybook/node-logger": 7.6.19 + "@storybook/postinstall": 7.6.19 + "@storybook/preview-api": 7.6.19 + "@storybook/react-dom-shim": 7.6.19 + "@storybook/theming": 7.6.19 + "@storybook/types": 7.6.19 fs-extra: ^11.1.0 remark-external-links: ^8.0.0 remark-slug: ^6.0.0 @@ -12274,284 +9610,90 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: ae0662ed91f6420110d2707133feb976644bb9536fa9601437a905c4e13f72ef1aec3540e209276ec429356bf8073dd02143ba40aeac9881381802d5429da633 - languageName: node - linkType: hard - -"@storybook/addon-essentials@npm:^6.3.12": - version: 6.5.16 - resolution: "@storybook/addon-essentials@npm:6.5.16" - dependencies: - "@storybook/addon-actions": 6.5.16 - "@storybook/addon-backgrounds": 6.5.16 - "@storybook/addon-controls": 6.5.16 - "@storybook/addon-docs": 6.5.16 - "@storybook/addon-measure": 6.5.16 - "@storybook/addon-outline": 6.5.16 - "@storybook/addon-toolbars": 6.5.16 - "@storybook/addon-viewport": 6.5.16 - "@storybook/addons": 6.5.16 - "@storybook/api": 6.5.16 - "@storybook/core-common": 6.5.16 - "@storybook/node-logger": 6.5.16 - core-js: ^3.8.2 - regenerator-runtime: ^0.13.7 - ts-dedent: ^2.0.0 - peerDependencies: - "@babel/core": ^7.9.6 - peerDependenciesMeta: - "@storybook/angular": - optional: true - "@storybook/builder-manager4": - optional: true - "@storybook/builder-manager5": - optional: true - "@storybook/builder-webpack4": - optional: true - "@storybook/builder-webpack5": - optional: true - "@storybook/html": - optional: true - "@storybook/vue": - optional: true - "@storybook/vue3": - optional: true - "@storybook/web-components": - optional: true - lit: - optional: true - lit-html: - optional: true - react: - optional: true - react-dom: - optional: true - svelte: - optional: true - sveltedoc-parser: - optional: true - vue: - optional: true - webpack: - optional: true - checksum: dd9d9d44e687d1fce34038a96a0de02abfd122007e6ab2c869aec132672a2734de8348134fbf63ab1c2a8f7ab8ab3c8909c4e66f4764969bbafc399c91bf9237 + checksum: a9ec3a2e2d0a5b847ed5e45f1f275f741652a4641cc76db8335a4d3838e6637015fe760a401b1b6244b58a6de3d6710ba9971a55dc77d4a281e8dde69f9ad623 languageName: node linkType: hard "@storybook/addon-essentials@npm:^7.0.23": - version: 7.5.1 - resolution: "@storybook/addon-essentials@npm:7.5.1" + version: 7.6.19 + resolution: "@storybook/addon-essentials@npm:7.6.19" dependencies: - "@storybook/addon-actions": 7.5.1 - "@storybook/addon-backgrounds": 7.5.1 - "@storybook/addon-controls": 7.5.1 - "@storybook/addon-docs": 7.5.1 - "@storybook/addon-highlight": 7.5.1 - "@storybook/addon-measure": 7.5.1 - "@storybook/addon-outline": 7.5.1 - "@storybook/addon-toolbars": 7.5.1 - "@storybook/addon-viewport": 7.5.1 - "@storybook/core-common": 7.5.1 - "@storybook/manager-api": 7.5.1 - "@storybook/node-logger": 7.5.1 - "@storybook/preview-api": 7.5.1 + "@storybook/addon-actions": 7.6.19 + "@storybook/addon-backgrounds": 7.6.19 + "@storybook/addon-controls": 7.6.19 + "@storybook/addon-docs": 7.6.19 + "@storybook/addon-highlight": 7.6.19 + "@storybook/addon-measure": 7.6.19 + "@storybook/addon-outline": 7.6.19 + "@storybook/addon-toolbars": 7.6.19 + "@storybook/addon-viewport": 7.6.19 + "@storybook/core-common": 7.6.19 + "@storybook/manager-api": 7.6.19 + "@storybook/node-logger": 7.6.19 + "@storybook/preview-api": 7.6.19 ts-dedent: ^2.0.0 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 9abf4a5bc62e1884393ca33a1ac9d3ca69a36bcaca51281dbe59e3c2f61e30acd8ddc3e99150fa5d88d999036f9899c711573ebb439cecda5dc359ab307c18da + checksum: c2cbedd201dd6404114435f48e396602a4b97053c62bcfa15fbd524aca1e4139298715d5bc60c4bcf9b09ed126907080875c06e0f62a1f5db585d052582465e1 languageName: node linkType: hard -"@storybook/addon-highlight@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/addon-highlight@npm:7.5.1" +"@storybook/addon-highlight@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/addon-highlight@npm:7.6.19" dependencies: - "@storybook/core-events": 7.5.1 "@storybook/global": ^5.0.0 - "@storybook/preview-api": 7.5.1 - checksum: c15ac6b84c2ca2c91bdce71b8ebcb331cdbd85ade0cd1f7c4e4bc6b2b63d2639daf58405f54728ccae0c48db8d82626312f29ff589b8e24559f6407a4caab1f3 + checksum: ae61dc1a8a44df117529afd333dd55f4fb47d9ea796a4f44bc5f097c48505b9ec757cdbd25f613613cd6e9f58c93bcb0f740a365e7af42a435f47e382787eb24 languageName: node linkType: hard "@storybook/addon-interactions@npm:^7.0.23": - version: 7.5.1 - resolution: "@storybook/addon-interactions@npm:7.5.1" + version: 7.6.19 + resolution: "@storybook/addon-interactions@npm:7.6.19" dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/components": 7.5.1 - "@storybook/core-common": 7.5.1 - "@storybook/core-events": 7.5.1 "@storybook/global": ^5.0.0 - "@storybook/instrumenter": 7.5.1 - "@storybook/manager-api": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/theming": 7.5.1 - "@storybook/types": 7.5.1 + "@storybook/types": 7.6.19 jest-mock: ^27.0.6 polished: ^4.2.2 ts-dedent: ^2.2.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 6ac3528e2f4a2eb29a14949e07982ac8246623dc45a9956c86180efcd78d57aeea0e49748d56d5031d145b4e0da989df52b4e6ef04276c3a6844e52e8aec3d12 - languageName: node - linkType: hard - -"@storybook/addon-links@npm:^6.3.12": - version: 6.5.16 - resolution: "@storybook/addon-links@npm:6.5.16" - dependencies: - "@storybook/addons": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/router": 6.5.16 - "@types/qs": ^6.9.5 - core-js: ^3.8.2 - global: ^4.4.0 - prop-types: ^15.7.2 - qs: ^6.10.0 - regenerator-runtime: ^0.13.7 - ts-dedent: ^2.0.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 5c4b1f689ffe957a1c5b58d2e305cffd9d0839805fdd71f9b6ac2a9ec2020778c3bb3c7e1bb3c5ec21a8373c3b371ca6b27d099234619ab10b8c4ed9bea9e388 + checksum: 430d62298930b5e78398024de99f8f5d19ef22d7eda51015fa88e8ed3fafd2e003b0c8694a97192848ebf3e013ba363d96bf753ef1ff844e8129a9c47d41894c languageName: node linkType: hard "@storybook/addon-links@npm:^7.0.23": - version: 7.5.1 - resolution: "@storybook/addon-links@npm:7.5.1" + version: 7.6.19 + resolution: "@storybook/addon-links@npm:7.6.19" dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/core-events": 7.5.1 - "@storybook/csf": ^0.1.0 + "@storybook/csf": ^0.1.2 "@storybook/global": ^5.0.0 - "@storybook/manager-api": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/router": 7.5.1 - "@storybook/types": 7.5.1 - prop-types: ^15.7.2 ts-dedent: ^2.0.0 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 peerDependenciesMeta: react: optional: true - react-dom: - optional: true - checksum: ea438d8e07a3daa338c4be948300ae07ddda85166e128de2e385a9caea0faba3797215a8ce255e4c15a486b5c844de49c7c1a60170c34d96ee00e261e0c19eae + checksum: c7f40095e8f00ed1dc9a6118b074d513e3a7dd77334e044d152b42ea5922a0fd26397bbcd45abaa2968a3b27a27b810af0e8039ab07ecee7043582fa2a14ca67 languageName: node linkType: hard -"@storybook/addon-measure@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/addon-measure@npm:6.5.16" +"@storybook/addon-measure@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/addon-measure@npm:7.6.19" dependencies: - "@storybook/addons": 6.5.16 - "@storybook/api": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/components": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - core-js: ^3.8.2 - global: ^4.4.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 790833966b5a3108686f5aae2ac53f8a7e5d23720c58e7df4d4a3a937cb35d694addcb17c90c9aeb653c96182705e68da23d3f7ab507a15005b29cd698c4975e - languageName: node - linkType: hard - -"@storybook/addon-measure@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/addon-measure@npm:7.5.1" - dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/components": 7.5.1 - "@storybook/core-events": 7.5.1 "@storybook/global": ^5.0.0 - "@storybook/manager-api": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/types": 7.5.1 tiny-invariant: ^1.3.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 0600db8c5a60a710e65e14cb21b1663f513d2574472f39bb4dc5b654c38982f3b6da7ea7769bfeb892a77303e9c9189b469ed5d46c501921b44c3124eff65e05 + checksum: 3a28046c80a8abbb6ff8f9d9916c2cae4abc51484f9c17b3722efc0e3677426622fc83016d8f140b3925fda123a3cce1333e903a94f349a42e3ea8db24f44174 languageName: node linkType: hard -"@storybook/addon-outline@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/addon-outline@npm:6.5.16" +"@storybook/addon-outline@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/addon-outline@npm:7.6.19" dependencies: - "@storybook/addons": 6.5.16 - "@storybook/api": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/components": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - core-js: ^3.8.2 - global: ^4.4.0 - regenerator-runtime: ^0.13.7 - ts-dedent: ^2.0.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 2ea36bf6ba1fd7538e42c23971e0a88e46e7ac19050148856da0f5d423848f8c2266cea68d5d522e1e38f8be92cc8e108b06b34b9b5622f098a00a4537f731f5 - languageName: node - linkType: hard - -"@storybook/addon-outline@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/addon-outline@npm:7.5.1" - dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/components": 7.5.1 - "@storybook/core-events": 7.5.1 "@storybook/global": ^5.0.0 - "@storybook/manager-api": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/types": 7.5.1 ts-dedent: ^2.0.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 0183e8778ea8a5ef8a1fc914e06a9c93156bcce5faf374390c93398b1fc276e075b4e0b9b6690c3bfec09d70611fc8cda13ad3ad2beaf9e041e5c358c774e2d4 + checksum: 1800b1af52947618b1f06111b3cea25ce96405befc906481f88a04c91de97f3380e7b6fdb9a5a9b2579ea31c08e75901e59fc7cd58bcb6d2d6e3132a5f340107 languageName: node linkType: hard @@ -12600,185 +9742,47 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-toolbars@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/addon-toolbars@npm:6.5.16" - dependencies: - "@storybook/addons": 6.5.16 - "@storybook/api": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/components": 6.5.16 - "@storybook/theming": 6.5.16 - core-js: ^3.8.2 - regenerator-runtime: ^0.13.7 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 84b5a880e71c580d7773671b4e4f2d93e2b19432f8915bce0e651b1502487240deb359122e21dffa77bebb3feeb8a9535014346603b72f7646d8145bbf421853 +"@storybook/addon-toolbars@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/addon-toolbars@npm:7.6.19" + checksum: 01a1c071355d01f41a785caa307c798d2d1fa9be962d43e9c4584f96d99649f03b838bb1c49440e0b2797f863106c98523be1896a3da14a825334533b5f1becc languageName: node linkType: hard -"@storybook/addon-toolbars@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/addon-toolbars@npm:7.5.1" +"@storybook/addon-viewport@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/addon-viewport@npm:7.6.19" dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/components": 7.5.1 - "@storybook/manager-api": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/theming": 7.5.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 3db60ffda02fb77321257a88eee9ae396d2cbe0e4f063b9565adbd646c55a02bad00b282173282a6e41f0ae1a154dcfe5fcaff79399f0670d2fd9d56f567e54e - languageName: node - linkType: hard - -"@storybook/addon-viewport@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/addon-viewport@npm:6.5.16" - dependencies: - "@storybook/addons": 6.5.16 - "@storybook/api": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/components": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/theming": 6.5.16 - core-js: ^3.8.2 - global: ^4.4.0 memoizerific: ^1.11.3 - prop-types: ^15.7.2 - regenerator-runtime: ^0.13.7 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: e43ff0424c20793d6c0de682d10b5cf810d3a9b7cc610499edca9032720ffe9d046764555b562cfe94ae44e2c94c1aacf588e9c9ff732e83ec2801f943f8d9d7 - languageName: node - linkType: hard - -"@storybook/addon-viewport@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/addon-viewport@npm:7.5.1" - dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/components": 7.5.1 - "@storybook/core-events": 7.5.1 - "@storybook/global": ^5.0.0 - "@storybook/manager-api": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/theming": 7.5.1 - memoizerific: ^1.11.3 - prop-types: ^15.7.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 2dad5761e5cf951d221084470076f7c587b07f50f064eba16317d31a3f1b80f694f286f1843fb9d4830649d7e57f76290c43de30cdb0856d99515c77c81db155 - languageName: node - linkType: hard - -"@storybook/addons@npm:6.5.16, @storybook/addons@npm:^6.3.12": - version: 6.5.16 - resolution: "@storybook/addons@npm:6.5.16" - dependencies: - "@storybook/api": 6.5.16 - "@storybook/channels": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/router": 6.5.16 - "@storybook/theming": 6.5.16 - "@types/webpack-env": ^1.16.0 - core-js: ^3.8.2 - global: ^4.4.0 - regenerator-runtime: ^0.13.7 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: a5e62e7523272f941c07412cfacee10a8e244eadce67e5855d14f48d9e1b8e295c923b8d80510ae76fbab3f955fff189273abcb5ff4868cb14c8f6f741e8c955 - languageName: node - linkType: hard - -"@storybook/api@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/api@npm:6.5.16" - dependencies: - "@storybook/channels": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/router": 6.5.16 - "@storybook/semver": ^7.3.2 - "@storybook/theming": 6.5.16 - core-js: ^3.8.2 - fast-deep-equal: ^3.1.3 - global: ^4.4.0 - lodash: ^4.17.21 - memoizerific: ^1.11.3 - regenerator-runtime: ^0.13.7 - store2: ^2.12.0 - telejson: ^6.0.8 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: d48185c2c6e94f5d531493732563b4e63c8a85709259346d62611faacac67272f67d8dcbc4885d4c12cfda1c921e92923c3a317d48595c3635f4d60f901c848c + checksum: ae32e4d942a12a23ab5f9637eed17f69847a4621a06be6daa78e5c21b19ad5a9baa7a11f6c84300459cc9fd14b5bca7b824180e2f16bde8466800eced77e8804 languageName: node linkType: hard "@storybook/api@npm:^7.0.12": - version: 7.5.1 - resolution: "@storybook/api@npm:7.5.1" + version: 7.6.19 + resolution: "@storybook/api@npm:7.6.19" dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/manager-api": 7.5.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: c096c55c6984d837db8c8a37bae15f80ef197c5b70879048e3ab85fd8efde3ab65451b207f2d2891dadd1975b5ad9de07d899b2bc0e017ab9b3cfec8cccfce03 + "@storybook/client-logger": 7.6.19 + "@storybook/manager-api": 7.6.19 + checksum: 28a2fa858effcec996a791c3f8e78f214b75ba281294dd3c30b9db9606ee4cd306569e6f9de99508b6f56afbbc8f3c4e9209a7302ae7ddb14ea76893d6318c28 languageName: node linkType: hard -"@storybook/blocks@npm:7.5.1, @storybook/blocks@npm:^7.0.23": - version: 7.5.1 - resolution: "@storybook/blocks@npm:7.5.1" +"@storybook/blocks@npm:7.6.19, @storybook/blocks@npm:^7.0.23": + version: 7.6.19 + resolution: "@storybook/blocks@npm:7.6.19" dependencies: - "@storybook/channels": 7.5.1 - "@storybook/client-logger": 7.5.1 - "@storybook/components": 7.5.1 - "@storybook/core-events": 7.5.1 - "@storybook/csf": ^0.1.0 - "@storybook/docs-tools": 7.5.1 + "@storybook/channels": 7.6.19 + "@storybook/client-logger": 7.6.19 + "@storybook/components": 7.6.19 + "@storybook/core-events": 7.6.19 + "@storybook/csf": ^0.1.2 + "@storybook/docs-tools": 7.6.19 "@storybook/global": ^5.0.0 - "@storybook/manager-api": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/theming": 7.5.1 - "@storybook/types": 7.5.1 + "@storybook/manager-api": 7.6.19 + "@storybook/preview-api": 7.6.19 + "@storybook/theming": 7.6.19 + "@storybook/types": 7.6.19 "@types/lodash": ^4.14.167 color-convert: ^2.0.1 dequal: ^2.0.2 @@ -12794,18 +9798,18 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 47542bc96d54fa858a98496560c656ae9eaa16ecb9c359d1490b9c7a260c63b065b7f5930f8df7d6b0b8ecdf994997edaf969f73805054b1c4bf9ed120b9a412 + checksum: 95203844036dd88c9d19f951f85b4a41615f2e87f55dca652eab7f9b7d1cda0d818045b2aad86d219cc4c03722b487aae6ee3b33aba9dcbf08fb469f2d2d12db languageName: node linkType: hard -"@storybook/builder-manager@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/builder-manager@npm:7.5.1" +"@storybook/builder-manager@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/builder-manager@npm:7.6.19" dependencies: "@fal-works/esbuild-plugin-global-externals": ^2.1.2 - "@storybook/core-common": 7.5.1 - "@storybook/manager": 7.5.1 - "@storybook/node-logger": 7.5.1 + "@storybook/core-common": 7.6.19 + "@storybook/manager": 7.6.19 + "@storybook/node-logger": 7.6.19 "@types/ejs": ^3.1.1 "@types/find-cache-dir": ^3.2.1 "@yarnpkg/esbuild-plugin-pnp": ^3.0.0-rc.10 @@ -12818,22 +9822,22 @@ __metadata: fs-extra: ^11.1.0 process: ^0.11.10 util: ^0.12.4 - checksum: 724d82c57ccb91ee095ff102c81bb84ba19885bce0b15620f57b34efa1f5024d4f88feca5d3e66ebcc542aba3f0301d7bc5de59fb67c82df03c2302c0e3804f5 + checksum: 29bbe85c5765f2c481c52982fd72e2e333146f521078c6f2160c6b00e02fce0353a9462e5a1dcb8f2a00cc7f65b82b4f2fd846243d348e4faa704e7b13eddf9e languageName: node linkType: hard -"@storybook/builder-vite@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/builder-vite@npm:7.5.1" +"@storybook/builder-vite@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/builder-vite@npm:7.6.19" dependencies: - "@storybook/channels": 7.5.1 - "@storybook/client-logger": 7.5.1 - "@storybook/core-common": 7.5.1 - "@storybook/csf-plugin": 7.5.1 - "@storybook/node-logger": 7.5.1 - "@storybook/preview": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/types": 7.5.1 + "@storybook/channels": 7.6.19 + "@storybook/client-logger": 7.6.19 + "@storybook/core-common": 7.6.19 + "@storybook/csf-plugin": 7.6.19 + "@storybook/node-logger": 7.6.19 + "@storybook/preview": 7.6.19 + "@storybook/preview-api": 7.6.19 + "@storybook/types": 7.6.19 "@types/find-cache-dir": ^3.2.1 browser-assert: ^1.2.1 es-module-lexer: ^0.9.3 @@ -12854,140 +9858,40 @@ __metadata: optional: true vite-plugin-glimmerx: optional: true - checksum: abdd480267163c608b082c1642c1f79543182a00768a2a945d7f98cd2cad287d43576f0f50add19bedbcad3bbad7d661d3162badaedf51cdf70dd569c71de356 + checksum: 2c88509333c24ee19c48a88dd51f4f3b86a10413bb71036ab7bbfd723afecf52bb0fd0c6f454dff86fc4cbfd6808eb35ef5ff8ffa82038650c3f863df74c1a50 languageName: node linkType: hard -"@storybook/builder-webpack4@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/builder-webpack4@npm:6.5.16" +"@storybook/channels@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/channels@npm:7.6.19" dependencies: - "@babel/core": ^7.12.10 - "@storybook/addons": 6.5.16 - "@storybook/api": 6.5.16 - "@storybook/channel-postmessage": 6.5.16 - "@storybook/channels": 6.5.16 - "@storybook/client-api": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/components": 6.5.16 - "@storybook/core-common": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/node-logger": 6.5.16 - "@storybook/preview-web": 6.5.16 - "@storybook/router": 6.5.16 - "@storybook/semver": ^7.3.2 - "@storybook/store": 6.5.16 - "@storybook/theming": 6.5.16 - "@storybook/ui": 6.5.16 - "@types/node": ^14.0.10 || ^16.0.0 - "@types/webpack": ^4.41.26 - autoprefixer: ^9.8.6 - babel-loader: ^8.0.0 - case-sensitive-paths-webpack-plugin: ^2.3.0 - core-js: ^3.8.2 - css-loader: ^3.6.0 - file-loader: ^6.2.0 - find-up: ^5.0.0 - fork-ts-checker-webpack-plugin: ^4.1.6 - glob: ^7.1.6 - glob-promise: ^3.4.0 - global: ^4.4.0 - html-webpack-plugin: ^4.0.0 - pnp-webpack-plugin: 1.6.4 - postcss: ^7.0.36 - postcss-flexbugs-fixes: ^4.2.1 - postcss-loader: ^4.2.0 - raw-loader: ^4.0.2 - stable: ^0.1.8 - style-loader: ^1.3.0 - terser-webpack-plugin: ^4.2.3 - ts-dedent: ^2.0.0 - url-loader: ^4.1.1 - util-deprecate: ^1.0.2 - webpack: 4 - webpack-dev-middleware: ^3.7.3 - webpack-filter-warnings-plugin: ^1.2.1 - webpack-hot-middleware: ^2.25.1 - webpack-virtual-modules: ^0.2.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 0873f320c46ddbeff4c177286c3e41564d20abf7cc40cdc5dc888bb178a940e5c54557ea3d66d64a55b691114f417928580fe7ae2b71b8b791467919a0f864ef - languageName: node - linkType: hard - -"@storybook/channel-postmessage@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/channel-postmessage@npm:6.5.16" - dependencies: - "@storybook/channels": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/core-events": 6.5.16 - core-js: ^3.8.2 - global: ^4.4.0 - qs: ^6.10.0 - telejson: ^6.0.8 - checksum: 24ac0790b3f68405357346edae174ccfb6f2101ca74f90eb8921a49576d67053ac3d53b5a293161a26b9bb9ce2c2751024a2751b1afbb787906346f9d845790d - languageName: node - linkType: hard - -"@storybook/channel-websocket@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/channel-websocket@npm:6.5.16" - dependencies: - "@storybook/channels": 6.5.16 - "@storybook/client-logger": 6.5.16 - core-js: ^3.8.2 - global: ^4.4.0 - telejson: ^6.0.8 - checksum: 82a5ce6c39419c41b3eae7bf4bebaff078159208accb26a001b888a7462850a3d2c332d3013d98cb6069d613b96316b6956c254a8c65f198f15dc2cde5e2b6d0 - languageName: node - linkType: hard - -"@storybook/channels@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/channels@npm:6.5.16" - dependencies: - core-js: ^3.8.2 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - checksum: 9bb4863f6671ab40d397c6e5075bc5504c34b4f0961421b6a342ce084e51ba471f295f7205258b1a6836d07c86ded044b339804ec755741718078802fd687d93 - languageName: node - linkType: hard - -"@storybook/channels@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/channels@npm:7.5.1" - dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/core-events": 7.5.1 + "@storybook/client-logger": 7.6.19 + "@storybook/core-events": 7.6.19 "@storybook/global": ^5.0.0 qs: ^6.10.0 telejson: ^7.2.0 tiny-invariant: ^1.3.1 - checksum: 25ea5765241ec71c8eb23bd98455054a155d9017a8235729f0b14c1592cc3ce264e0843bdd265a63d900c02c5470635e74ea8b1bff78f86c41ac46be1abfa932 + checksum: 7b5e879d15da93aa312f7e3df4055f9c0bf5d5120f82058cca6c878469c1748637509a03e7c31986cadec05ab378c035c4d38d74a4d45c94b5ad9ed77b4c93ee languageName: node linkType: hard -"@storybook/cli@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/cli@npm:7.5.1" +"@storybook/cli@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/cli@npm:7.6.19" dependencies: - "@babel/core": ^7.22.9 - "@babel/preset-env": ^7.22.9 - "@babel/types": ^7.22.5 + "@babel/core": ^7.23.2 + "@babel/preset-env": ^7.23.2 + "@babel/types": ^7.23.0 "@ndelangen/get-tarball": ^3.0.7 - "@storybook/codemod": 7.5.1 - "@storybook/core-common": 7.5.1 - "@storybook/core-events": 7.5.1 - "@storybook/core-server": 7.5.1 - "@storybook/csf-tools": 7.5.1 - "@storybook/node-logger": 7.5.1 - "@storybook/telemetry": 7.5.1 - "@storybook/types": 7.5.1 + "@storybook/codemod": 7.6.19 + "@storybook/core-common": 7.6.19 + "@storybook/core-events": 7.6.19 + "@storybook/core-server": 7.6.19 + "@storybook/csf-tools": 7.6.19 + "@storybook/node-logger": 7.6.19 + "@storybook/telemetry": 7.6.19 + "@storybook/types": 7.6.19 "@types/semver": ^7.3.4 "@yarnpkg/fslib": 2.10.3 "@yarnpkg/libzip": 2.3.0 @@ -13004,7 +9908,7 @@ __metadata: get-port: ^5.1.1 giget: ^1.0.0 globby: ^11.0.2 - jscodeshift: ^0.14.0 + jscodeshift: ^0.15.1 leven: ^3.1.0 ora: ^5.4.1 prettier: ^2.8.0 @@ -13012,7 +9916,6 @@ __metadata: puppeteer-core: ^2.1.1 read-pkg-up: ^7.0.1 semver: ^7.3.7 - simple-update-notifier: ^2.0.0 strip-json-comments: ^3.0.1 tempy: ^1.0.1 ts-dedent: ^2.0.0 @@ -13020,238 +9923,79 @@ __metadata: bin: getstorybook: ./bin/index.js sb: ./bin/index.js - checksum: 34011299ac0c57ad2e1c8498c73b4540ded1b4a4136446ad0bf4b4a1ebf301fa429834d6a80caf1fc0e0114e8464b58916864332b013ec35a8a52b1e391e07f3 + checksum: af46b19e9c248a0f3eb0c70a237f738109f09e1af6c8a101f8d4e3254f22ad84e7afed94964f925c10dcf2dc2039d2926d608e406a5b2d04a172a9374bfc00aa languageName: node linkType: hard -"@storybook/client-api@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/client-api@npm:6.5.16" - dependencies: - "@storybook/addons": 6.5.16 - "@storybook/channel-postmessage": 6.5.16 - "@storybook/channels": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/store": 6.5.16 - "@types/qs": ^6.9.5 - "@types/webpack-env": ^1.16.0 - core-js: ^3.8.2 - fast-deep-equal: ^3.1.3 - global: ^4.4.0 - lodash: ^4.17.21 - memoizerific: ^1.11.3 - qs: ^6.10.0 - regenerator-runtime: ^0.13.7 - store2: ^2.12.0 - synchronous-promise: ^2.0.15 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: b4fc41ba600fd33334b3e9fb572b293b0507c80deb5f5d250ff821eb5d2e3655dbeb2e812cc6a99a4cbc3bb7942b8915d37db3424b30eb7ad9465b3dc729c2cc - languageName: node - linkType: hard - -"@storybook/client-logger@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/client-logger@npm:6.5.16" - dependencies: - core-js: ^3.8.2 - global: ^4.4.0 - checksum: 6c1f1861c63f304af2fc864b3f17b65547a052efeade5a5cee86da6b9babdb804cb06327c4db83dcb147042221c7b3383bcfb6ac68f149ca97bbd9cba72b21f3 - languageName: node - linkType: hard - -"@storybook/client-logger@npm:7.5.1, @storybook/client-logger@npm:^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0": - version: 7.5.1 - resolution: "@storybook/client-logger@npm:7.5.1" +"@storybook/client-logger@npm:7.6.19, @storybook/client-logger@npm:^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0": + version: 7.6.19 + resolution: "@storybook/client-logger@npm:7.6.19" dependencies: "@storybook/global": ^5.0.0 - checksum: aedb53847d282152afc5d8f5c1eef7107d2c6d788322bfa7e672f11079daa9cda3bd2f485291bf9553c86a1c92cff8431961bfce92ea5515b2806fd72da217e7 + checksum: 16b5a6755874f82eec71364223af62c155d29e1bcd3c1061a734dff8b687a6a2e9d09da8866b92a16bf5e8f0717ad8f8a522e5d1cb023a9457ff220cb4819604 languageName: node linkType: hard -"@storybook/codemod@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/codemod@npm:7.5.1" +"@storybook/codemod@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/codemod@npm:7.6.19" dependencies: - "@babel/core": ^7.22.9 - "@babel/preset-env": ^7.22.9 - "@babel/types": ^7.22.5 - "@storybook/csf": ^0.1.0 - "@storybook/csf-tools": 7.5.1 - "@storybook/node-logger": 7.5.1 - "@storybook/types": 7.5.1 + "@babel/core": ^7.23.2 + "@babel/preset-env": ^7.23.2 + "@babel/types": ^7.23.0 + "@storybook/csf": ^0.1.2 + "@storybook/csf-tools": 7.6.19 + "@storybook/node-logger": 7.6.19 + "@storybook/types": 7.6.19 "@types/cross-spawn": ^6.0.2 cross-spawn: ^7.0.3 globby: ^11.0.2 - jscodeshift: ^0.14.0 + jscodeshift: ^0.15.1 lodash: ^4.17.21 prettier: ^2.8.0 recast: ^0.23.1 - checksum: 64a755238b512e5a7cc191054c604185a1aef2b7588c28a755a29b14af1b4da3f2533fca30a01c84549e451cb36a87d84d4c8dbfd8c15ad2921875faf4141290 + checksum: 68fd5cbd85b28a02c2164f52499197ad1ac55c01434fca50a5ca56a45fa39a86910c3792390e788e9796aa0bdef1253412b7c039247de42cb8555223ff91ffdb languageName: node linkType: hard -"@storybook/components@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/components@npm:6.5.16" - dependencies: - "@storybook/client-logger": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/theming": 6.5.16 - core-js: ^3.8.2 - memoizerific: ^1.11.3 - qs: ^6.10.0 - regenerator-runtime: ^0.13.7 - util-deprecate: ^1.0.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: b925da37bccab1aaf131c4d48caa3deccc329d9bbe3fa124846fa60855d6251ede4ba49b3254353fc876f44e3e8f4f1e5034e20d98d59136daf3cd9ae70a249e - languageName: node - linkType: hard - -"@storybook/components@npm:7.5.1, @storybook/components@npm:^7.0.12": - version: 7.5.1 - resolution: "@storybook/components@npm:7.5.1" +"@storybook/components@npm:7.6.19, @storybook/components@npm:^7.0.12": + version: 7.6.19 + resolution: "@storybook/components@npm:7.6.19" dependencies: "@radix-ui/react-select": ^1.2.2 "@radix-ui/react-toolbar": ^1.0.4 - "@storybook/client-logger": 7.5.1 - "@storybook/csf": ^0.1.0 + "@storybook/client-logger": 7.6.19 + "@storybook/csf": ^0.1.2 "@storybook/global": ^5.0.0 - "@storybook/theming": 7.5.1 - "@storybook/types": 7.5.1 + "@storybook/theming": 7.6.19 + "@storybook/types": 7.6.19 memoizerific: ^1.11.3 use-resize-observer: ^9.1.0 util-deprecate: ^1.0.2 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 04699e50746e9953763b5644e9219095daba7ec96b4977b7113ad5e1c794a31fc233bec452eb09d5cc06c92525d0143d2601a6870be190fb9743dcd4d486e423 + checksum: ac30b93b7d29a4905b4fd13952eae374f0460246c0741f1689b9835251a1ef3b2a89125f8b500597b8c7de295c43f575b2b1458fea9db44f7fb9f9c5d58f52c6 languageName: node linkType: hard -"@storybook/core-client@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/core-client@npm:6.5.16" +"@storybook/core-client@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/core-client@npm:7.6.19" dependencies: - "@storybook/addons": 6.5.16 - "@storybook/channel-postmessage": 6.5.16 - "@storybook/channel-websocket": 6.5.16 - "@storybook/client-api": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/preview-web": 6.5.16 - "@storybook/store": 6.5.16 - "@storybook/ui": 6.5.16 - airbnb-js-shims: ^2.2.1 - ansi-to-html: ^0.6.11 - core-js: ^3.8.2 - global: ^4.4.0 - lodash: ^4.17.21 - qs: ^6.10.0 - regenerator-runtime: ^0.13.7 - ts-dedent: ^2.0.0 - unfetch: ^4.2.0 - util-deprecate: ^1.0.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - webpack: "*" - peerDependenciesMeta: - typescript: - optional: true - checksum: 91ad10bbeb36f2576357d644b0cc89d34258c5589f3aba5941738e6aed4494e6e2dde33aedfdc7b91118c48a9585c151366c8cbd53e82054d84a332d371629b5 + "@storybook/client-logger": 7.6.19 + "@storybook/preview-api": 7.6.19 + checksum: e1ff7f6095b06fbc5956d0e18f61f10b342df46e9b09331705c87f388222882d4fc679f8673e8254ebdebc1b68da36e2d2f6f7b550d8f8337b64b312dcc085a6 languageName: node linkType: hard -"@storybook/core-client@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/core-client@npm:7.5.1" +"@storybook/core-common@npm:7.6.19, @storybook/core-common@npm:^7.0.12": + version: 7.6.19 + resolution: "@storybook/core-common@npm:7.6.19" dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/preview-api": 7.5.1 - checksum: eb89a2ffad9646a4ba96471bbaa605e314cd6afbfe23fa3ddb4a0128e343a5d7dee7c0f5a5a28e2a2bea3c9d96d9505d9139efe05b0d24f863e25ce174eef042 - languageName: node - linkType: hard - -"@storybook/core-common@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/core-common@npm:6.5.16" - dependencies: - "@babel/core": ^7.12.10 - "@babel/plugin-proposal-class-properties": ^7.12.1 - "@babel/plugin-proposal-decorators": ^7.12.12 - "@babel/plugin-proposal-export-default-from": ^7.12.1 - "@babel/plugin-proposal-nullish-coalescing-operator": ^7.12.1 - "@babel/plugin-proposal-object-rest-spread": ^7.12.1 - "@babel/plugin-proposal-optional-chaining": ^7.12.7 - "@babel/plugin-proposal-private-methods": ^7.12.1 - "@babel/plugin-proposal-private-property-in-object": ^7.12.1 - "@babel/plugin-syntax-dynamic-import": ^7.8.3 - "@babel/plugin-transform-arrow-functions": ^7.12.1 - "@babel/plugin-transform-block-scoping": ^7.12.12 - "@babel/plugin-transform-classes": ^7.12.1 - "@babel/plugin-transform-destructuring": ^7.12.1 - "@babel/plugin-transform-for-of": ^7.12.1 - "@babel/plugin-transform-parameters": ^7.12.1 - "@babel/plugin-transform-shorthand-properties": ^7.12.1 - "@babel/plugin-transform-spread": ^7.12.1 - "@babel/preset-env": ^7.12.11 - "@babel/preset-react": ^7.12.10 - "@babel/preset-typescript": ^7.12.7 - "@babel/register": ^7.12.1 - "@storybook/node-logger": 6.5.16 - "@storybook/semver": ^7.3.2 - "@types/node": ^14.0.10 || ^16.0.0 - "@types/pretty-hrtime": ^1.0.0 - babel-loader: ^8.0.0 - babel-plugin-macros: ^3.0.1 - babel-plugin-polyfill-corejs3: ^0.1.0 - chalk: ^4.1.0 - core-js: ^3.8.2 - express: ^4.17.1 - file-system-cache: ^1.0.5 - find-up: ^5.0.0 - fork-ts-checker-webpack-plugin: ^6.0.4 - fs-extra: ^9.0.1 - glob: ^7.1.6 - handlebars: ^4.7.7 - interpret: ^2.2.0 - json5: ^2.2.3 - lazy-universal-dotenv: ^3.0.1 - picomatch: ^2.3.0 - pkg-dir: ^5.0.0 - pretty-hrtime: ^1.0.3 - resolve-from: ^5.0.0 - slash: ^3.0.0 - telejson: ^6.0.8 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - webpack: 4 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: fa838cedcdfd7a26971ea456b0d0bbe32c9c506774d975e4d3d97380678d33cce9c04610abbaffe1620f88dc33f9acd577c96e66c4f7643e107496856fd4f03b - languageName: node - linkType: hard - -"@storybook/core-common@npm:7.5.1, @storybook/core-common@npm:^7.0.12": - version: 7.5.1 - resolution: "@storybook/core-common@npm:7.5.1" - dependencies: - "@storybook/core-events": 7.5.1 - "@storybook/node-logger": 7.5.1 - "@storybook/types": 7.5.1 + "@storybook/core-events": 7.6.19 + "@storybook/node-logger": 7.6.19 + "@storybook/types": 7.6.19 "@types/find-cache-dir": ^3.2.1 "@types/node": ^18.0.0 "@types/node-fetch": ^2.6.4 @@ -13272,110 +10016,38 @@ __metadata: pretty-hrtime: ^1.0.3 resolve-from: ^5.0.0 ts-dedent: ^2.0.0 - checksum: 7d0af920e2b6ad591e580f922c51cf433da035b34e7b26c576b84f2d90ea9a8b3e6dfe6b6b89ef6f2909a4dae959db51ac639dc7943839f6c1fce244cb907172 + checksum: da68811e3a54705ad5358917e073b21d83a96b35e15f960861e63ce383928893d69707f3cf6b54c0f13efbb774e2e6e0ba2b34bfbb89fd71cc38f176f673670c languageName: node linkType: hard -"@storybook/core-events@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/core-events@npm:6.5.16" - dependencies: - core-js: ^3.8.2 - checksum: d7957f1df4703f4586f27281f207b0535e3003a4f5fb9c888f2c583b7101c46111bc1335c8d16861962f2be6dec7e3b5959548d5ef58965d3744085823621d59 - languageName: node - linkType: hard - -"@storybook/core-events@npm:7.5.1, @storybook/core-events@npm:^7.0.12": - version: 7.5.1 - resolution: "@storybook/core-events@npm:7.5.1" +"@storybook/core-events@npm:7.6.19, @storybook/core-events@npm:^7.0.12": + version: 7.6.19 + resolution: "@storybook/core-events@npm:7.6.19" dependencies: ts-dedent: ^2.0.0 - checksum: 5d0b21480b437922527236cce0522c849fe4972bd073e74b322b5c77015ec2b447931ad67ef4ddd4cfdc16a7e6fe42ca12905338099902258c664c5c7238b3e2 + checksum: 9cb367fe024797f7673b308f0b1dac0043b91d3bca77cc2c55589c0234faaa91f3e886efba7b077a1b8c2f2e48d7269f8c40ac7246a679b03123c4015e3e3f60 languageName: node linkType: hard -"@storybook/core-server@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/core-server@npm:6.5.16" - dependencies: - "@discoveryjs/json-ext": ^0.5.3 - "@storybook/builder-webpack4": 6.5.16 - "@storybook/core-client": 6.5.16 - "@storybook/core-common": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/csf-tools": 6.5.16 - "@storybook/manager-webpack4": 6.5.16 - "@storybook/node-logger": 6.5.16 - "@storybook/semver": ^7.3.2 - "@storybook/store": 6.5.16 - "@storybook/telemetry": 6.5.16 - "@types/node": ^14.0.10 || ^16.0.0 - "@types/node-fetch": ^2.5.7 - "@types/pretty-hrtime": ^1.0.0 - "@types/webpack": ^4.41.26 - better-opn: ^2.1.1 - boxen: ^5.1.2 - chalk: ^4.1.0 - cli-table3: ^0.6.1 - commander: ^6.2.1 - compression: ^1.7.4 - core-js: ^3.8.2 - cpy: ^8.1.2 - detect-port: ^1.3.0 - express: ^4.17.1 - fs-extra: ^9.0.1 - global: ^4.4.0 - globby: ^11.0.2 - ip: ^2.0.0 - lodash: ^4.17.21 - node-fetch: ^2.6.7 - open: ^8.4.0 - pretty-hrtime: ^1.0.3 - prompts: ^2.4.0 - regenerator-runtime: ^0.13.7 - serve-favicon: ^2.5.0 - slash: ^3.0.0 - telejson: ^6.0.8 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - watchpack: ^2.2.0 - webpack: 4 - ws: ^8.2.3 - x-default-browser: ^0.4.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - "@storybook/builder-webpack5": - optional: true - "@storybook/manager-webpack5": - optional: true - typescript: - optional: true - checksum: 710d1562caa3a11233f15505db67fd32ab604fcfb6911d7d1c1c20c1d6f86cc15dadb06ff9eedbcd7f66d3e0b5b31209293fe989056023710f2d31f81f597b26 - languageName: node - linkType: hard - -"@storybook/core-server@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/core-server@npm:7.5.1" +"@storybook/core-server@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/core-server@npm:7.6.19" dependencies: "@aw-web-design/x-default-browser": 1.4.126 "@discoveryjs/json-ext": ^0.5.3 - "@storybook/builder-manager": 7.5.1 - "@storybook/channels": 7.5.1 - "@storybook/core-common": 7.5.1 - "@storybook/core-events": 7.5.1 - "@storybook/csf": ^0.1.0 - "@storybook/csf-tools": 7.5.1 + "@storybook/builder-manager": 7.6.19 + "@storybook/channels": 7.6.19 + "@storybook/core-common": 7.6.19 + "@storybook/core-events": 7.6.19 + "@storybook/csf": ^0.1.2 + "@storybook/csf-tools": 7.6.19 "@storybook/docs-mdx": ^0.1.0 "@storybook/global": ^5.0.0 - "@storybook/manager": 7.5.1 - "@storybook/node-logger": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/telemetry": 7.5.1 - "@storybook/types": 7.5.1 + "@storybook/manager": 7.6.19 + "@storybook/node-logger": 7.6.19 + "@storybook/preview-api": 7.6.19 + "@storybook/telemetry": 7.6.19 + "@storybook/types": 7.6.19 "@types/detect-port": ^1.3.0 "@types/node": ^18.0.0 "@types/pretty-hrtime": ^1.0.0 @@ -13388,7 +10060,7 @@ __metadata: express: ^4.17.3 fs-extra: ^11.1.0 globby: ^11.0.2 - ip: ^2.0.0 + ip: ^2.0.1 lodash: ^4.17.21 open: ^8.4.0 pretty-hrtime: ^1.0.3 @@ -13402,91 +10074,34 @@ __metadata: util-deprecate: ^1.0.2 watchpack: ^2.2.0 ws: ^8.2.3 - checksum: bbc9ac63641b00edede9df8813c745e40ecd2efb51313212d3878cfdaaf94e73cd22120d0c771abba18a26e13ed5d549ec930dd7b4ad6f1540c2ef0a17f29b6e + checksum: 4e9f4cd7aacb9c8008acdc630223fc4854f93a7bd9c7ecf1db622df1202a98cc4d5de5d01a97ab43fcdb08311a7ddb0b19b4a0e67ebf19556f15710e891bb73b languageName: node linkType: hard -"@storybook/core@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/core@npm:6.5.16" +"@storybook/csf-plugin@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/csf-plugin@npm:7.6.19" dependencies: - "@storybook/core-client": 6.5.16 - "@storybook/core-server": 6.5.16 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - webpack: "*" - peerDependenciesMeta: - "@storybook/builder-webpack5": - optional: true - "@storybook/manager-webpack5": - optional: true - typescript: - optional: true - checksum: 218696a20bd273c269597229e8aa6e8145246fef0919ca3fb16369eb4683b5dcc339f24f80bc46844e0017c14e51d9273dc96b4077ad8743ffafea02505f2324 - languageName: node - linkType: hard - -"@storybook/csf-plugin@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/csf-plugin@npm:7.5.1" - dependencies: - "@storybook/csf-tools": 7.5.1 + "@storybook/csf-tools": 7.6.19 unplugin: ^1.3.1 - checksum: 979060ef98e48d60645a265ad7f4eb7fadf760617612dc70b1c5b7368aa389795da0e7e8817a29b0b055a90e781de23ae24bc18f16679947a988bf327ece2af5 + checksum: 93556567ea0fbb130f0204e9dd04c03bbbd6f0a95ecf413d94659b2e0e6922dd0db4124ae549ff6a3fb8bb78d2338ea21f2f9d98b1857fcd4e6d8301c77d0a05 languageName: node linkType: hard -"@storybook/csf-tools@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/csf-tools@npm:6.5.16" +"@storybook/csf-tools@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/csf-tools@npm:7.6.19" dependencies: - "@babel/core": ^7.12.10 - "@babel/generator": ^7.12.11 - "@babel/parser": ^7.12.11 - "@babel/plugin-transform-react-jsx": ^7.12.12 - "@babel/preset-env": ^7.12.11 - "@babel/traverse": ^7.12.11 - "@babel/types": ^7.12.11 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/mdx1-csf": ^0.0.1 - core-js: ^3.8.2 - fs-extra: ^9.0.1 - global: ^4.4.0 - regenerator-runtime: ^0.13.7 - ts-dedent: ^2.0.0 - peerDependencies: - "@storybook/mdx2-csf": ^0.0.3 - peerDependenciesMeta: - "@storybook/mdx2-csf": - optional: true - checksum: 4e0ede613d65db9361e00d63233c2c1567043e0a5250c486d7714468311c9d57875d21156b75caf549dd553fc8098730b2648eeaff2e1ffbab2fba34fc3a1798 - languageName: node - linkType: hard - -"@storybook/csf-tools@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/csf-tools@npm:7.5.1" - dependencies: - "@babel/generator": ^7.22.9 - "@babel/parser": ^7.22.7 - "@babel/traverse": ^7.22.8 - "@babel/types": ^7.22.5 - "@storybook/csf": ^0.1.0 - "@storybook/types": 7.5.1 + "@babel/generator": ^7.23.0 + "@babel/parser": ^7.23.0 + "@babel/traverse": ^7.23.2 + "@babel/types": ^7.23.0 + "@storybook/csf": ^0.1.2 + "@storybook/types": 7.6.19 fs-extra: ^11.1.0 recast: ^0.23.1 ts-dedent: ^2.0.0 - checksum: ec0c5100379beeb691b3bad6e9368f2946d1487f748562a3b4e2871af3541db13d26bd2a413b7dcbb756a6af874f161c091035a21fb60263795504636e640a82 - languageName: node - linkType: hard - -"@storybook/csf@npm:0.0.2--canary.4566f4d.1": - version: 0.0.2--canary.4566f4d.1 - resolution: "@storybook/csf@npm:0.0.2--canary.4566f4d.1" - dependencies: - lodash: ^4.17.15 - checksum: dc0fe9940a47fbba9762275083816953da07a188f0315a631c307716b16a7073586a4d229df6b177dfb4b01604667e2bb24c13d6bfcb137d2f4d306874a590f4 + checksum: 8f362672c475b3ea328eaa98b7575d338fbe18e281d046ac6dfd2efe6cce17e53027fa6fb6e4e45682ec2d07605e5428eec1328abcdff4e1c904161f2a99e659 languageName: node linkType: hard @@ -13499,12 +10114,12 @@ __metadata: languageName: node linkType: hard -"@storybook/csf@npm:^0.1.0": - version: 0.1.1 - resolution: "@storybook/csf@npm:0.1.1" +"@storybook/csf@npm:^0.1.2": + version: 0.1.7 + resolution: "@storybook/csf@npm:0.1.7" dependencies: type-fest: ^2.19.0 - checksum: 999bb87fbbe047a559bbaa5baf2ed84872fcd5cdcae3c1169f8e4c641eefe8759d09a09034a78ed114032c0e5cf6301b7fa89e5e3ce60d75cf0bd5e33ec0a6e7 + checksum: aaebc9fa5f850cebef1fd9d786d7b5844e2d88e5c8078904ea4571c053f858fab064392960274b854037b9f8693d12c7c45c3c4c9142ec88a08fb498f3f056a5 languageName: node linkType: hard @@ -13515,32 +10130,18 @@ __metadata: languageName: node linkType: hard -"@storybook/docs-tools@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/docs-tools@npm:6.5.16" +"@storybook/docs-tools@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/docs-tools@npm:7.6.19" dependencies: - "@babel/core": ^7.12.10 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/store": 6.5.16 - core-js: ^3.8.2 - doctrine: ^3.0.0 - lodash: ^4.17.21 - regenerator-runtime: ^0.13.7 - checksum: 240aa397ad6cd4d8afd80c26ec893cd483afacebea6e2f1c08e18e7079c9c057221854cc1d31fb3e2c53254548edc11238c5a3a3916b19f4523a67a17a5c855f - languageName: node - linkType: hard - -"@storybook/docs-tools@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/docs-tools@npm:7.5.1" - dependencies: - "@storybook/core-common": 7.5.1 - "@storybook/preview-api": 7.5.1 - "@storybook/types": 7.5.1 + "@storybook/core-common": 7.6.19 + "@storybook/preview-api": 7.6.19 + "@storybook/types": 7.6.19 "@types/doctrine": ^0.0.3 + assert: ^2.1.0 doctrine: ^3.0.0 lodash: ^4.17.21 - checksum: 7eccd668ac4fc50730482025044c3ebff96bd07bf9cfbee5212c4b89ebb3e18b3730c217044094bf3cf1114d4d4cabccb92485698b176222ec4a80dd19128a04 + checksum: 667f3da08737e186dae79369b78e65b428aa49b9d58dc2ecac087420548e45fb680880c8934289c8c2ddc8ed19c2042f72bada1949076b2cda459df1628e29cd languageName: node linkType: hard @@ -13551,117 +10152,47 @@ __metadata: languageName: node linkType: hard -"@storybook/instrumenter@npm:7.5.1, @storybook/instrumenter@npm:^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0": - version: 7.5.1 - resolution: "@storybook/instrumenter@npm:7.5.1" +"@storybook/instrumenter@npm:^7.0.0-beta.0 || ^7.0.0-rc.0 || ^7.0.0": + version: 7.6.19 + resolution: "@storybook/instrumenter@npm:7.6.19" dependencies: - "@storybook/channels": 7.5.1 - "@storybook/client-logger": 7.5.1 - "@storybook/core-events": 7.5.1 + "@storybook/channels": 7.6.19 + "@storybook/client-logger": 7.6.19 + "@storybook/core-events": 7.6.19 "@storybook/global": ^5.0.0 - "@storybook/preview-api": 7.5.1 - checksum: 57af56556fccb03a646c4ef2db546cced728460a29987c6d18e43450e93d864c73302a470f2b790cd1383d265946c1ef07dddb7f55523ebf51f431f9a1ae4bb1 + "@storybook/preview-api": 7.6.19 + "@vitest/utils": ^0.34.6 + util: ^0.12.4 + checksum: 9d07a28da8dae63b5abecbef9b49dcd673961ff35b2444926382c0f379b4fa47f0dfae48916343df5c48fe5055fe7fe5a801342a93aaf99e8c26be9e4b1f3734 languageName: node linkType: hard -"@storybook/manager-api@npm:7.5.1, @storybook/manager-api@npm:^7.0.12": - version: 7.5.1 - resolution: "@storybook/manager-api@npm:7.5.1" +"@storybook/manager-api@npm:7.6.19, @storybook/manager-api@npm:^7.0.12": + version: 7.6.19 + resolution: "@storybook/manager-api@npm:7.6.19" dependencies: - "@storybook/channels": 7.5.1 - "@storybook/client-logger": 7.5.1 - "@storybook/core-events": 7.5.1 - "@storybook/csf": ^0.1.0 + "@storybook/channels": 7.6.19 + "@storybook/client-logger": 7.6.19 + "@storybook/core-events": 7.6.19 + "@storybook/csf": ^0.1.2 "@storybook/global": ^5.0.0 - "@storybook/router": 7.5.1 - "@storybook/theming": 7.5.1 - "@storybook/types": 7.5.1 + "@storybook/router": 7.6.19 + "@storybook/theming": 7.6.19 + "@storybook/types": 7.6.19 dequal: ^2.0.2 lodash: ^4.17.21 memoizerific: ^1.11.3 - semver: ^7.3.7 store2: ^2.14.2 telejson: ^7.2.0 ts-dedent: ^2.0.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: ae2ea9081fc660bd7350eafeebe39275f2358f368dffa3f9117f385adc5eed399e0b33a8b26d5ea38e09d0088edcbeebd605d046b8ee87689b42cc77b3825598 + checksum: e1f48864bcd17615c56e5589ffff55193c7667605f7ec348e08d829ceaea70987e0e1cb38e46f112cf0e49b067581c892e88447f465403eefde22cab200af3d2 languageName: node linkType: hard -"@storybook/manager-webpack4@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/manager-webpack4@npm:6.5.16" - dependencies: - "@babel/core": ^7.12.10 - "@babel/plugin-transform-template-literals": ^7.12.1 - "@babel/preset-react": ^7.12.10 - "@storybook/addons": 6.5.16 - "@storybook/core-client": 6.5.16 - "@storybook/core-common": 6.5.16 - "@storybook/node-logger": 6.5.16 - "@storybook/theming": 6.5.16 - "@storybook/ui": 6.5.16 - "@types/node": ^14.0.10 || ^16.0.0 - "@types/webpack": ^4.41.26 - babel-loader: ^8.0.0 - case-sensitive-paths-webpack-plugin: ^2.3.0 - chalk: ^4.1.0 - core-js: ^3.8.2 - css-loader: ^3.6.0 - express: ^4.17.1 - file-loader: ^6.2.0 - find-up: ^5.0.0 - fs-extra: ^9.0.1 - html-webpack-plugin: ^4.0.0 - node-fetch: ^2.6.7 - pnp-webpack-plugin: 1.6.4 - read-pkg-up: ^7.0.1 - regenerator-runtime: ^0.13.7 - resolve-from: ^5.0.0 - style-loader: ^1.3.0 - telejson: ^6.0.8 - terser-webpack-plugin: ^4.2.3 - ts-dedent: ^2.0.0 - url-loader: ^4.1.1 - util-deprecate: ^1.0.2 - webpack: 4 - webpack-dev-middleware: ^3.7.3 - webpack-virtual-modules: ^0.2.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 9e8ebc2022b19d8ed9a6832517e5251508c1a7a76660fbc0796192edda7dd18b477c5d1f79a784289a71ebed9fac862fc4ea402f0d27ed365261551d61ebcfae - languageName: node - linkType: hard - -"@storybook/manager@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/manager@npm:7.5.1" - checksum: 2b99b2a044fad90fd76ea86d751bf22d116b54250ece184068cfd0f842abf40ba524dd0748bee8a84c346289b14f2feda48ad9a0cfac85491163df069c793a3e - languageName: node - linkType: hard - -"@storybook/mdx1-csf@npm:^0.0.1": - version: 0.0.1 - resolution: "@storybook/mdx1-csf@npm:0.0.1" - dependencies: - "@babel/generator": ^7.12.11 - "@babel/parser": ^7.12.11 - "@babel/preset-env": ^7.12.11 - "@babel/types": ^7.12.11 - "@mdx-js/mdx": ^1.6.22 - "@types/lodash": ^4.14.167 - js-string-escape: ^1.0.1 - loader-utils: ^2.0.0 - lodash: ^4.17.21 - prettier: ">=2.2.1 <=2.3.0" - ts-dedent: ^2.0.0 - checksum: c25a4ad1356ce65950483bd85f37ba93237149fd782360e3548a86dafd9753674ddebb03a8665ed78f99bc1533e87ba2a0605c2fc984a5ad19662fd4b930db78 +"@storybook/manager@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/manager@npm:7.6.19" + checksum: e145747a28cc10507f572f1c0f22b5dbf4ccf346e64614946d9bb57b048768a0fa83cb3d24dfe7a24fb43ed070c82f5c0c768bf1b6e9667ddc8c732e66512b25 languageName: node linkType: hard @@ -13672,52 +10203,30 @@ __metadata: languageName: node linkType: hard -"@storybook/node-logger@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/node-logger@npm:6.5.16" +"@storybook/node-logger@npm:7.6.19, @storybook/node-logger@npm:^7.0.12": + version: 7.6.19 + resolution: "@storybook/node-logger@npm:7.6.19" + checksum: cfb5ff9b6135cf59a9ea61613bcb6786485bf7a41593ad0d02d4d3f833ee672057bb7741cbd40baf79f7fdf1b45e80b86528d4b67a6f20ffdb93a8b83956eedd + languageName: node + linkType: hard + +"@storybook/postinstall@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/postinstall@npm:7.6.19" + checksum: 6356e55670fe83ea8afd3e1458c04e0e5a6ceb4dabdd0cf83ef80dc33409542923e180760fc9b29308aff51ead25a60383b6ef6126a5cf8754b7a50d7a6f2a47 + languageName: node + linkType: hard + +"@storybook/preview-api@npm:7.6.19, @storybook/preview-api@npm:^7.0.12": + version: 7.6.19 + resolution: "@storybook/preview-api@npm:7.6.19" dependencies: - "@types/npmlog": ^4.1.2 - chalk: ^4.1.0 - core-js: ^3.8.2 - npmlog: ^5.0.1 - pretty-hrtime: ^1.0.3 - checksum: 53d922aace33a58b016bc1db65f71b3aaf615af1fe64c61b80c91ea29b76549b02a9a77f9f00466b89dc44e8f2e5070842cc7cb15e294a635b501602575388cc - languageName: node - linkType: hard - -"@storybook/node-logger@npm:7.5.1, @storybook/node-logger@npm:^7.0.12": - version: 7.5.1 - resolution: "@storybook/node-logger@npm:7.5.1" - checksum: 4977191230f3a34efb644218c1092c293757be358224ce7cca8ad32e1f84f18c51b7bc564728b5b9350d4f1bb0c2feb8b08e22d29741c10e40c7c79c20a56a5d - languageName: node - linkType: hard - -"@storybook/postinstall@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/postinstall@npm:6.5.16" - dependencies: - core-js: ^3.8.2 - checksum: e86cc51db1c70107e7f1b7b1eda570032539189e6e1ac909ecd5dfb82027e7eec7e0f007a63200591a280d8700fc30cc0fd940de5262292c76baef2de6d84701 - languageName: node - linkType: hard - -"@storybook/postinstall@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/postinstall@npm:7.5.1" - checksum: 07793a47dd50b48005d61b9560c2a3647dc3bd73ffc8f14773211d7dd1b09e9a193b069e28304d6f0a46b6e9b1daca0740869e8af78b4642247daaab78bc0e7e - languageName: node - linkType: hard - -"@storybook/preview-api@npm:7.5.1, @storybook/preview-api@npm:^7.0.12": - version: 7.5.1 - resolution: "@storybook/preview-api@npm:7.5.1" - dependencies: - "@storybook/channels": 7.5.1 - "@storybook/client-logger": 7.5.1 - "@storybook/core-events": 7.5.1 - "@storybook/csf": ^0.1.0 + "@storybook/channels": 7.6.19 + "@storybook/client-logger": 7.6.19 + "@storybook/core-events": 7.6.19 + "@storybook/csf": ^0.1.2 "@storybook/global": ^5.0.0 - "@storybook/types": 7.5.1 + "@storybook/types": 7.6.19 "@types/qs": ^6.9.5 dequal: ^2.0.2 lodash: ^4.17.21 @@ -13726,102 +10235,57 @@ __metadata: synchronous-promise: ^2.0.15 ts-dedent: ^2.0.0 util-deprecate: ^1.0.2 - checksum: dd600eeaf752def91b81816bdfe353edf4217a81fca76535e9bec98fff4d4614ada2eded486f0404c6e3304ef734d2945cf8e93bff7ab1753d2b75acd2925415 + checksum: 4c43ed02034e07070087308093899df809a14d1152bd1aff90e1f2a285e4f6e7fd5844d0c8de1be64c5883b040b6ae509ef9dae621acbca00ffb3f4eec4882b3 languageName: node linkType: hard -"@storybook/preview-web@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/preview-web@npm:6.5.16" - dependencies: - "@storybook/addons": 6.5.16 - "@storybook/channel-postmessage": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/store": 6.5.16 - ansi-to-html: ^0.6.11 - core-js: ^3.8.2 - global: ^4.4.0 - lodash: ^4.17.21 - qs: ^6.10.0 - regenerator-runtime: ^0.13.7 - synchronous-promise: ^2.0.15 - ts-dedent: ^2.0.0 - unfetch: ^4.2.0 - util-deprecate: ^1.0.2 +"@storybook/preview@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/preview@npm:7.6.19" + checksum: 7a75392738f55d115b404fc41a00351e23733b10b95fffd75e1af4043469dc8d1cefeca1cfa88145aa0f8d4a856986804b617e3254f5eed2a588bf13203e3dfa + languageName: node + linkType: hard + +"@storybook/react-dom-shim@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/react-dom-shim@npm:7.6.19" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 378d2c196e69e95837d6286824f192cb5ae97d6aaff490ef6bb9e1c8428e97d52f16e07cd62de0dc92945db43ab7b68d7c12113b87cec98a836121b36cf56744 - languageName: node - linkType: hard - -"@storybook/preview@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/preview@npm:7.5.1" - checksum: b4dcd89c27b2b88ef2e103225ae727a8e0454897567e1b407f131239750aa2a0e6bc69146524c92eef1970d48aafc8b4b8e206c005096e9b9b0c7de3ce34fe99 - languageName: node - linkType: hard - -"@storybook/react-docgen-typescript-plugin@npm:1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0": - version: 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0 - resolution: "@storybook/react-docgen-typescript-plugin@npm:1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0" - dependencies: - debug: ^4.1.1 - endent: ^2.0.1 - find-cache-dir: ^3.3.1 - flat-cache: ^3.0.4 - micromatch: ^4.0.2 - react-docgen-typescript: ^2.1.1 - tslib: ^2.0.0 - peerDependencies: - typescript: ">= 3.x" - webpack: ">= 4" - checksum: 2d3ab49e4858d5f28f36b5bd0e30f3d3450bc7d9865cd4fbe65a35085ae63feff9556a3265b594a2c84b03c66f009dc8b057802f3ca0f76b961d51536835cb8f - languageName: node - linkType: hard - -"@storybook/react-dom-shim@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/react-dom-shim@npm:7.5.1" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 4ae5e7501495f16ddd2906ea0d95b496c3c99d18cc4198b97c58c81bd59c0ca5c803fe262f9023d8125060523e7234e4dc82d75c019a3a185cf071ddaa3a6c03 + checksum: bed132060ffe000fa73bb90c5325afbb22b74346e23f382becabd4e05889e9f0199527782f454bf5fc409174b56d80f50ab3fcd8fc674148117724b22b303c30 languageName: node linkType: hard "@storybook/react-vite@npm:^7.0.23": - version: 7.5.1 - resolution: "@storybook/react-vite@npm:7.5.1" + version: 7.6.19 + resolution: "@storybook/react-vite@npm:7.6.19" dependencies: "@joshwooding/vite-plugin-react-docgen-typescript": 0.3.0 "@rollup/pluginutils": ^5.0.2 - "@storybook/builder-vite": 7.5.1 - "@storybook/react": 7.5.1 + "@storybook/builder-vite": 7.6.19 + "@storybook/react": 7.6.19 "@vitejs/plugin-react": ^3.0.1 magic-string: ^0.30.0 - react-docgen: ^6.0.2 + react-docgen: ^7.0.0 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 || ^5.0.0 - checksum: 0fc92436284b2e5addab1c8cf8916b45e407faf70ee18282b1ec7fe1840cbc1e8a825bf5536c70e80d8e88e4b906c17fd60719f119600ca4520b1618d3a89afa + checksum: 3a216a42e6d06b00590686b8bceb1a853260c6074cd80eae265e444286f8105571f40daf5000686da5d10443521d6bbd3abcf1234c1fd52b977a4cbdc71119d6 languageName: node linkType: hard -"@storybook/react@npm:7.5.1, @storybook/react@npm:^7.0.23": - version: 7.5.1 - resolution: "@storybook/react@npm:7.5.1" +"@storybook/react@npm:7.6.19, @storybook/react@npm:^7.0.23": + version: 7.6.19 + resolution: "@storybook/react@npm:7.6.19" dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/core-client": 7.5.1 - "@storybook/docs-tools": 7.5.1 + "@storybook/client-logger": 7.6.19 + "@storybook/core-client": 7.6.19 + "@storybook/docs-tools": 7.6.19 "@storybook/global": ^5.0.0 - "@storybook/preview-api": 7.5.1 - "@storybook/react-dom-shim": 7.5.1 - "@storybook/types": 7.5.1 + "@storybook/preview-api": 7.6.19 + "@storybook/react-dom-shim": 7.6.19 + "@storybook/types": 7.6.19 "@types/escodegen": ^0.0.6 "@types/estree": ^0.0.51 "@types/node": ^18.0.0 @@ -13843,197 +10307,34 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: b9bca9e619ba96b574f6098af12b6bda0fa5f792c35750656fa8b67b390e91e202c2ca5b841b04b90b9db091454b5c57eac1e58a74fd5e072ed0715d71c176a3 + checksum: cddfc34ade9bad3411c1228633b2c63496cbe8edadb8dac0bbfda4669d2bfdfb0984cfe8c1db247c55d2a675da3ddb8bd4ddeb7b69f0f9d1098882e129bffc47 languageName: node linkType: hard -"@storybook/react@npm:^6.3.12": - version: 6.5.16 - resolution: "@storybook/react@npm:6.5.16" +"@storybook/router@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/router@npm:7.6.19" dependencies: - "@babel/preset-flow": ^7.12.1 - "@babel/preset-react": ^7.12.10 - "@pmmmwh/react-refresh-webpack-plugin": ^0.5.3 - "@storybook/addons": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/core": 6.5.16 - "@storybook/core-common": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/docs-tools": 6.5.16 - "@storybook/node-logger": 6.5.16 - "@storybook/react-docgen-typescript-plugin": 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0 - "@storybook/semver": ^7.3.2 - "@storybook/store": 6.5.16 - "@types/estree": ^0.0.51 - "@types/node": ^14.14.20 || ^16.0.0 - "@types/webpack-env": ^1.16.0 - acorn: ^7.4.1 - acorn-jsx: ^5.3.1 - acorn-walk: ^7.2.0 - babel-plugin-add-react-displayname: ^0.0.5 - babel-plugin-react-docgen: ^4.2.1 - core-js: ^3.8.2 - escodegen: ^2.0.0 - fs-extra: ^9.0.1 - global: ^4.4.0 - html-tags: ^3.1.0 - lodash: ^4.17.21 - prop-types: ^15.7.2 - react-element-to-jsx-string: ^14.3.4 - react-refresh: ^0.11.0 - read-pkg-up: ^7.0.1 - regenerator-runtime: ^0.13.7 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - webpack: ">=4.43.0 <6.0.0" - peerDependencies: - "@babel/core": ^7.11.5 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - require-from-string: ^2.0.2 - peerDependenciesMeta: - "@babel/core": - optional: true - "@storybook/builder-webpack4": - optional: true - "@storybook/builder-webpack5": - optional: true - "@storybook/manager-webpack4": - optional: true - "@storybook/manager-webpack5": - optional: true - typescript: - optional: true - bin: - build-storybook: bin/build.js - start-storybook: bin/index.js - storybook-server: bin/index.js - checksum: d87df8e96b9f006d3f388aef60fc4ca1cf7535d69f219188a84c581358014be6beaa987a054906e650d73f32513c9dd480e1660185471c9332de17dd611b7182 - languageName: node - linkType: hard - -"@storybook/router@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/router@npm:6.5.16" - dependencies: - "@storybook/client-logger": 6.5.16 - core-js: ^3.8.2 + "@storybook/client-logger": 7.6.19 memoizerific: ^1.11.3 qs: ^6.10.0 - regenerator-runtime: ^0.13.7 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 7f16ddc1252a01aae0282d0ac88c78db1ae8a4ab372cea848f726cb0e59ce2906304bd83a77021cab75d6f7c45518db20fedd72d282030752a11e8a87876349a + checksum: d20ce5d9d40dcac4d473cec1215be9b8eadfc94bcd9ffa4522db9de8e9351497be35892a6e1bc1c9d02acd5423e4a05622a44500b9dcbb9619adfdca1b04c1e1 languageName: node linkType: hard -"@storybook/router@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/router@npm:7.5.1" +"@storybook/telemetry@npm:7.6.19": + version: 7.6.19 + resolution: "@storybook/telemetry@npm:7.6.19" dependencies: - "@storybook/client-logger": 7.5.1 - memoizerific: ^1.11.3 - qs: ^6.10.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 52f84e2c53d919d492d38cd18df745b82ec1d61b959a78bbf48664e48414b77da8474f009c6fb10f8dba6d4c6eb29fd44a1c6d3e10b37bac2b3a451113177c2f - languageName: node - linkType: hard - -"@storybook/semver@npm:^7.3.2": - version: 7.3.2 - resolution: "@storybook/semver@npm:7.3.2" - dependencies: - core-js: ^3.6.5 - find-up: ^4.1.0 - bin: - semver: bin/semver.js - checksum: f90e0c714d694330e9664af96ff7c3806c10981d6754e839caf59cd6791bf38c050caf98b19e97f7b059fd8521217f5f70b941a79b68a40b485e054d46343791 - languageName: node - linkType: hard - -"@storybook/source-loader@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/source-loader@npm:6.5.16" - dependencies: - "@storybook/addons": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - core-js: ^3.8.2 - estraverse: ^5.2.0 - global: ^4.4.0 - loader-utils: ^2.0.4 - lodash: ^4.17.21 - prettier: ">=2.2.1 <=2.3.0" - regenerator-runtime: ^0.13.7 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 9dfed1ad02a76c947e11b68fb680b66f1acd7c26361d686b13908b2c0b27bd96334a67678e254ccdfa306e1b88a24501ce548b6f2d030bd1bed9da25fdb758b3 - languageName: node - linkType: hard - -"@storybook/store@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/store@npm:6.5.16" - dependencies: - "@storybook/addons": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - core-js: ^3.8.2 - fast-deep-equal: ^3.1.3 - global: ^4.4.0 - lodash: ^4.17.21 - memoizerific: ^1.11.3 - regenerator-runtime: ^0.13.7 - slash: ^3.0.0 - stable: ^0.1.8 - synchronous-promise: ^2.0.15 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 403c4a99f29093b6ce546a18b9291e91e58db2a44e7e7da0dc81cd4d7f28220b42d63ee9f0e18bc9b19aff61df44658c38ae1d61bfa2ba4cf3fbb9f8354df492 - languageName: node - linkType: hard - -"@storybook/telemetry@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/telemetry@npm:6.5.16" - dependencies: - "@storybook/client-logger": 6.5.16 - "@storybook/core-common": 6.5.16 - chalk: ^4.1.0 - core-js: ^3.8.2 - detect-package-manager: ^2.0.1 - fetch-retry: ^5.0.2 - fs-extra: ^9.0.1 - global: ^4.4.0 - isomorphic-unfetch: ^3.1.0 - nanoid: ^3.3.1 - read-pkg-up: ^7.0.1 - regenerator-runtime: ^0.13.7 - checksum: 5f8c09720477fb52cb824cb5194d1f5af9affb3f068170432741d897059b710912525412b33f716238f32a635fba349a8cbebe2360c844a339fc720e73827016 - languageName: node - linkType: hard - -"@storybook/telemetry@npm:7.5.1": - version: 7.5.1 - resolution: "@storybook/telemetry@npm:7.5.1" - dependencies: - "@storybook/client-logger": 7.5.1 - "@storybook/core-common": 7.5.1 - "@storybook/csf-tools": 7.5.1 + "@storybook/client-logger": 7.6.19 + "@storybook/core-common": 7.6.19 + "@storybook/csf-tools": 7.6.19 chalk: ^4.1.0 detect-package-manager: ^2.0.1 fetch-retry: ^5.0.2 fs-extra: ^11.1.0 read-pkg-up: ^7.0.1 - checksum: 60eaca85dd2168dbd22a7726565bf7393c06d83b006eb9a887b6a56fa421f566b5ebc101afb7242b36e1eaad68ddd416ab172db2144742c4fcaad9dc974fd85b + checksum: 78b1d65363abf043f00e7e99489d6502e62dfe5ff31156668e3fd2931d3f7768ddfd72957072b8c96363bf5a5446c4f46803d4c342020c732d9ed6fe41787282 languageName: node linkType: hard @@ -14050,70 +10351,30 @@ __metadata: languageName: node linkType: hard -"@storybook/theming@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/theming@npm:6.5.16" - dependencies: - "@storybook/client-logger": 6.5.16 - core-js: ^3.8.2 - memoizerific: ^1.11.3 - regenerator-runtime: ^0.13.7 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: d8256badcd97189705be9a0de27b53da6cac5562e8a95b37530de183c8ffbfc71e5d9cbb1993dc67413079486c2353440ab61d0e748c6f4f72f9353354d6005a - languageName: node - linkType: hard - -"@storybook/theming@npm:7.5.1, @storybook/theming@npm:^7.0.12": - version: 7.5.1 - resolution: "@storybook/theming@npm:7.5.1" +"@storybook/theming@npm:7.6.19, @storybook/theming@npm:^7.0.12": + version: 7.6.19 + resolution: "@storybook/theming@npm:7.6.19" dependencies: "@emotion/use-insertion-effect-with-fallbacks": ^1.0.0 - "@storybook/client-logger": 7.5.1 + "@storybook/client-logger": 7.6.19 "@storybook/global": ^5.0.0 memoizerific: ^1.11.3 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 2b59ac6bb41a024ca31e5a39daa1b46c52da03bc1d69f3e3f91173621a0d1928a722acebe63d1ff84f50e0bbc0a661f5f48bde36a40292e40c670674bdeaf53a + checksum: 41f02bf38d2842ed77691bf645f818d8f4560655b95922a871f5f633a7bbec66d7ddf4ed98c48fec13460e8773ba6c400b860981de612e872e0ef0257eeb9f94 languageName: node linkType: hard -"@storybook/types@npm:7.5.1, @storybook/types@npm:^7.0.12": - version: 7.5.1 - resolution: "@storybook/types@npm:7.5.1" +"@storybook/types@npm:7.6.19, @storybook/types@npm:^7.0.12": + version: 7.6.19 + resolution: "@storybook/types@npm:7.6.19" dependencies: - "@storybook/channels": 7.5.1 + "@storybook/channels": 7.6.19 "@types/babel__core": ^7.0.0 "@types/express": ^4.7.0 file-system-cache: 2.3.0 - checksum: 8f3aeb459f0b1af5c6ed8c6bf79d1be9089078733ef2b7e6353862d1238d0bc5a303749210ad268a220e9b79c9ebc6b5f8ef7e1fef423a5d7e4bb6c3ed627bfc - languageName: node - linkType: hard - -"@storybook/ui@npm:6.5.16": - version: 6.5.16 - resolution: "@storybook/ui@npm:6.5.16" - dependencies: - "@storybook/addons": 6.5.16 - "@storybook/api": 6.5.16 - "@storybook/channels": 6.5.16 - "@storybook/client-logger": 6.5.16 - "@storybook/components": 6.5.16 - "@storybook/core-events": 6.5.16 - "@storybook/router": 6.5.16 - "@storybook/semver": ^7.3.2 - "@storybook/theming": 6.5.16 - core-js: ^3.8.2 - memoizerific: ^1.11.3 - qs: ^6.10.0 - regenerator-runtime: ^0.13.7 - resolve-from: ^5.0.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: ae15c0f7c51de5b32a8c007964010692d0ae1ca5240d092ce241bb6feb6aa0bad6f18fd34b30f3162914a82815e2fb0c1a8e61cbb1aaad4dc36eda7a4ee19aae + checksum: 6df3b74b0164c44e7edf2eb77458daac90b4facdd739bbec09498e88dfa6d29bf61cff9d937b7c27145f8e7029bc50a28d306c66ebafc868ad042bf73ff4aaf9 languageName: node linkType: hard @@ -14269,90 +10530,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.4.8": - version: 1.4.8 - resolution: "@swc/core-darwin-arm64@npm:1.4.8" +"@swc/core-darwin-arm64@npm:1.5.3": + version: 1.5.3 + resolution: "@swc/core-darwin-arm64@npm:1.5.3" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.4.8": - version: 1.4.8 - resolution: "@swc/core-darwin-x64@npm:1.4.8" +"@swc/core-darwin-x64@npm:1.5.3": + version: 1.5.3 + resolution: "@swc/core-darwin-x64@npm:1.5.3" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.4.8": - version: 1.4.8 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.4.8" +"@swc/core-linux-arm-gnueabihf@npm:1.5.3": + version: 1.5.3 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.5.3" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.4.8": - version: 1.4.8 - resolution: "@swc/core-linux-arm64-gnu@npm:1.4.8" +"@swc/core-linux-arm64-gnu@npm:1.5.3": + version: 1.5.3 + resolution: "@swc/core-linux-arm64-gnu@npm:1.5.3" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.4.8": - version: 1.4.8 - resolution: "@swc/core-linux-arm64-musl@npm:1.4.8" +"@swc/core-linux-arm64-musl@npm:1.5.3": + version: 1.5.3 + resolution: "@swc/core-linux-arm64-musl@npm:1.5.3" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.4.8": - version: 1.4.8 - resolution: "@swc/core-linux-x64-gnu@npm:1.4.8" +"@swc/core-linux-x64-gnu@npm:1.5.3": + version: 1.5.3 + resolution: "@swc/core-linux-x64-gnu@npm:1.5.3" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.4.8": - version: 1.4.8 - resolution: "@swc/core-linux-x64-musl@npm:1.4.8" +"@swc/core-linux-x64-musl@npm:1.5.3": + version: 1.5.3 + resolution: "@swc/core-linux-x64-musl@npm:1.5.3" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.4.8": - version: 1.4.8 - resolution: "@swc/core-win32-arm64-msvc@npm:1.4.8" +"@swc/core-win32-arm64-msvc@npm:1.5.3": + version: 1.5.3 + resolution: "@swc/core-win32-arm64-msvc@npm:1.5.3" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.4.8": - version: 1.4.8 - resolution: "@swc/core-win32-ia32-msvc@npm:1.4.8" +"@swc/core-win32-ia32-msvc@npm:1.5.3": + version: 1.5.3 + resolution: "@swc/core-win32-ia32-msvc@npm:1.5.3" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.4.8": - version: 1.4.8 - resolution: "@swc/core-win32-x64-msvc@npm:1.4.8" +"@swc/core-win32-x64-msvc@npm:1.5.3": + version: 1.5.3 + resolution: "@swc/core-win32-x64-msvc@npm:1.5.3" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.4.8": - version: 1.4.8 - resolution: "@swc/core@npm:1.4.8" + version: 1.5.3 + resolution: "@swc/core@npm:1.5.3" dependencies: - "@swc/core-darwin-arm64": 1.4.8 - "@swc/core-darwin-x64": 1.4.8 - "@swc/core-linux-arm-gnueabihf": 1.4.8 - "@swc/core-linux-arm64-gnu": 1.4.8 - "@swc/core-linux-arm64-musl": 1.4.8 - "@swc/core-linux-x64-gnu": 1.4.8 - "@swc/core-linux-x64-musl": 1.4.8 - "@swc/core-win32-arm64-msvc": 1.4.8 - "@swc/core-win32-ia32-msvc": 1.4.8 - "@swc/core-win32-x64-msvc": 1.4.8 + "@swc/core-darwin-arm64": 1.5.3 + "@swc/core-darwin-x64": 1.5.3 + "@swc/core-linux-arm-gnueabihf": 1.5.3 + "@swc/core-linux-arm64-gnu": 1.5.3 + "@swc/core-linux-arm64-musl": 1.5.3 + "@swc/core-linux-x64-gnu": 1.5.3 + "@swc/core-linux-x64-musl": 1.5.3 + "@swc/core-win32-arm64-msvc": 1.5.3 + "@swc/core-win32-ia32-msvc": 1.5.3 + "@swc/core-win32-x64-msvc": 1.5.3 "@swc/counter": ^0.1.2 "@swc/types": ^0.1.5 peerDependencies: @@ -14381,7 +10642,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: da9079e66d7de696bef2445ba5ba20c7be80b9132f56b7912f2359edab3caa02d334204e4663458771b1995e5556c0629de9427b55587cbac27de6b259c61932 + checksum: b038251989a600054d5d9cd54ed25febd1c32afa43914c33eeaafd8ed975cbe2491de2187dfacabcd1f6c29aaac55a91d7f9adc3818ef20438e10fd233e91e01 languageName: node linkType: hard @@ -14393,11 +10654,11 @@ __metadata: linkType: hard "@swc/helpers@npm:^0.5.0": - version: 0.5.1 - resolution: "@swc/helpers@npm:0.5.1" + version: 0.5.11 + resolution: "@swc/helpers@npm:0.5.11" dependencies: tslib: ^2.4.0 - checksum: 2e2272c8278351670e1daf27cc634ace793afb378dcc85be2800d30a7b4d3afad37707371ead2a6d96662fa30294da678d66cdc4dc7f3e698bd8e111235c60fc + checksum: 7d1987ee6b887277d373a9be8c445cd2259c3258c08b16908c06864121fd8eac8bb89b179c91b6c5395f38194a903b5772575947c7eb3ca23285152cb0f66caa languageName: node linkType: hard @@ -14433,57 +10694,31 @@ __metadata: linkType: hard "@tailwindcss/forms@npm:^0.5.3": - version: 0.5.3 - resolution: "@tailwindcss/forms@npm:0.5.3" + version: 0.5.7 + resolution: "@tailwindcss/forms@npm:0.5.7" dependencies: mini-svg-data-uri: ^1.2.3 peerDependencies: tailwindcss: ">=3.0.0 || >= 3.0.0-alpha.1" - checksum: 4881c1d5a9aeaa2eea453dd60a5b7c6671a11f0d74f6075d052a3b4f2d8c7e1f1a42f74fe52421da4c13b19018ab883199f528cd41e6fdb249ed638d3f04cd94 + checksum: cd29e0c978402ae87a923ae802dcff43f7b050595666cb067321cac2e37a52f61b9d73385cb0a10455548581ddd0d3886815bd6c64a1da06247c0057fa9f4601 languageName: node linkType: hard -"@tanstack/query-core@npm:4.22.0": - version: 4.22.0 - resolution: "@tanstack/query-core@npm:4.22.0" - checksum: be3f870719ea9c53dfc3398725c92876448a2a5cd8253010226ad88e91b0586d3c5e9bb9366ca27a035d5855517b6883ec0a5d7d4437458ff5bd3acb5553974f - languageName: node - linkType: hard - -"@tanstack/query-core@npm:5.28.13": - version: 5.28.13 - resolution: "@tanstack/query-core@npm:5.28.13" - checksum: 4eb2c162a05948caf556d84ee65a7d640786adcfdc3fbefaf3e010ab462bdfb3ea7bdb200829ca33ccc60699a9a6d9414e7d6a3ea92b819a5de25337ea07b0d7 - languageName: node - linkType: hard - -"@tanstack/react-query@npm:4.22.0": - version: 4.22.0 - resolution: "@tanstack/react-query@npm:4.22.0" - dependencies: - "@tanstack/query-core": 4.22.0 - use-sync-external-store: ^1.2.0 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-native: "*" - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - checksum: aacb071935c20ec695adfce7594649b6a7683640b82b232727f1b000bb871b6e99bb98bf47b9617eb76829d6b5822a6c98d3cefb1ede90a69cc52c2c79488d14 +"@tanstack/query-core@npm:5.35.1": + version: 5.35.1 + resolution: "@tanstack/query-core@npm:5.35.1" + checksum: c991efeb29ec42f9aadf43130dac5e4e9e0651880ef96e0cb5f0dc3224b9b919b34f0e4af53231a7de32582aa7ba801ed6683ed7448e41e7b2a344803f08f3fe languageName: node linkType: hard "@tanstack/react-query@npm:^5.28.14": - version: 5.28.14 - resolution: "@tanstack/react-query@npm:5.28.14" + version: 5.35.1 + resolution: "@tanstack/react-query@npm:5.35.1" dependencies: - "@tanstack/query-core": 5.28.13 + "@tanstack/query-core": 5.35.1 peerDependencies: react: ^18.0.0 - checksum: 34d269be1653d1ac313603c145540e15c5bd94da012b0fafda2f2d90bbc0712a213e41d4335d5b2f2fd54ac2f238dd0582aeb617b71edba5046235ec6bc69939 + checksum: 80b3d4e295b05171e34f522c1856bcd561c58963e7661ae2340f3406a3097b7c9896d4f67005876c634ce1d808791498a987b200f00341e6df9fcc862060e6ad languageName: node linkType: hard @@ -14500,14 +10735,14 @@ __metadata: linkType: hard "@tanstack/react-virtual@npm:^3.0.4": - version: 3.0.4 - resolution: "@tanstack/react-virtual@npm:3.0.4" + version: 3.5.0 + resolution: "@tanstack/react-virtual@npm:3.5.0" dependencies: - "@tanstack/virtual-core": 3.0.0 + "@tanstack/virtual-core": 3.5.0 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 6222dc1254843fa52bdb93deca74282e2b8aabd17337d7b35596441bb70d1d7e333b1679acfb50240847799d63ee24eb184958ad8c7f1ca84c4ff0c13aefa7ec + checksum: 0e0389dcae02cb3a6dc31644be6fedc9c635f66b747136149b065351ef23995e131b01c85348875a8c8c7bade28a2bb8bbc9c7b66a995051d6be08aec60d07c4 languageName: node linkType: hard @@ -14518,14 +10753,14 @@ __metadata: languageName: node linkType: hard -"@tanstack/virtual-core@npm:3.0.0": - version: 3.0.0 - resolution: "@tanstack/virtual-core@npm:3.0.0" - checksum: d0899fe470b43f80a2ccc567a01138cc015900f13d91b82abc784fc7bc46419e9c8b99c102a5c6ee76d15933db61aecc68c0ae8e92e9cb9ded9ae2f51a01cf4c +"@tanstack/virtual-core@npm:3.5.0": + version: 3.5.0 + resolution: "@tanstack/virtual-core@npm:3.5.0" + checksum: 21a12049df81ce282054e8406cb74dd21d867aac077f31568ffdb08acd9aa171ae0666ceb43654895e73907acf5db02c7d651a66960da8acceeb2e034885e605 languageName: node linkType: hard -"@testing-library/dom@npm:^8.3.0, @testing-library/dom@npm:^8.5.0": +"@testing-library/dom@npm:^8.3.0": version: 8.20.1 resolution: "@testing-library/dom@npm:8.20.1" dependencies: @@ -14542,8 +10777,8 @@ __metadata: linkType: hard "@testing-library/dom@npm:^9.0.0, @testing-library/dom@npm:^9.3.1": - version: 9.3.3 - resolution: "@testing-library/dom@npm:9.3.3" + version: 9.3.4 + resolution: "@testing-library/dom@npm:9.3.4" dependencies: "@babel/code-frame": ^7.10.4 "@babel/runtime": ^7.12.5 @@ -14553,7 +10788,7 @@ __metadata: dom-accessibility-api: ^0.5.9 lz-string: ^1.5.0 pretty-format: ^27.0.2 - checksum: c3bbd67503634fd955233dc172531640656701fe35ecb9a83f85e5965874b786452f5e7c26b4f8b3b4fc4379f3a80193c74425b57843ba191f4845e22b0ac483 + checksum: 147da340e8199d7f98f3a4ad8aa22ed55b914b83957efa5eb22bfea021a979ebe5a5182afa9c1e5b7a5f99a7f6744a5a4d9325ae46ec3b33b5a15aed8750d794 languageName: node linkType: hard @@ -14574,45 +10809,9 @@ __metadata: languageName: node linkType: hard -"@testing-library/react-hooks@npm:^8.0.1": - version: 8.0.1 - resolution: "@testing-library/react-hooks@npm:8.0.1" - dependencies: - "@babel/runtime": ^7.12.5 - react-error-boundary: ^3.1.0 - peerDependencies: - "@types/react": ^16.9.0 || ^17.0.0 - react: ^16.9.0 || ^17.0.0 - react-dom: ^16.9.0 || ^17.0.0 - react-test-renderer: ^16.9.0 || ^17.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - react-dom: - optional: true - react-test-renderer: - optional: true - checksum: 83bef2d4c437b84143213b5275ef00ef14e5bcd344f9ded12b162d253dc3c799138ead4428026b9c725e5a38dbebf611f2898aa43f3e43432bcaccbd7bf413e5 - languageName: node - linkType: hard - -"@testing-library/react@npm:^13.4.0": - version: 13.4.0 - resolution: "@testing-library/react@npm:13.4.0" - dependencies: - "@babel/runtime": ^7.12.5 - "@testing-library/dom": ^8.5.0 - "@types/react-dom": ^18.0.0 - peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - checksum: 371bf982dd0deb27da004f368b06904353eac0f23f9c08ff0f24443c3f51a6d647009e366034417565d2484c40f1c7eff74413738abf4ec55209da9bd3253b0e - languageName: node - linkType: hard - "@testing-library/react@npm:^14.0.0": - version: 14.0.0 - resolution: "@testing-library/react@npm:14.0.0" + version: 14.3.1 + resolution: "@testing-library/react@npm:14.3.1" dependencies: "@babel/runtime": ^7.12.5 "@testing-library/dom": ^9.0.0 @@ -14620,7 +10819,7 @@ __metadata: peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 81035913024faf18ba7e163418af517b2c3b85aef496fbd6334bda38f6f6dd4072678c6b76c41148b46b7fc846764f875e1156cbfc7643ffa1b62ee069d78951 + checksum: 1ccf4eb1510500cc20a805cb0244c9098dca28a8745173a8f71ea1274d63774f0b7898a35c878b43c797b89c13621548909ff37843b835c1a27ee1efbbdd098c languageName: node linkType: hard @@ -14636,11 +10835,11 @@ __metadata: linkType: hard "@testing-library/user-event@npm:^14.4.3": - version: 14.5.1 - resolution: "@testing-library/user-event@npm:14.5.1" + version: 14.5.2 + resolution: "@testing-library/user-event@npm:14.5.2" peerDependencies: "@testing-library/dom": ">=7.21.4" - checksum: 1e00d6ead23377885b906db6e46e259161a0efb4138f7527481d7435f3c8f65cb7e3eab2900e2ac1886fa6dd03416e773a3a60dea87a9a2086a7127dee315f6f + checksum: 68a0c2aa28a3c8e6eb05cafee29705438d7d8a9427423ce5064d44f19c29e89b5636de46dd2f28620fb10abba75c67130185bbc3aa23ac1163a227a5f36641e1 languageName: node linkType: hard @@ -14666,9 +10865,9 @@ __metadata: linkType: hard "@tsconfig/node10@npm:^1.0.7": - version: 1.0.9 - resolution: "@tsconfig/node10@npm:1.0.9" - checksum: c176a2c1e1b16be120c328300ea910df15fb9a5277010116d26818272341a11483c5a80059389d04edacf6fd2d03d4687ad3660870fdd1cc0b7109e160adb220 + version: 1.0.11 + resolution: "@tsconfig/node10@npm:1.0.11" + checksum: 28a0710e5d039e0de484bdf85fee883bfd3f6a8980601f4d44066b0a6bcd821d31c4e231d1117731c4e24268bd4cf2a788a6787c12fc7f8d11014c07d582783c languageName: node linkType: hard @@ -14701,39 +10900,13 @@ __metadata: linkType: hard "@types/aria-query@npm:^5.0.1": - version: 5.0.1 - resolution: "@types/aria-query@npm:5.0.1" - checksum: bc9e40ce37bd3a1654948778c7829bd55aea1bc5f2cd06fcf6cd650b07bb388995799e9aab6e2d93a6cf55dcba3b85c155f7ba93adefcc7c2e152fc6057061b5 + version: 5.0.4 + resolution: "@types/aria-query@npm:5.0.4" + checksum: dc667bc6a3acc7bba2bccf8c23d56cb1f2f4defaa704cfef595437107efaa972d3b3db9ec1d66bc2711bfc35086821edd32c302bffab36f2e79b97f312069f08 languageName: node linkType: hard -"@types/babel__core@npm:^7.0.0, @types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.1.7": - version: 7.20.1 - resolution: "@types/babel__core@npm:7.20.1" - dependencies: - "@babel/parser": ^7.20.7 - "@babel/types": ^7.20.7 - "@types/babel__generator": "*" - "@types/babel__template": "*" - "@types/babel__traverse": "*" - checksum: c83402fc7ef8abd1f94ffe350b8bde9a35ccb6c3624bc8e39b6a7e1a675d112f6b70ac1b05391a579ca3b126baffe66b0b94f954edef086c4482b97d293c3659 - languageName: node - linkType: hard - -"@types/babel__core@npm:^7.18.0, @types/babel__core@npm:^7.20.2": - version: 7.20.3 - resolution: "@types/babel__core@npm:7.20.3" - dependencies: - "@babel/parser": ^7.20.7 - "@babel/types": ^7.20.7 - "@types/babel__generator": "*" - "@types/babel__template": "*" - "@types/babel__traverse": "*" - checksum: 5b5f9de4df7f995c2f06f3fdad39b58bc30121d1f2daceb97dd423c9b5dcbd5c464959338824e0dbee0c758bf55c4e9fe46fafd13bd29c1834afad04f291c588 - languageName: node - linkType: hard - -"@types/babel__core@npm:^7.20.5": +"@types/babel__core@npm:^7.0.0, @types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.1.7, @types/babel__core@npm:^7.18.0, @types/babel__core@npm:^7.20.5": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" dependencies: @@ -14747,34 +10920,25 @@ __metadata: linkType: hard "@types/babel__generator@npm:*": - version: 7.6.4 - resolution: "@types/babel__generator@npm:7.6.4" + version: 7.6.8 + resolution: "@types/babel__generator@npm:7.6.8" dependencies: "@babel/types": ^7.0.0 - checksum: e0051b450e4ba2df0a7e386f08df902a4e920f6f8d6f185d69ddbe9b0e2e2d3ae434bb51e437bc0fca2a9a0f5dc4ca44d3a1941ef75e74371e8be5bf64416fe4 + checksum: f0ba105e7d2296bf367d6e055bb22996886c114261e2cb70bf9359556d0076c7a57239d019dee42bb063f565bade5ccb46009bce2044b2952d964bf9a454d6d2 languageName: node linkType: hard "@types/babel__template@npm:*": - version: 7.4.1 - resolution: "@types/babel__template@npm:7.4.1" + version: 7.4.4 + resolution: "@types/babel__template@npm:7.4.4" dependencies: "@babel/parser": ^7.1.0 "@babel/types": ^7.0.0 - checksum: 6f180e96c39765487f27e861d43eebed341ec7a2fc06cdf5a52c22872fae67f474ca165d149c708f4fd9d5482beb66c0a92f77411b234bb30262ed2303e50b1a + checksum: cc84f6c6ab1eab1427e90dd2b76ccee65ce940b778a9a67be2c8c39e1994e6f5bbc8efa309f6cea8dc6754994524cd4d2896558df76d92e7a1f46ecffee7112b languageName: node linkType: hard -"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.4, @types/babel__traverse@npm:^7.0.6": - version: 7.20.1 - resolution: "@types/babel__traverse@npm:7.20.1" - dependencies: - "@babel/types": ^7.20.7 - checksum: 5a6a3a26be090573309527184a31f1b82ef55f3d73d811c15f181d323e471305f2390651a04d49d4cd4ca41bbeabb53c9f7862a8e09eab5a0f8910a6aec6e867 - languageName: node - linkType: hard - -"@types/babel__traverse@npm:7.20.5": +"@types/babel__traverse@npm:*, @types/babel__traverse@npm:7.20.5, @types/babel__traverse@npm:^7.0.4, @types/babel__traverse@npm:^7.0.6, @types/babel__traverse@npm:^7.18.0": version: 7.20.5 resolution: "@types/babel__traverse@npm:7.20.5" dependencies: @@ -14783,22 +10947,13 @@ __metadata: languageName: node linkType: hard -"@types/babel__traverse@npm:^7.18.0": - version: 7.20.3 - resolution: "@types/babel__traverse@npm:7.20.3" - dependencies: - "@babel/types": ^7.20.7 - checksum: 295ed9b837e62e17ee43be0df45d90fff5208986bd43af593c9020d152d3b2c55328e038c2f8585926b63cc22f887f28bf3f4c805aa881e2dd0bdd5ead92ece0 - languageName: node - linkType: hard - "@types/body-parser@npm:*": - version: 1.19.2 - resolution: "@types/body-parser@npm:1.19.2" + version: 1.19.5 + resolution: "@types/body-parser@npm:1.19.5" dependencies: "@types/connect": "*" "@types/node": "*" - checksum: c2dd533e1d4af958d656bdba7f376df68437d8dfb7e4522c88b6f3e6f827549e4be5bf0be68a5f1878accf5752ea37fba7e8a4b6dda53d0d122d77e27b69c750 + checksum: aebeb200f25e8818d8cf39cd0209026750d77c9b85381cdd8deeb50913e4d18a1ebe4b74ca9b0b4d21952511eeaba5e9fbbf739b52731a2061e206ec60d568df languageName: node linkType: hard @@ -14815,18 +10970,18 @@ __metadata: linkType: hard "@types/chai-subset@npm:^1.3.3": - version: 1.3.4 - resolution: "@types/chai-subset@npm:1.3.4" + version: 1.3.5 + resolution: "@types/chai-subset@npm:1.3.5" dependencies: "@types/chai": "*" - checksum: 19c0240324ddec012a5f85480462adcbad5c653d32608d1eee2fdcdf81cb346ef5e295e8b5e6246e2bc6983cb22693dda6200f3261183faa21f96c09f2a0668a + checksum: d5cfb483917b0fdf245c8c51d1fa35a2c302295dfc5383ee4faa545db49a28ea169650bb1b75de2cd31f6f8e486a856d241acf9e0456fc93cb74ac18dfdfd19d languageName: node linkType: hard "@types/chai@npm:*, @types/chai@npm:^4.3.5": - version: 4.3.9 - resolution: "@types/chai@npm:4.3.9" - checksum: 3c20a208840dfc15df15c555074bec14d8be7ed2c825f139250f99f944cf8f75b47e9741877688be8baa68d41c197c44e72baebcaa808fe81ae1234264b5f86e + version: 4.3.16 + resolution: "@types/chai@npm:4.3.16" + checksum: 745d4a9be429d5d86a7ab26064610b8957fe12dd80e94dc7d0707cf3db1c889e3ffe0d73d69bb15e6d376bf4462a7a75e9d8fc1051750b5d656d6cfe459829b7 languageName: node linkType: hard @@ -14856,34 +11011,27 @@ __metadata: linkType: hard "@types/connect@npm:*": - version: 3.4.35 - resolution: "@types/connect@npm:3.4.35" + version: 3.4.38 + resolution: "@types/connect@npm:3.4.38" dependencies: "@types/node": "*" - checksum: f11a1ccfed540723dddd7cb496543ad40a2f663f22ff825e9b220f0bae86db8b1ced2184ee41d3fb358b019ad6519e39481b06386db91ebb859003ad1d54fe6a - languageName: node - linkType: hard - -"@types/cookie@npm:^0.4.1": - version: 0.4.1 - resolution: "@types/cookie@npm:0.4.1" - checksum: f96afe12bd51be1ec61410b0641243d93fa3a494702407c787a4c872b5c8bcd39b224471452055e44a9ce42af1a636e87d161994226eaf4c2be9c30f60418409 + checksum: 2e1cdba2c410f25649e77856505cd60223250fa12dff7a503e492208dbfdd25f62859918f28aba95315251fd1f5e1ffbfca1e25e73037189ab85dd3f8d0a148c languageName: node linkType: hard "@types/cross-spawn@npm:^6.0.2": - version: 6.0.4 - resolution: "@types/cross-spawn@npm:6.0.4" + version: 6.0.6 + resolution: "@types/cross-spawn@npm:6.0.6" dependencies: "@types/node": "*" - checksum: 33df54e348b634d27a80c0512ec6c7d85ddcff000f53e14b906ed86e307222e6fff4a39f894ff2eb5f3d4543105eb9ba1af138a96e4d30eb9c1a17130b936018 + checksum: e3d476bb6b3a54a8934a97fe6ee4bd13e2e5eb29073929a4be76a52466602ffaea420b20774ffe8503f9fa24f3ae34817e95e7f625689fb0d1c10404f5b2889c languageName: node linkType: hard "@types/detect-port@npm:^1.3.0": - version: 1.3.4 - resolution: "@types/detect-port@npm:1.3.4" - checksum: 2e584440c32c7a12ca3e196a7be7606bb5d7837834745ec50d7b0a86ef37338cd1eae41510ffcc85c758adfedb75d93a01330e9f88e4fe4b07f6232472350eb7 + version: 1.3.5 + resolution: "@types/detect-port@npm:1.3.5" + checksum: d8dd9d0e643106a2263f530b24ffdc3409d9391c50fc5e404018ba3633947aa3777db7fb094aeb0f49a13cc998aae8889747ad9edaa02b13a2de2385f37106ef languageName: node linkType: hard @@ -14894,24 +11042,24 @@ __metadata: languageName: node linkType: hard -"@types/doctrine@npm:^0.0.6": - version: 0.0.6 - resolution: "@types/doctrine@npm:0.0.6" - checksum: eae59a178be3b7989f3dd269cbe30fee9041a95ccb7ac963bbff3fcc82e7985c5002228afe23b7fad985f3eedf5257d36c7011bd8caafb087fcdcc6df1e52cb3 +"@types/doctrine@npm:^0.0.9": + version: 0.0.9 + resolution: "@types/doctrine@npm:0.0.9" + checksum: cdaca493f13c321cf0cacd1973efc0ae74569633145d9e6fc1128f32217a6968c33bea1f858275239fe90c98f3be57ec8f452b416a9ff48b8e8c1098b20fa51c languageName: node linkType: hard "@types/ejs@npm:^3.1.1": - version: 3.1.4 - resolution: "@types/ejs@npm:3.1.4" - checksum: d4ff1ff9bc185ca05e9001c1a8ced415e2c9e281a464735d6c4e70d9611622fe217a699a4a3869c7748a29df6d13dc413200f8a6d1a9020b0ce5cb7a539ce6bd + version: 3.1.5 + resolution: "@types/ejs@npm:3.1.5" + checksum: 13d994cf0323d7e0ad33b9384914ccd3b4cd8bf282eced3649b1621b66ee7c784ac2d120a9d7b1f43d6f873518248fb8c3221b06a649b847860b9c2389a0b0ed languageName: node linkType: hard "@types/emscripten@npm:^1.39.6": - version: 1.39.9 - resolution: "@types/emscripten@npm:1.39.9" - checksum: d11461453315f4ba382f304717c64e907b10646af0f9ec0f64f34d604a79d8d839b9227dc9b95311b247c86a3bb4a7b95f5c971ad4fe079296836ad2245a48fe + version: 1.39.11 + resolution: "@types/emscripten@npm:1.39.11" + checksum: 62c5d7ec204d7d6ba0d0c9672baca5c5194f33e56784b301065bd62b7f067f494871d5cb058f9c55a7c371345bc72bc577b0db2c7af192e3fb8f38992ba95a08 languageName: node linkType: hard @@ -14922,30 +11070,10 @@ __metadata: languageName: node linkType: hard -"@types/eslint-scope@npm:^3.7.3": - version: 3.7.4 - resolution: "@types/eslint-scope@npm:3.7.4" - dependencies: - "@types/eslint": "*" - "@types/estree": "*" - checksum: f8a19cddf9d402f079bcc261958fff5ff2616465e4fb4cd423aa966a6a32bf5d3c65ca3ca0fbe824776b48c5cd525efbaf927b98b8eeef093aa68a1a2ba19359 - languageName: node - linkType: hard - -"@types/eslint@npm:*": - version: 8.40.2 - resolution: "@types/eslint@npm:8.40.2" - dependencies: - "@types/estree": "*" - "@types/json-schema": "*" - checksum: 5797dce7805f601ee34b2f63d6a80dba21302e2fe2614c7990eca7a22472f9e0c386d56d82fe79a7cdede57c8dcc1e0f9b1e5dc384adf736833b901ffcc29628 - languageName: node - linkType: hard - -"@types/estree@npm:*, @types/estree@npm:^1.0.0": - version: 1.0.1 - resolution: "@types/estree@npm:1.0.1" - checksum: b4022067f834d86766f23074a1a7ac6c460e823b00cd8fe94c997bc491e7794615facd3e1520a934c42bd8c0689dbff81e5c643b01f1dee143fc758cac19669e +"@types/estree@npm:*, @types/estree@npm:1.0.5, @types/estree@npm:^1.0.0": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: b3b0e334288ddb407c7b3357ca67dbee75ee22db242ca7c56fe27db4e1a31989cb8af48a84dd401deb787fe10cc6b2ab1ee82dc4783be87ededbe3d53c79c70d languageName: node linkType: hard @@ -14964,38 +11092,26 @@ __metadata: linkType: hard "@types/express-serve-static-core@npm:^4.17.33": - version: 4.17.35 - resolution: "@types/express-serve-static-core@npm:4.17.35" + version: 4.19.0 + resolution: "@types/express-serve-static-core@npm:4.19.0" dependencies: "@types/node": "*" "@types/qs": "*" "@types/range-parser": "*" "@types/send": "*" - checksum: 08db6ffff07b5d53d852bb0a078ea5ee6dc3eb581d8c8fdf0d65f48c641db2830658074c797844e618b0933ce4ca2ddd08191f9d79b12eb2ec3d66f8551716ec + checksum: 38a13dfbb38d18526276e68dae1097eb0ebef296e76bff2a9bf6831c052c2f87797e910c87bd3f0dd1a1b4136241c9d7c841779a00b22576d12aa9b483a63349 languageName: node linkType: hard -"@types/express@npm:*, @types/express@npm:^4.17.17": - version: 4.17.17 - resolution: "@types/express@npm:4.17.17" +"@types/express@npm:*, @types/express@npm:^4.17.17, @types/express@npm:^4.7.0": + version: 4.17.21 + resolution: "@types/express@npm:4.17.21" dependencies: "@types/body-parser": "*" "@types/express-serve-static-core": ^4.17.33 "@types/qs": "*" "@types/serve-static": "*" - checksum: 5802a0a28f7473744dd6a118479440d8c5c801c973d34fb6f31b5ee645a41fee936193978a8e905d55deefda9b675d19924167bf11a31339874c3161a3fc2922 - languageName: node - linkType: hard - -"@types/express@npm:^4.7.0": - version: 4.17.20 - resolution: "@types/express@npm:4.17.20" - dependencies: - "@types/body-parser": "*" - "@types/express-serve-static-core": ^4.17.33 - "@types/qs": "*" - "@types/serve-static": "*" - checksum: f73f5f92bd0a0fa4697598be3122c89522caa9e3bcb14c28b5e6d58a8e47f0301027478997153ae9ee4cf3d432576fb3fb0918ea0db521cc1204f8b759828a32 + checksum: 12e562c4571da50c7d239e117e688dc434db1bac8be55613294762f84fd77fbd0658ccd553c7d3ab02408f385bc93980992369dd30e2ecd2c68c358e6af8fabf languageName: node linkType: hard @@ -15025,17 +11141,7 @@ __metadata: languageName: node linkType: hard -"@types/glob@npm:*": - version: 8.1.0 - resolution: "@types/glob@npm:8.1.0" - dependencies: - "@types/minimatch": ^5.1.2 - "@types/node": "*" - checksum: ded07aa0d7a1caf3c47b85e262be82989ccd7933b4a14712b79c82fd45a239249811d9fc3a135b3e9457afa163e74a297033d7245b0dc63cd3d032f3906b053f - languageName: node - linkType: hard - -"@types/glob@npm:^7.1.1, @types/glob@npm:^7.1.3": +"@types/glob@npm:^7.1.3": version: 7.2.0 resolution: "@types/glob@npm:7.2.0" dependencies: @@ -15046,27 +11152,11 @@ __metadata: linkType: hard "@types/graceful-fs@npm:^4.1.2, @types/graceful-fs@npm:^4.1.3": - version: 4.1.6 - resolution: "@types/graceful-fs@npm:4.1.6" + version: 4.1.9 + resolution: "@types/graceful-fs@npm:4.1.9" dependencies: "@types/node": "*" - checksum: b1d32c5ae7bd52cf60e29df20407904c4312a39612e7ec2ee23c1e3731c1cfe31d97c6941bf6cb52f5f929d50d86d92dd506436b63fafa833181d439b628885e - languageName: node - linkType: hard - -"@types/hast@npm:^2.0.0": - version: 2.3.4 - resolution: "@types/hast@npm:2.3.4" - dependencies: - "@types/unist": "*" - checksum: 635cfe9a8e91f6b3c15c9929455d0136ac4d75c5b7f596ce21b453cecdfda785e89b10eb2b2d9da9d43e548b1d65ba3e20c741bbaf83823575c9c45001ade4bb - languageName: node - linkType: hard - -"@types/html-minifier-terser@npm:^5.0.0": - version: 5.1.2 - resolution: "@types/html-minifier-terser@npm:5.1.2" - checksum: 13276ac71fbcc89795627cc7fa0234e95402656285df2bda4df83e3ebaa9b30f29905f52aa7786d158a887cef72748cbd897e12628dc396ba1225ce0d18159b9 + checksum: 235d2fc69741448e853333b7c3d1180a966dd2b8972c8cbcd6b2a0c6cd7f8d582ab2b8e58219dbc62cce8f1b40aa317ff78ea2201cdd8249da5025adebed6f0b languageName: node linkType: hard @@ -15078,19 +11168,9 @@ __metadata: linkType: hard "@types/http-errors@npm:*": - version: 2.0.1 - resolution: "@types/http-errors@npm:2.0.1" - checksum: 3bbc8c84fb02b381737e2eec563b434121384b1aef4e070edec4479a1bc74f27373edc09162680cd3ea1035ef8e5ab6d606bd7c99e3855c424045fb74376cb66 - languageName: node - linkType: hard - -"@types/inquirer@npm:^7.3.3": - version: 7.3.3 - resolution: "@types/inquirer@npm:7.3.3" - dependencies: - "@types/through": "*" - rxjs: ^6.4.0 - checksum: f79a333a1b2f08f5c16da88e2a0afbad95ba24e9cadddec069947489836aeae59f7ea8c9484979c71c2adc475bba57d6763e461f3355720d0836ca152f7f2ca4 + version: 2.0.4 + resolution: "@types/http-errors@npm:2.0.4" + checksum: 494670a57ad4062fee6c575047ad5782506dd35a6b9ed3894cea65830a94367bd84ba302eb3dde331871f6d70ca287bfedb1b2cf658e6132cd2cbd427ab56836 languageName: node linkType: hard @@ -15113,35 +11193,19 @@ __metadata: languageName: node linkType: hard -"@types/is-ci@npm:^3.0.0": - version: 3.0.0 - resolution: "@types/is-ci@npm:3.0.0" - dependencies: - ci-info: ^3.1.0 - checksum: da9eb9d61b70a4de96485c6b8962124b2ad77f374c672d9ba2656cfa2a0c7ef9b8514e5cc45920adf4b691d40ccd9916753b5ddb1c2acbbb422846bf90a0bcb8 - languageName: node - linkType: hard - -"@types/is-function@npm:^1.0.0": - version: 1.0.1 - resolution: "@types/is-function@npm:1.0.1" - checksum: 3bd8cf70ef103141bf6bb0404bca6887766615bb655f967a0e46cf301e277b59eaeab8b91ce117331ce5c7c8875050796d06c25bf3da4531e3a4514269373c3c - languageName: node - linkType: hard - "@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": - version: 2.0.4 - resolution: "@types/istanbul-lib-coverage@npm:2.0.4" - checksum: af5f6b64e788331ed3f7b2e2613cb6ca659c58b8500be94bbda8c995ad3da9216c006f1cfe6f66b321c39392b1bda18b16e63cef090a77d24a00b4bd5ba3b018 + version: 2.0.6 + resolution: "@types/istanbul-lib-coverage@npm:2.0.6" + checksum: 3948088654f3eeb45363f1db158354fb013b362dba2a5c2c18c559484d5eb9f6fd85b23d66c0a7c2fcfab7308d0a585b14dadaca6cc8bf89ebfdc7f8f5102fb7 languageName: node linkType: hard "@types/istanbul-lib-report@npm:*": - version: 3.0.0 - resolution: "@types/istanbul-lib-report@npm:3.0.0" + version: 3.0.3 + resolution: "@types/istanbul-lib-report@npm:3.0.3" dependencies: "@types/istanbul-lib-coverage": "*" - checksum: 7ced458631276a28082ee40645224c3cdd8b861961039ff811d841069171c987ec7e50bc221845ec0d04df0022b2f457a21fb2f816dab2fbe64d59377b32031f + checksum: 247e477bbc1a77248f3c6de5dadaae85ff86ac2d76c5fc6ab1776f54512a745ff2a5f791d22b942e3990ddbd40f3ef5289317c4fca5741bedfaa4f01df89051c languageName: node linkType: hard @@ -15156,21 +11220,21 @@ __metadata: linkType: hard "@types/istanbul-reports@npm:^3.0.0": - version: 3.0.1 - resolution: "@types/istanbul-reports@npm:3.0.1" + version: 3.0.4 + resolution: "@types/istanbul-reports@npm:3.0.4" dependencies: "@types/istanbul-lib-report": "*" - checksum: e147f0db9346a0cae9a359220bc76f7c78509fb6979a2597feb24d64b6e8328d2d26f9d152abbd59c6bca721e4ea2530af20116d01df50815efafd1e151fd777 + checksum: 1647fd402aced5b6edac87274af14ebd6b3a85447ef9ad11853a70fd92a98d35f81a5d3ea9fcb5dbb5834e800c6e35b64475e33fcae6bfa9acc70d61497c54ee languageName: node linkType: hard "@types/jest@npm:*": - version: 29.5.6 - resolution: "@types/jest@npm:29.5.6" + version: 29.5.12 + resolution: "@types/jest@npm:29.5.12" dependencies: expect: ^29.0.0 pretty-format: ^29.0.0 - checksum: 316463d2755677c42db5b6d5189794b8bbcf281c79f60cc936b5daa049cb2dc6339a6e343941b3c995ef29778c1c84b2a4f32f10a119ece418c47a3febfb2051 + checksum: 25fc8e4c611fa6c4421e631432e9f0a6865a8cb07c9815ec9ac90d630271cad773b2ee5fe08066f7b95bebd18bb967f8ce05d018ee9ab0430f9dfd1d84665b6f languageName: node linkType: hard @@ -15184,23 +11248,6 @@ __metadata: languageName: node linkType: hard -"@types/jest@npm:^27.0.3": - version: 27.5.2 - resolution: "@types/jest@npm:27.5.2" - dependencies: - jest-matcher-utils: ^27.0.0 - pretty-format: ^27.0.0 - checksum: 29ef3da9b94a15736a67fc13956f385ac2ba2c6297f50d550446842c278f2e0d9f343dcd8e31c321ada5d8a1bd67bc1d79c7b6ff1802d55508c692123b3d9794 - languageName: node - linkType: hard - -"@types/js-levenshtein@npm:^1.1.0": - version: 1.1.1 - resolution: "@types/js-levenshtein@npm:1.1.1" - checksum: 23d021eb3c976e0a6648dbf2fc104cafd7f417b04aa22de24e3d26479d6295660e3f4cfdb93073924830297b8191ec64d86881c55b08c6d7a9798fde41d2a767 - languageName: node - linkType: hard - "@types/js-yaml@npm:^4.0.9": version: 4.0.9 resolution: "@types/js-yaml@npm:4.0.9" @@ -15220,24 +11267,17 @@ __metadata: linkType: hard "@types/jsdom@npm:^21.1.1": - version: 21.1.4 - resolution: "@types/jsdom@npm:21.1.4" + version: 21.1.6 + resolution: "@types/jsdom@npm:21.1.6" dependencies: "@types/node": "*" "@types/tough-cookie": "*" parse5: ^7.0.0 - checksum: 011343281cd771f5758f2569a18a557dc5c0ccd580e0cc6b5ed690342ca6eccfa4a5bf17cb875b0bc1ff3ea262f0c148552f2d6188460b9d45e79f001995b30e + checksum: 6ae8f84c6e7b8e1c303b8bc271bc51ad21399bbfec93fdc3b168af8aa9cafb41ebb00eed99753fbb1943e4fc5006aa39e34251dee4d116d55f731cebc0f02e64 languageName: node linkType: hard -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.6, @types/json-schema@npm:^7.0.7, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": - version: 7.0.12 - resolution: "@types/json-schema@npm:7.0.12" - checksum: 2c39946ae321fe42d085c61a85872a81bbee70f9b2054ad344e8811dfc478fdbaf1ebf5f2989bb87c895ba2dfc3b1dcba85db11e467bbcdc023708814207791c - languageName: node - linkType: hard - -"@types/json-schema@npm:^7.0.12": +"@types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.6, @types/json-schema@npm:^7.0.7, @types/json-schema@npm:^7.0.9": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" checksum: a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db @@ -15245,11 +11285,11 @@ __metadata: linkType: hard "@types/jsonfile@npm:*": - version: 6.1.3 - resolution: "@types/jsonfile@npm:6.1.3" + version: 6.1.4 + resolution: "@types/jsonfile@npm:6.1.4" dependencies: "@types/node": "*" - checksum: 2f974e33d2e2aa3e8b04af77ece343c980d495a5ad3318d302a6aa8ba221806096f664353d0f70f1f83007831f15a3a1d3c8d48cd4039efb0880b02865d01175 + checksum: b12d068b021e4078f6ac4441353965769be87acf15326173e2aea9f3bf8ead41bd0ad29421df5bbeb0123ec3fc02eb0a734481d52903704a1454a1845896b9eb languageName: node linkType: hard @@ -15272,50 +11312,34 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.167, @types/lodash@npm:^4.14.191": - version: 4.14.195 - resolution: "@types/lodash@npm:4.14.195" - checksum: 6d733276df592614a0943a0053056140398b3c263cdf2557d4301b3a47b07ff561926cb9339a4725acbc7d8766f91ded218df11e0a4288cee369eafb5141d94d - languageName: node - linkType: hard - -"@types/mdast@npm:^3.0.0": - version: 3.0.11 - resolution: "@types/mdast@npm:3.0.11" - dependencies: - "@types/unist": "*" - checksum: 569ec32ac16deb42f2c9e7cdbfb5be0f67d2407036b49ba9cfa07ad0258b044c259922acba170eaed165ebcf5eb168032fbb4b3e35023fe8c581fe46e9bcbad0 + version: 4.17.1 + resolution: "@types/lodash@npm:4.17.1" + checksum: af2ad8a3c8d7deb170a7ec6e18afc5ae8980576e5f7fe798d8a95a1df7222c15bdf967a25a35879f575a3b64743de00145710ee461a0051e055e94e4fe253f45 languageName: node linkType: hard "@types/mdx@npm:^2.0.0": - version: 2.0.9 - resolution: "@types/mdx@npm:2.0.9" - checksum: b6afd7adf039d64aaacd49f445dee4e5eba70a6199cc29df5d798c6704347bcd7c87868e59ec2614dd64127f74fad572c01d4e72ea08e7d23aa8f909fefafb87 + version: 2.0.13 + resolution: "@types/mdx@npm:2.0.13" + checksum: 5edf1099505ac568da55f9ae8a93e7e314e8cbc13d3445d0be61b75941226b005e1390d9b95caecf5dcb00c9d1bab2f1f60f6ff9876dc091a48b547495007720 languageName: node linkType: hard "@types/mime-types@npm:^2.1.0": - version: 2.1.3 - resolution: "@types/mime-types@npm:2.1.3" - checksum: d728d69f89e15497aa2edbb7622f3d53d3a45b9daa8a3eb581dbb3352550b72cfe7c69d52531bda31e21906bfa0223a31a02c2150fb8666db237f66759f2d5f3 - languageName: node - linkType: hard - -"@types/mime@npm:*": - version: 3.0.1 - resolution: "@types/mime@npm:3.0.1" - checksum: c4c0fc89042822a3b5ffd6ef0da7006513454ee8376ffa492372d17d2925a4e4b1b194c977b718c711df38b33eb9d06deb5dbf9f851bcfb7e5e65f06b2a87f97 + version: 2.1.4 + resolution: "@types/mime-types@npm:2.1.4" + checksum: a10d57881d14a053556b3d09292de467968d965b0a06d06732c748da39b3aa569270b5b9f32529fd0e9ac1e5f3b91abb894f5b1996373254a65cb87903c86622 languageName: node linkType: hard "@types/mime@npm:^1": - version: 1.3.2 - resolution: "@types/mime@npm:1.3.2" - checksum: 61d144e5170c6cdf6de334ec0ee4bb499b1a0fb0233834a9e8cec6d289b0e3042bedf35cbc1c995d71a247635770dae3f13a9ddae69098bb54b933429bc08d35 + version: 1.3.5 + resolution: "@types/mime@npm:1.3.5" + checksum: c2ee31cd9b993804df33a694d5aa3fa536511a49f2e06eeab0b484fef59b4483777dbb9e42a4198a0809ffbf698081fdbca1e5c2218b82b91603dfab10a10fbc languageName: node linkType: hard -"@types/minimatch@npm:*, @types/minimatch@npm:^5.1.2": +"@types/minimatch@npm:*": version: 5.1.2 resolution: "@types/minimatch@npm:5.1.2" checksum: 83cf1c11748891b714e129de0585af4c55dd4c2cafb1f1d5233d79246e5e1e19d1b5ad9e8db449667b3ffa2b6c80125c429dbee1054e9efb45758dbc4e118562 @@ -15323,18 +11347,18 @@ __metadata: linkType: hard "@types/minimist@npm:^1.2.0": - version: 1.2.2 - resolution: "@types/minimist@npm:1.2.2" - checksum: f220f57f682bbc3793dab4518f8e2180faa79d8e2589c79614fd777d7182be203ba399020c3a056a115064f5d57a065004a32b522b2737246407621681b24137 + version: 1.2.5 + resolution: "@types/minimist@npm:1.2.5" + checksum: 3f791258d8e99a1d7d0ca2bda1ca6ea5a94e5e7b8fc6cde84dd79b0552da6fb68ade750f0e17718f6587783c24254bbca0357648dd59dc3812c150305cabdc46 languageName: node linkType: hard "@types/multer@npm:^1.4.7": - version: 1.4.7 - resolution: "@types/multer@npm:1.4.7" + version: 1.4.11 + resolution: "@types/multer@npm:1.4.11" dependencies: "@types/express": "*" - checksum: 0bb0dfc399ef8f4e298eda88ef44ca7e5d2ec5c406ebb79424f88ba556fe26f46b4813b6d3f9c1e4adafc70fdcf89962eb5a0b8bfd726893ad9ece3e96f4f445 + checksum: ace8e9f5ac7d2d7f6e0c35b790504f582a2f82a84cc06a7b90315527599b95256595bc0bb5bba60220c20a558554f0c21b96b94848b885987ab69512a3a9865e languageName: node linkType: hard @@ -15355,30 +11379,22 @@ __metadata: languageName: node linkType: hard -"@types/node-fetch@npm:^2.5.7": - version: 2.6.4 - resolution: "@types/node-fetch@npm:2.6.4" - dependencies: - "@types/node": "*" - form-data: ^3.0.0 - checksum: e43e4670ed8b7693dbf660ac1450b14fcfcdd8efca1eb0f501b6ad95af2d1fa06f8541db03e9511e82a5fee510a238fe0913330c9a58f8ac6892b985f6dd993e - languageName: node - linkType: hard - "@types/node-fetch@npm:^2.6.4": - version: 2.6.7 - resolution: "@types/node-fetch@npm:2.6.7" + version: 2.6.11 + resolution: "@types/node-fetch@npm:2.6.11" dependencies: "@types/node": "*" form-data: ^4.0.0 - checksum: 83dc3170a5951f7a4e83547b6f617ec219580fd85d693c3e1e11fcbe84058c82f20beeda7d19441cd42af7ef8d5a8fac802fe1fae369fd8fa1832509248d0aea + checksum: 5283d4e0bcc37a5b6d8e629aee880a4ffcfb33e089f4b903b2981b19c623972d1e64af7c3f9540ab990f0f5c89b9b5dda19c5bcb37a8e177079e93683bfd2f49 languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:>=8.1.0": - version: 20.3.3 - resolution: "@types/node@npm:20.3.3" - checksum: d172311e9e2d42e060eacb78ecdfd4e1596dbd1e54939bacf42003c84559bdcb5d7dbe539dc5262db4c8f408e21f3abd65435fec9bc0ff8968a3b32dafde0bbf +"@types/node@npm:*, @types/node@npm:>=8.1.0, @types/node@npm:^20.10.4, @types/node@npm:^20.11.15": + version: 20.12.10 + resolution: "@types/node@npm:20.12.10" + dependencies: + undici-types: ~5.26.4 + checksum: 2cc3b6ea09894ed1a3cf39f6491ec539281580f4ff83216e7d26ce85c83237fe0543c0ca49e25b2515ccdb6c8814b488d17a64a05f536dcaea94f9d32a60c7d7 languageName: node linkType: hard @@ -15396,13 +11412,6 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^14.0.10 || ^16.0.0, @types/node@npm:^14.14.20 || ^16.0.0": - version: 16.18.38 - resolution: "@types/node@npm:16.18.38" - checksum: 02631f1cfe0c111024e4bf0909c3bfc7476e65e03cb32dc48b2f71f000590b244d239b349b91a6b03667c33f31fbd3200c8fc5838623fcaadce3e92d60efee1a - languageName: node - linkType: hard - "@types/node@npm:^17.0.36": version: 17.0.45 resolution: "@types/node@npm:17.0.45" @@ -15411,71 +11420,41 @@ __metadata: linkType: hard "@types/node@npm:^18.0.0": - version: 18.18.6 - resolution: "@types/node@npm:18.18.6" - checksum: 50312053b0906058aa026e1c85c9125b4f0e8d6ae5e3699fb5bc8e0d5b9d1c2b12303902b2b91477c389f15ad40235d240b882819dd93a49bd6b46983f63be1c - languageName: node - linkType: hard - -"@types/node@npm:^20.10.4": - version: 20.10.6 - resolution: "@types/node@npm:20.10.6" + version: 18.19.32 + resolution: "@types/node@npm:18.19.32" dependencies: undici-types: ~5.26.4 - checksum: 6692ccfa8552ef60c4069fda3c8de726c23e8d403cdf788e3c7efa769987e80fbda5f02723dd857f9de7df24a5fa40b3ed4580ec3c5cbac04eba44cf7b2ab1dc - languageName: node - linkType: hard - -"@types/node@npm:^20.11.15": - version: 20.11.15 - resolution: "@types/node@npm:20.11.15" - dependencies: - undici-types: ~5.26.4 - checksum: 7dfab4208fedc02e9584c619551906f46ade7955bb929b1e32e354a50522eb532d6bfb2844fdaad2c8dca03be84a590674460c64cb101e1a33bb318e1ec448d4 + checksum: 29d60ddd83a8216daf90d4bf101a6eff7fcf034b24bb89da90291017ec54c33b5ce30e7c125aef3f23f756037f0c382d15ebd434ad9c4536c8db8f1fb129f0ce languageName: node linkType: hard "@types/normalize-package-data@npm:^2.4.0": - version: 2.4.1 - resolution: "@types/normalize-package-data@npm:2.4.1" - checksum: c90b163741f27a1a4c3b1869d7d5c272adbd355eb50d5f060f9ce122ce4342cf35f5b0005f55ef780596cacfeb69b7eee54cd3c2e02d37f75e664945b6e75fc6 - languageName: node - linkType: hard - -"@types/npmlog@npm:^4.1.2": - version: 4.1.4 - resolution: "@types/npmlog@npm:4.1.4" - checksum: 5670c38db51f2c4a5da05657920d7597bf9da00615920b42a001fde9011f05ab1e8ec8cbc671abb47915028e3e0ace5c3d981c23684c202a00bf518f16ece01d + version: 2.4.4 + resolution: "@types/normalize-package-data@npm:2.4.4" + checksum: aef7bb9b015883d6f4119c423dd28c4bdc17b0e8a0ccf112c78b4fe0e91fbc4af7c6204b04bba0e199a57d2f3fbbd5b4a14bf8739bf9d2a39b2a0aad545e0f86 languageName: node linkType: hard "@types/object-path@npm:^0.11.1": - version: 0.11.3 - resolution: "@types/object-path@npm:0.11.3" - checksum: 7512efbd1687bbfa3e0e19acaa821008c311b46b049266c040a628e64e4e3b0c1525f48cb52edbc5967fc7732a681f9a17476ba3bcdf5faff11768d8cbd23af5 + version: 0.11.4 + resolution: "@types/object-path@npm:0.11.4" + checksum: fb7f71b170013cf23d323782f12d25e8fa3e2d4048ee3d4d71ca7fe9c553ceeaaa720560bae9925a1c6b893f6d02bbaefad6d68be52c0bd6b136722a5baba77d languageName: node linkType: hard "@types/papaparse@npm:^5.3.7": - version: 5.3.7 - resolution: "@types/papaparse@npm:5.3.7" + version: 5.3.14 + resolution: "@types/papaparse@npm:5.3.14" dependencies: "@types/node": "*" - checksum: fd234e7872aa7ed86c539583e7b4bac387f3efe55c5f403c590712e7125dfe73f7f0a84e646d5d222bf7e36b4c6213a85a0ae4406db9006a5b9a1b6bc03b6e50 + checksum: feb4d215903b67442feaa9836a6a5771e78dc6a9da24781e399c6f891622fa82245cd783ab2613c5be43e4a2d6a94da52325538e4485af258166864576ecd0d8 languageName: node linkType: hard "@types/parse-json@npm:^4.0.0": - version: 4.0.0 - resolution: "@types/parse-json@npm:4.0.0" - checksum: 1d3012ab2fcdad1ba313e1d065b737578f6506c8958e2a7a5bdbdef517c7e930796cb1599ee067d5dee942fb3a764df64b5eef7e9ae98548d776e86dcffba985 - languageName: node - linkType: hard - -"@types/parse5@npm:^5.0.0": - version: 5.0.3 - resolution: "@types/parse5@npm:5.0.3" - checksum: 7d7ebbcb704a0ef438aa0de43ea1fd9723dfa802b8fa459628ceaf063f092bd19791b2a2580265244898dcc9d40f7345588a76cf752847d29540539f802711ed + version: 4.0.2 + resolution: "@types/parse-json@npm:4.0.2" + checksum: b1b863ac34a2c2172fbe0807a1ec4d5cb684e48d422d15ec95980b81475fac4fdb3768a8b13eef39130203a7c04340fc167bae057c7ebcafd7dec9fe6c36aeb1 languageName: node linkType: hard @@ -15512,27 +11491,34 @@ __metadata: linkType: hard "@types/pretty-hrtime@npm:^1.0.0": - version: 1.0.1 - resolution: "@types/pretty-hrtime@npm:1.0.1" - checksum: e990110a3626e987319092c5149d5ea244785b83fbbd8e62605714ec1fa4317a3524ae0b6381cdc2ca92619d9a451b3fe9ff4085c42826f5398e3380d3031bff + version: 1.0.3 + resolution: "@types/pretty-hrtime@npm:1.0.3" + checksum: e4c22475c588be982b398dee9ac0b05b21078bc26581819290a4901c5b269bcaa04cae0e61e012d412e811b0897c9dab316db064208914df2f0ed0960fc5306b languageName: node linkType: hard "@types/prismjs@npm:^1.26.0": - version: 1.26.0 - resolution: "@types/prismjs@npm:1.26.0" - checksum: dce1388a626c20b95fa2715917deef5a401eec33e9e181f202840ee3b3c7d8a84d5558c834af4c29b8e007741a6a18639b074db8ecccdd6e7de15280fc4dfdd2 + version: 1.26.3 + resolution: "@types/prismjs@npm:1.26.3" + checksum: 3e8a64bcf0ab5f9a47ec2590938c5a8a20ac849b4949a95ed96e73e64cb890fc56e9c9b724286914717458267b28405f965709e1b9f80db5d68817a7ce5a18a9 languageName: node linkType: hard "@types/prop-types@npm:*": - version: 15.7.5 - resolution: "@types/prop-types@npm:15.7.5" - checksum: 648aae41423821c61c83823ae36116c8d0f68258f8b609bdbc257752dcd616438d6343d554262aa9a7edaee5a19aca2e028a74fa2d0f40fffaf2816bc7056857 + version: 15.7.12 + resolution: "@types/prop-types@npm:15.7.12" + checksum: 1babcc7db6a1177779f8fde0ccc78d64d459906e6ef69a4ed4dd6339c920c2e05b074ee5a92120fe4e9d9f1a01c952f843ebd550bee2332fc2ef81d1706878f8 languageName: node linkType: hard -"@types/qs@npm:*, @types/qs@npm:6.9.7, @types/qs@npm:^6.9.5": +"@types/qs@npm:*, @types/qs@npm:^6.9.5": + version: 6.9.15 + resolution: "@types/qs@npm:6.9.15" + checksum: 49c5ff75ca3adb18a1939310042d273c9fc55920861bd8e5100c8a923b3cda90d759e1a95e18334092da1c8f7b820084687770c83a1ccef04fb2c6908117c823 + languageName: node + linkType: hard + +"@types/qs@npm:6.9.7": version: 6.9.7 resolution: "@types/qs@npm:6.9.7" checksum: 157eb05f4c75790b0ebdcf7b0547ff117feabc8cda03c3cac3d3ea82bb19a1912e76a411df3eb0bdd01026a9770f07bc0e7e3fbe39ebb31c1be4564c16be35f1 @@ -15540,40 +11526,13 @@ __metadata: linkType: hard "@types/range-parser@npm:*": - version: 1.2.4 - resolution: "@types/range-parser@npm:1.2.4" - checksum: 8e3c3cda88675efd9145241bcb454449715b7d015a7fb80d018dcb3d441fa1938b302242cc0dfa6b02c5d014dd8bc082ae90091e62b1e816cae3ec36c2a7dbcb + version: 1.2.7 + resolution: "@types/range-parser@npm:1.2.7" + checksum: 361bb3e964ec5133fa40644a0b942279ed5df1949f21321d77de79f48b728d39253e5ce0408c9c17e4e0fd95ca7899da36841686393b9f7a1e209916e9381a3c languageName: node linkType: hard -"@types/react-dom@npm:^17.0.18": - version: 17.0.20 - resolution: "@types/react-dom@npm:17.0.20" - dependencies: - "@types/react": ^17 - checksum: 1389bfd96ec5f0c580bb1c237c8af137203de912cf403b4116cdfb026762bf31b4206cc1de0a5c20d0df2e07b0ba1b1b72ac51995d5ef45889d5d878321b7418 - languageName: node - linkType: hard - -"@types/react-dom@npm:^18.0.0": - version: 18.2.6 - resolution: "@types/react-dom@npm:18.2.6" - dependencies: - "@types/react": "*" - checksum: bd734ca04c52b3c96891a7f9c1139486807dac7a2449fb72e8f8e23018bc6eeeb87a490a105cb39d05ccb7ddf80ed7a441e5bd3e5866c6f6ae8870cd723599e8 - languageName: node - linkType: hard - -"@types/react-dom@npm:^18.2.0, @types/react-dom@npm:^18.2.6": - version: 18.2.14 - resolution: "@types/react-dom@npm:18.2.14" - dependencies: - "@types/react": "*" - checksum: 1f79a7708d038cd651bdb21e01a99c594761bc9a40a565abe98958e1d27facfeb6e9824ddf6ae3504e7a56568f0f3da2380fe52ac18477b5864d2d5cf1386a9e - languageName: node - linkType: hard - -"@types/react-dom@npm:^18.2.25": +"@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.2.0, @types/react-dom@npm:^18.2.25, @types/react-dom@npm:^18.2.6": version: 18.3.0 resolution: "@types/react-dom@npm:18.3.0" dependencies: @@ -15582,46 +11541,13 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*": - version: 18.2.14 - resolution: "@types/react@npm:18.2.14" - dependencies: - "@types/prop-types": "*" - "@types/scheduler": "*" - csstype: ^3.0.2 - checksum: a728a90e242fb41c233729fa46885cc47aca7df2035ed803f83bf0b582dde81143d465ecbf04a056bc6404f0f746f219d7043245ebd99baf83a178bbbb856c76 - languageName: node - linkType: hard - -"@types/react@npm:>=16, @types/react@npm:^18.2.0, @types/react@npm:^18.2.14": - version: 18.2.31 - resolution: "@types/react@npm:18.2.31" - dependencies: - "@types/prop-types": "*" - "@types/scheduler": "*" - csstype: ^3.0.2 - checksum: d2793873aef68038e0dc3ee05a573c663fcd3ba7402f1134a633df25aaeb72fd397479d5a5f02e9edc8cd5d000479a73f7bdc64cf00c50fb022c883f22e1fd0f - languageName: node - linkType: hard - -"@types/react@npm:^17, @types/react@npm:^17.0.53": - version: 17.0.62 - resolution: "@types/react@npm:17.0.62" - dependencies: - "@types/prop-types": "*" - "@types/scheduler": "*" - csstype: ^3.0.2 - checksum: 88046d4b11246a71baf06d82dbe877a48e691b513e25f71f3a7ec7cbbd93ffeb64e2eb535f8e86791556fe2c523d9ba560764995c8e707750909a72fc3acdff2 - languageName: node - linkType: hard - -"@types/react@npm:^18.2.79": - version: 18.2.79 - resolution: "@types/react@npm:18.2.79" +"@types/react@npm:*, @types/react@npm:>=16, @types/react@npm:^18.2.0, @types/react@npm:^18.2.14, @types/react@npm:^18.2.79": + version: 18.3.1 + resolution: "@types/react@npm:18.3.1" dependencies: "@types/prop-types": "*" csstype: ^3.0.2 - checksum: c8a8a005d8830a48cc1ef93c3510c4935a2a03e5557dbecaa8f1038450cbfcb18eb206fa7fba7077d54b8da21faeb25577e897a333392770a7797f625b62c78a + checksum: 18d856c12a4ec93f3cda2d58ef3d77a9480818afd3af895f812896fb82cfca1f35a692ab1add4ce826a4eb58a071624c7d1c8c6c4ccfb81c100d2916dc607614 languageName: node linkType: hard @@ -15642,9 +11568,9 @@ __metadata: linkType: hard "@types/resolve@npm:^1.20.2": - version: 1.20.4 - resolution: "@types/resolve@npm:1.20.4" - checksum: 662d3d9c1a9bd277a5289f8530ee869e4f3f5db17024f41fd90c631942a89e0cc6c5dab447fbc024d29c173b3f165dfa9be28747596e6668824a1ef81f994e04 + version: 1.20.6 + resolution: "@types/resolve@npm:1.20.6" + checksum: a9b0549d816ff2c353077365d865a33655a141d066d0f5a3ba6fd4b28bc2f4188a510079f7c1f715b3e7af505a27374adce2a5140a3ece2a059aab3d6e1a4244 languageName: node linkType: hard @@ -15657,61 +11583,31 @@ __metadata: languageName: node linkType: hard -"@types/scheduler@npm:*": - version: 0.16.3 - resolution: "@types/scheduler@npm:0.16.3" - checksum: c249d4b96fa05165ac22c214f94a045ee0af8beedefdbc54b769febd0044cab3a874e55419841a0dcc76439e379a63e257f3253c87168e3261e7bc783d623302 - languageName: node - linkType: hard - -"@types/semver@npm:^7.3.12, @types/semver@npm:^7.5.0": - version: 7.5.0 - resolution: "@types/semver@npm:7.5.0" - checksum: ca4ba4642b5972b6e88e73c5bc02bbaceb8d76bce71748d86e3e95042d4e5a44603113a1dcd2cb9b73ad6f91f6e4ab73185eb41bbfc9c73b11f0ed3db3b7443a - languageName: node - linkType: hard - -"@types/semver@npm:^7.3.4": - version: 7.5.4 - resolution: "@types/semver@npm:7.5.4" - checksum: dee66a71d9f089c118be74b5937d4fef42864d68d9472a3f4f5399b9e3ad74d56a8e155020c846667b9ecf9de78fdb9ea55a53fff5067af28e06779b282b6c40 +"@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.4, @types/semver@npm:^7.5.0": + version: 7.5.8 + resolution: "@types/semver@npm:7.5.8" + checksum: 8663ff927234d1c5fcc04b33062cb2b9fcfbe0f5f351ed26c4d1e1581657deebd506b41ff7fdf89e787e3d33ce05854bc01686379b89e9c49b564c4cfa988efa languageName: node linkType: hard "@types/send@npm:*": - version: 0.17.1 - resolution: "@types/send@npm:0.17.1" + version: 0.17.4 + resolution: "@types/send@npm:0.17.4" dependencies: "@types/mime": ^1 "@types/node": "*" - checksum: 1aad6bfafdaa3a3cadad1b441843dfd166821c0e93513daabe979de85b552a1298cfb6f07d40f80b5ecf14a3194dc148deb138605039841f1dadc7132c73e634 + checksum: 7f17fa696cb83be0a104b04b424fdedc7eaba1c9a34b06027239aba513b398a0e2b7279778af521f516a397ced417c96960e5f50fcfce40c4bc4509fb1a5883c languageName: node linkType: hard "@types/serve-static@npm:*": - version: 1.15.2 - resolution: "@types/serve-static@npm:1.15.2" + version: 1.15.7 + resolution: "@types/serve-static@npm:1.15.7" dependencies: "@types/http-errors": "*" - "@types/mime": "*" "@types/node": "*" - checksum: 5e7b3e17b376f8910d5c9a0b1def38d7841c8939713940098f1b80a330d5caa9cfe9b632c122252cd70165052439e18fafa46635dc55b1d6058343901eec22eb - languageName: node - linkType: hard - -"@types/set-cookie-parser@npm:^2.4.0": - version: 2.4.2 - resolution: "@types/set-cookie-parser@npm:2.4.2" - dependencies: - "@types/node": "*" - checksum: 71a668ebd353deed2c0fccac7505c29e4b6b1cabde91ce9a1b2a9956dd8c91f82fd6b730dcb726a43e3a511c912b1f64e2f2dea32c4fec7b5ed7f950e6ea9a6d - languageName: node - linkType: hard - -"@types/source-list-map@npm:*": - version: 0.1.2 - resolution: "@types/source-list-map@npm:0.1.2" - checksum: 0538ce317294febf40ed3fc3a2e483fa4aee8ba85584a66e5ed9c0af9ea48a348960bc467076643cb56aeafdd7d2252e90c75e68ef664c0477ec87ea0554ffdc + "@types/send": "*" + checksum: 26ec864d3a626ea627f8b09c122b623499d2221bbf2f470127f4c9ebfe92bd8a6bb5157001372d4c4bd0dd37a1691620217d9dc4df5aa8f779f3fd996b1c60ae languageName: node linkType: hard @@ -15723,9 +11619,9 @@ __metadata: linkType: hard "@types/stack-utils@npm:^2.0.0": - version: 2.0.1 - resolution: "@types/stack-utils@npm:2.0.1" - checksum: 3327ee919a840ffe907bbd5c1d07dfd79137dd9732d2d466cf717ceec5bb21f66296173c53bb56cff95fae4185b9cd6770df3e9745fe4ba528bbc4975f54d13f + version: 2.0.3 + resolution: "@types/stack-utils@npm:2.0.3" + checksum: 1f4658385ae936330581bcb8aa3a066df03867d90281cdf89cc356d404bd6579be0f11902304e1f775d92df22c6dd761d4451c804b0a4fba973e06211e9bd77c languageName: node linkType: hard @@ -15745,13 +11641,6 @@ __metadata: languageName: node linkType: hard -"@types/tapable@npm:^1, @types/tapable@npm:^1.0.5": - version: 1.0.8 - resolution: "@types/tapable@npm:1.0.8" - checksum: 01f77d47bac8aaeee7ed298e8e74eb012a28f920106c3c359e1f2730512cd810f2c6165cd2cd769422ae1064e2bf1072778b27fb5ec1973e18c35e2cc1ed5c8d - languageName: node - linkType: hard - "@types/testing-library__jest-dom@npm:^5.9.1": version: 5.14.9 resolution: "@types/testing-library__jest-dom@npm:5.14.9" @@ -15762,55 +11651,39 @@ __metadata: linkType: hard "@types/through@npm:*": - version: 0.0.30 - resolution: "@types/through@npm:0.0.30" + version: 0.0.33 + resolution: "@types/through@npm:0.0.33" dependencies: "@types/node": "*" - checksum: f78ead4bb253d9ce7e173fb3895a61d3bfc7c368246e886cfc79e16c65ed88b3acfe7812c06e72bfde54d6a25b9b1af4fc09072ee9353627093159d403003d59 + checksum: 6a8edd7f40cd7e197318e86310a40e568cddd380609dde59b30d5cc6c5f8276ddc698905eac4b3b429eb39f2e8ee326bc20dc6e95a2cdc41c4d3fc9a1ebd4929 languageName: node linkType: hard "@types/tough-cookie@npm:*": - version: 4.0.2 - resolution: "@types/tough-cookie@npm:4.0.2" - checksum: 38d01fc79a9a87166253b8c548bb401599424c57a818bea1b47a68be6dcd37fc3bff381f978354e00221f284937d5066bb92d58bf79952f9d21deb934e8ec9a7 + version: 4.0.5 + resolution: "@types/tough-cookie@npm:4.0.5" + checksum: 68c6921721a3dcb40451543db2174a145ef915bc8bcbe7ad4e59194a0238e776e782b896c7a59f4b93ac6acefca9161fccb31d1ce3b3445cb6faa467297fb473 languageName: node linkType: hard "@types/triple-beam@npm:^1.3.2": - version: 1.3.2 - resolution: "@types/triple-beam@npm:1.3.2" - checksum: 2e936cff7cde9df7da854a54a5f63e0a434b2ae1d6c1eb6de5f7a0b1107b023b3c272abecbba28614a54b8831226b29e37a49e3e34a7490a6a24d770a5b44eb9 + version: 1.3.5 + resolution: "@types/triple-beam@npm:1.3.5" + checksum: d5d7f25da612f6d79266f4f1bb9c1ef8f1684e9f60abab251e1261170631062b656ba26ff22631f2760caeafd372abc41e64867cde27fba54fafb73a35b9056a languageName: node linkType: hard "@types/ua-parser-js@npm:^0.7.36": - version: 0.7.38 - resolution: "@types/ua-parser-js@npm:0.7.38" - checksum: 38defb228b286637f7021c4acef29f5b3e6e33288df45f4f05d51d598c21242abd0d8837dbb825cf1ecd4c3cd45830bc13b963ffd89383527dff209d1a1621de + version: 0.7.39 + resolution: "@types/ua-parser-js@npm:0.7.39" + checksum: fea522f42dfc2854d9c93144a13c3db3bbe1c791458451db06d46bec7e1dbbe945d1542e02bb38378e39a04bdb7810b43e2ead26f9e6c250832e187312522708 languageName: node linkType: hard -"@types/uglify-js@npm:*": - version: 3.17.1 - resolution: "@types/uglify-js@npm:3.17.1" - dependencies: - source-map: ^0.6.1 - checksum: c19a44017a901ab15f862e6645023bf96ffb7502b7305a15ee811667693ec66a997a42d5d0ba67814de537b562dafd26230142e26c9bb9f840ee8bb7f798cbcc - languageName: node - linkType: hard - -"@types/unist@npm:*, @types/unist@npm:^2.0.0, @types/unist@npm:^2.0.2, @types/unist@npm:^2.0.3": - version: 2.0.6 - resolution: "@types/unist@npm:2.0.6" - checksum: 8690789328e8e10c487334341fcf879fd49f8987c98ce49849f9871052f95d87477735171bb661e6f551bdb95235e015dfdad1867ca1d9b5b88a053f72ac40eb - languageName: node - linkType: hard - -"@types/uuid@npm:^9.0.0": - version: 9.0.2 - resolution: "@types/uuid@npm:9.0.2" - checksum: 4c4834f9738575a69db1179589cf397830dc205850b491216697afb254764c79c96a63b92f76e81b6d03515bed9227adf184fa4d33bb04970e6377e2f7c5bab9 +"@types/unist@npm:^2.0.0": + version: 2.0.10 + resolution: "@types/unist@npm:2.0.10" + checksum: 5f247dc2229944355209ad5c8e83cfe29419fa7f0a6d557421b1985a1500444719cc9efcc42c652b55aab63c931813c88033e0202c1ac684bcd4829d66e44731 languageName: node linkType: hard @@ -15821,14 +11694,7 @@ __metadata: languageName: node linkType: hard -"@types/validator@npm:^13.7.10": - version: 13.7.17 - resolution: "@types/validator@npm:13.7.17" - checksum: 46ec9b8bc11d91a575aead891a9c1d2f23bc28369449cb62415d663262d1d0e96debe75ceac626102a17a0a7a899330626ec36c8d4e84d337c705daed314fed5 - languageName: node - linkType: hard - -"@types/validator@npm:^13.7.17": +"@types/validator@npm:^13.11.8, @types/validator@npm:^13.7.17": version: 13.11.9 resolution: "@types/validator@npm:13.11.9" checksum: 856ebfcfe25d6c91a90235e0eb27302a737832530898195bbfb265da52ae7fe6d68f684942574f8818d3c262cae7a1de99f145dac73fc57217933af1bfc199cb @@ -15844,55 +11710,14 @@ __metadata: languageName: node linkType: hard -"@types/webpack-env@npm:^1.16.0": - version: 1.18.1 - resolution: "@types/webpack-env@npm:1.18.1" - checksum: 7b7cb8d22fe85fb3f87f592cb5ba2fb3b1057d1d5ce8d770b28728095879f5921085fae97f5bc479bdca55f2cb3111bd9148dc36cd641a5694dfbe001c5fc2f7 - languageName: node - linkType: hard - -"@types/webpack-sources@npm:*": - version: 3.2.0 - resolution: "@types/webpack-sources@npm:3.2.0" - dependencies: - "@types/node": "*" - "@types/source-list-map": "*" - source-map: ^0.7.3 - checksum: 17716e9f03fa63362f92d510bb9119313bac3a7985321e0fe9326dc30ebe598cb2c85b8c7cdc4f4d34d783c4c45e74e3ec08e209f9c9dab27bf188c3def32706 - languageName: node - linkType: hard - -"@types/webpack@npm:^4.41.26, @types/webpack@npm:^4.41.8": - version: 4.41.33 - resolution: "@types/webpack@npm:4.41.33" - dependencies: - "@types/node": "*" - "@types/tapable": ^1 - "@types/uglify-js": "*" - "@types/webpack-sources": "*" - anymatch: ^3.0.0 - source-map: ^0.6.0 - checksum: dc6db66fa84664d8fab7ea79bd2482ea1c4500b09ed6939258e205548501b8d29c06b0fe5e869c4b59f74acf884c61a391875dadb9f7a91c8cd10c3841143729 - languageName: node - linkType: hard - "@types/yargs-parser@npm:*": - version: 21.0.0 - resolution: "@types/yargs-parser@npm:21.0.0" - checksum: cb89f3bb2e8002f1479a65a934e825be4cc18c50b350bbc656405d41cf90b8a299b105e7da497d7eb1aa460472a07d1e5a389f3af0862f1d1252279cfcdd017c + version: 21.0.3 + resolution: "@types/yargs-parser@npm:21.0.3" + checksum: e71c3bd9d0b73ca82e10bee2064c384ab70f61034bbfb78e74f5206283fc16a6d85267b606b5c22cb2a3338373586786fed595b2009825d6a9115afba36560a0 languageName: node linkType: hard -"@types/yargs@npm:^15.0.0": - version: 15.0.15 - resolution: "@types/yargs@npm:15.0.15" - dependencies: - "@types/yargs-parser": "*" - checksum: b52519ba68a8d90996b54143ff74fcd8ac1722a1ef4a50ed8c3dbc1f7a76d14210f0262f8b91eabcdab202ff4babdd92ce7332ab1cdd6af4eae7c9fc81c83797 - languageName: node - linkType: hard - -"@types/yargs@npm:^15.0.15": +"@types/yargs@npm:^15.0.0, @types/yargs@npm:^15.0.15": version: 15.0.19 resolution: "@types/yargs@npm:15.0.19" dependencies: @@ -15902,32 +11727,32 @@ __metadata: linkType: hard "@types/yargs@npm:^16.0.0": - version: 16.0.5 - resolution: "@types/yargs@npm:16.0.5" + version: 16.0.9 + resolution: "@types/yargs@npm:16.0.9" dependencies: "@types/yargs-parser": "*" - checksum: 7b2824c749b6e28f5ee3248d13b244eaf7d3c5bb96089add774997572b5a10f1a0826d29a7bc797d64d29ca504b0b0d6ba2e74931b3fabae78ccbbcf07282f0c + checksum: be24bd9a56c97ddb2964c1c18f5b9fe8271a50e100dc6945989901aae58f7ce6fb8f3a591c749a518401b6301358dbd1997e83c36138a297094feae7f9ac8211 languageName: node linkType: hard "@types/yargs@npm:^17.0.8": - version: 17.0.24 - resolution: "@types/yargs@npm:17.0.24" + version: 17.0.32 + resolution: "@types/yargs@npm:17.0.32" dependencies: "@types/yargs-parser": "*" - checksum: fbebf57e1d04199e5e7eb0c67a402566fa27177ee21140664e63da826408793d203d262b48f8f41d4a7665126393d2e952a463e960e761226def247d9bbcdbd0 + checksum: 2095e8aad8a4e66b86147415364266b8d607a3b95b4239623423efd7e29df93ba81bb862784a6e08664f645cc1981b25fd598f532019174cd3e5e1e689e1cccf languageName: node linkType: hard "@typescript-eslint/eslint-plugin@npm:^6.19.0": - version: 6.19.0 - resolution: "@typescript-eslint/eslint-plugin@npm:6.19.0" + version: 6.21.0 + resolution: "@typescript-eslint/eslint-plugin@npm:6.21.0" dependencies: "@eslint-community/regexpp": ^4.5.1 - "@typescript-eslint/scope-manager": 6.19.0 - "@typescript-eslint/type-utils": 6.19.0 - "@typescript-eslint/utils": 6.19.0 - "@typescript-eslint/visitor-keys": 6.19.0 + "@typescript-eslint/scope-manager": 6.21.0 + "@typescript-eslint/type-utils": 6.21.0 + "@typescript-eslint/utils": 6.21.0 + "@typescript-eslint/visitor-keys": 6.21.0 debug: ^4.3.4 graphemer: ^1.4.0 ignore: ^5.2.4 @@ -15940,25 +11765,25 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: ab1a5ace6663b0c6d2418e321328fa28aa4bdc4b5fae257addec01346fb3a9c2d3a2960ade0f7114e6974c513a28632c9e8e602333cc0fab3135c445babdef59 + checksum: f911a79ee64d642f814a3b6cdb0d324b5f45d9ef955c5033e78903f626b7239b4aa773e464a38c3e667519066169d983538f2bf8e5d00228af587c9d438fb344 languageName: node linkType: hard "@typescript-eslint/parser@npm:^6.19.0": - version: 6.19.0 - resolution: "@typescript-eslint/parser@npm:6.19.0" + version: 6.21.0 + resolution: "@typescript-eslint/parser@npm:6.21.0" dependencies: - "@typescript-eslint/scope-manager": 6.19.0 - "@typescript-eslint/types": 6.19.0 - "@typescript-eslint/typescript-estree": 6.19.0 - "@typescript-eslint/visitor-keys": 6.19.0 + "@typescript-eslint/scope-manager": 6.21.0 + "@typescript-eslint/types": 6.21.0 + "@typescript-eslint/typescript-estree": 6.21.0 + "@typescript-eslint/visitor-keys": 6.21.0 debug: ^4.3.4 peerDependencies: eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: d547bfb1aaed112cfc0f9f0be8506a280952ba3b61be42b749352139361bd94e4a47fa043d819e19c6a498cacbd8bb36a46e3628c436a7e2009e7ac27afc8861 + checksum: a8f99820679decd0d115c0af61903fb1de3b1b5bec412dc72b67670bf636de77ab07f2a68ee65d6da7976039bbf636907f9d5ca546db3f0b98a31ffbc225bc7d languageName: node linkType: hard @@ -15972,22 +11797,22 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.19.0": - version: 6.19.0 - resolution: "@typescript-eslint/scope-manager@npm:6.19.0" +"@typescript-eslint/scope-manager@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/scope-manager@npm:6.21.0" dependencies: - "@typescript-eslint/types": 6.19.0 - "@typescript-eslint/visitor-keys": 6.19.0 - checksum: 1ec7b9dedca7975f0aa4543c1c382f7d6131411bd443a5f9b96f137acb6adb450888ed13c95f6d26546b682b2e0579ce8a1c883fdbe2255dc0b61052193b8243 + "@typescript-eslint/types": 6.21.0 + "@typescript-eslint/visitor-keys": 6.21.0 + checksum: eaf868938d811cbbea33e97e44ba7050d2b6892202cea6a9622c486b85ab1cf801979edf78036179a8ba4ac26f1dfdf7fcc83a68c1ff66be0b3a8e9a9989b526 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:6.19.0": - version: 6.19.0 - resolution: "@typescript-eslint/type-utils@npm:6.19.0" +"@typescript-eslint/type-utils@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/type-utils@npm:6.21.0" dependencies: - "@typescript-eslint/typescript-estree": 6.19.0 - "@typescript-eslint/utils": 6.19.0 + "@typescript-eslint/typescript-estree": 6.21.0 + "@typescript-eslint/utils": 6.21.0 debug: ^4.3.4 ts-api-utils: ^1.0.1 peerDependencies: @@ -15995,7 +11820,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 5b146b985481e587122026c703ac9f537ad7e90eee1dca814971bca0d7e4a5d4ff9861fb4bf749014c28c6a4fbb4a01a4527355961315eb9501f3569f8e8dd38 + checksum: 7409c97d1c4a4386b488962739c4f1b5b04dc60cf51f8cd88e6b12541f84d84c6b8b67e491a147a2c95f9ec486539bf4519fb9d418411aef6537b9c156468117 languageName: node linkType: hard @@ -16006,10 +11831,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:6.19.0": - version: 6.19.0 - resolution: "@typescript-eslint/types@npm:6.19.0" - checksum: 6f81860a3c14df55232c2e6dec21fb166867b9f30b3c3369b325aef5ee1c7e41e827c0504654daa49c8ff1a3a9ca9d9bfe76786882b6212a7c1b58991a9c80b9 +"@typescript-eslint/types@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/types@npm:6.21.0" + checksum: 020631d3223bbcff8a0da3efbdf058220a8f48a3de221563996ad1dcc30d6c08dadc3f7608cc08830d21c0d565efd2db19b557b9528921c78aabb605eef2d74d languageName: node linkType: hard @@ -16031,12 +11856,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.19.0": - version: 6.19.0 - resolution: "@typescript-eslint/typescript-estree@npm:6.19.0" +"@typescript-eslint/typescript-estree@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/typescript-estree@npm:6.21.0" dependencies: - "@typescript-eslint/types": 6.19.0 - "@typescript-eslint/visitor-keys": 6.19.0 + "@typescript-eslint/types": 6.21.0 + "@typescript-eslint/visitor-keys": 6.21.0 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 @@ -16046,24 +11871,24 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 5b365f009e43c7beafdbb7d8ecad78ee1087b0a4338cd9ec695eed514b7b4c1089e56239761139ddae629ec0ce8d428840c6ebfeea3618d2efe00c84f8794da5 + checksum: af1438c60f080045ebb330155a8c9bb90db345d5069cdd5d01b67de502abb7449d6c75500519df829f913a6b3f490ade3e8215279b6bdc63d0fb0ae61034df5f languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.19.0": - version: 6.19.0 - resolution: "@typescript-eslint/utils@npm:6.19.0" +"@typescript-eslint/utils@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/utils@npm:6.21.0" dependencies: "@eslint-community/eslint-utils": ^4.4.0 "@types/json-schema": ^7.0.12 "@types/semver": ^7.5.0 - "@typescript-eslint/scope-manager": 6.19.0 - "@typescript-eslint/types": 6.19.0 - "@typescript-eslint/typescript-estree": 6.19.0 + "@typescript-eslint/scope-manager": 6.21.0 + "@typescript-eslint/types": 6.21.0 + "@typescript-eslint/typescript-estree": 6.21.0 semver: ^7.5.4 peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: 343ff4cd4f7e102df8c46b41254d017a33d95df76455531fda679fdb92aebb9c111df8ee9ab54972e73c1e8fad9dd7e421001233f0aee8115384462b0821852e + checksum: ab2df3833b2582d4e5467a484d08942b4f2f7208f8e09d67de510008eb8001a9b7460f2f9ba11c12086fd3cdcac0c626761c7995c2c6b5657d5fa6b82030a32d languageName: node linkType: hard @@ -16095,24 +11920,24 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.19.0": - version: 6.19.0 - resolution: "@typescript-eslint/visitor-keys@npm:6.19.0" +"@typescript-eslint/visitor-keys@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/visitor-keys@npm:6.21.0" dependencies: - "@typescript-eslint/types": 6.19.0 + "@typescript-eslint/types": 6.21.0 eslint-visitor-keys: ^3.4.1 - checksum: bb34e922e018aadf34866995ea5949d6623f184cc4f6470ab05767dd208ffabb003b7dc3872199714574b7f10afe89d49c6f89a4e8d086edea82be73e189f1bb + checksum: 7395f69739cfa1cb83c1fb2fad30afa2a814756367302fb4facd5893eff66abc807e8d8f63eba94ed3b0fe0c1c996ac9a1680bcbf0f83717acedc3f2bb724fbf languageName: node linkType: hard "@uiw/react-json-view@npm:^2.0.0-alpha.17": - version: 2.0.0-alpha.17 - resolution: "@uiw/react-json-view@npm:2.0.0-alpha.17" + version: 2.0.0-alpha.24 + resolution: "@uiw/react-json-view@npm:2.0.0-alpha.24" peerDependencies: "@babel/runtime": ">=7.10.0" react: ">=18.0.0" react-dom: ">=18.0.0" - checksum: 6c8f10af40db9ae60da4b799fc391a544d2e6eec071d882d64050869b057e26fa6104c00de0406693a341c03a8017cb37c14136d803c9ff60e86c6e0d0187cbc + checksum: 7075ae7fe95810104ae3717aaf90600d73e8406c7e94e37b98770edc6a983e35b0dfcd884f7ab00863adebc80384fc597770166e4b7ccf9867bf36e2c83e8b69 languageName: node linkType: hard @@ -16182,7 +12007,7 @@ __metadata: languageName: node linkType: hard -"@vitejs/plugin-react@npm:4.2.1, @vitejs/plugin-react@npm:^4.2.1": +"@vitejs/plugin-react@npm:4.2.1, @vitejs/plugin-react@npm:^4.0.1, @vitejs/plugin-react@npm:^4.2.1": version: 4.2.1 resolution: "@vitejs/plugin-react@npm:4.2.1" dependencies: @@ -16212,21 +12037,6 @@ __metadata: languageName: node linkType: hard -"@vitejs/plugin-react@npm:^4.0.1": - version: 4.1.0 - resolution: "@vitejs/plugin-react@npm:4.1.0" - dependencies: - "@babel/core": ^7.22.20 - "@babel/plugin-transform-react-jsx-self": ^7.22.5 - "@babel/plugin-transform-react-jsx-source": ^7.22.5 - "@types/babel__core": ^7.20.2 - react-refresh: ^0.14.0 - peerDependencies: - vite: ^4.2.0 - checksum: 307753d34662079d4c65e205b365cbae0eba4273dc77d7c658d8611fb6546fa92c4e71f4cacccb58cff09d0a86f7b5ba35f85379b166485e484982093f7dcfc1 - languageName: node - linkType: hard - "@vitest/coverage-v8@npm:^0.32.2": version: 0.32.4 resolution: "@vitest/coverage-v8@npm:0.32.4" @@ -16301,335 +12111,14 @@ __metadata: languageName: node linkType: hard -"@webassemblyjs/ast@npm:1.11.6, @webassemblyjs/ast@npm:^1.11.5": - version: 1.11.6 - resolution: "@webassemblyjs/ast@npm:1.11.6" +"@vitest/utils@npm:^0.34.6": + version: 0.34.7 + resolution: "@vitest/utils@npm:0.34.7" dependencies: - "@webassemblyjs/helper-numbers": 1.11.6 - "@webassemblyjs/helper-wasm-bytecode": 1.11.6 - checksum: e28476a183c8a1787adcf0e5df1d36ec4589467ab712c674fe4f6769c7fb19d1217bfb5856b3edd0f3e0a148ebae9e4bbb84110cee96664966dfef204d9c31fb - languageName: node - linkType: hard - -"@webassemblyjs/ast@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/ast@npm:1.9.0" - dependencies: - "@webassemblyjs/helper-module-context": 1.9.0 - "@webassemblyjs/helper-wasm-bytecode": 1.9.0 - "@webassemblyjs/wast-parser": 1.9.0 - checksum: 8246c714346cdcd3ab204a2b09904d9d36c4f7da8f30cc217b0b7272a3ef57a3c21e95d51b26601641133fb66fea5cc46c357cf897808512f13b3d1c2efe88e4 - languageName: node - linkType: hard - -"@webassemblyjs/floating-point-hex-parser@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/floating-point-hex-parser@npm:1.11.6" - checksum: 37fe26f89e18e4ca0e7d89cfe3b9f17cfa327d7daf906ae01400416dbb2e33c8a125b4dc55ad7ff405e5fcfb6cf0d764074c9bc532b9a31a71e762be57d2ea0a - languageName: node - linkType: hard - -"@webassemblyjs/floating-point-hex-parser@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/floating-point-hex-parser@npm:1.9.0" - checksum: 17acfdfe6650691ae8d0279e6ff4fb8b5efce64e12f3fa18c6a7d279968cc72eb21c0db7ebb5be9d627d05fa7014cef087843d999de96c917079f57d7dac8f77 - languageName: node - linkType: hard - -"@webassemblyjs/helper-api-error@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/helper-api-error@npm:1.11.6" - checksum: a681ed51863e4ff18cf38d223429f414894e5f7496856854d9a886eeddcee32d7c9f66290f2919c9bb6d2fc2b2fae3f989b6a1e02a81e829359738ea0c4d371a - languageName: node - linkType: hard - -"@webassemblyjs/helper-api-error@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/helper-api-error@npm:1.9.0" - checksum: 892851b25cf4b4b307490328f45858414326dac667ca15244b5e959fa6e22478b29dabeb581d49ef8a2874e291d0417a3a959be70428c39cd40870e73b394dbc - languageName: node - linkType: hard - -"@webassemblyjs/helper-buffer@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/helper-buffer@npm:1.11.6" - checksum: 55b5d67db95369cdb2a505ae7ebdf47194d49dfc1aecb0f5403277dcc899c7d3e1f07e8d279646adf8eafd89959272db62ca66fbe803321661ab184176ddfd3a - languageName: node - linkType: hard - -"@webassemblyjs/helper-buffer@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/helper-buffer@npm:1.9.0" - checksum: b09a3e27d9127ccaab095bd171336e7675bb5b832e05b701ff174a853b763154a49f5382c4c3f2f1cc746b1cff3f2025452145cf807ddf788133bcccf5920ca8 - languageName: node - linkType: hard - -"@webassemblyjs/helper-code-frame@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/helper-code-frame@npm:1.9.0" - dependencies: - "@webassemblyjs/wast-printer": 1.9.0 - checksum: 010969a6c8b016680a9b1383ff4b8147c363608dd1e29602154e5460954af4fd48daed518a76b232ca43935d4b6bebf54fba38da56f809e2bd12f063d84013ec - languageName: node - linkType: hard - -"@webassemblyjs/helper-fsm@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/helper-fsm@npm:1.9.0" - checksum: ef0c99b58716d757a1a41f99fb46578d3f07d97b60cd51deaeffdf0aad09ec47f5093ee8d098d12324d57f8812609704c377fccfe9a32d02c0a658a4a33dce94 - languageName: node - linkType: hard - -"@webassemblyjs/helper-module-context@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/helper-module-context@npm:1.9.0" - dependencies: - "@webassemblyjs/ast": 1.9.0 - checksum: 130a9ac1141770b9f70ad568ec2dc769e92c756f91b06ece9cda2c2a5e80e21ec9c8c2a945a5839bf379e52fa921ae134245a7492e1b9ae0e8c557bb9b4953c3 - languageName: node - linkType: hard - -"@webassemblyjs/helper-numbers@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/helper-numbers@npm:1.11.6" - dependencies: - "@webassemblyjs/floating-point-hex-parser": 1.11.6 - "@webassemblyjs/helper-api-error": 1.11.6 - "@xtuc/long": 4.2.2 - checksum: c7d5afc0ff3bd748339b466d8d2f27b908208bf3ff26b2e8e72c39814479d486e0dca6f3d4d776fd9027c1efe05b5c0716c57a23041eb34473892b2731c33af3 - languageName: node - linkType: hard - -"@webassemblyjs/helper-wasm-bytecode@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/helper-wasm-bytecode@npm:1.11.6" - checksum: 79d2bebdd11383d142745efa32781249745213af8e022651847382685ca76709f83e1d97adc5f0d3c2b8546bf02864f8b43a531fdf5ca0748cb9e4e0ef2acaa5 - languageName: node - linkType: hard - -"@webassemblyjs/helper-wasm-bytecode@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/helper-wasm-bytecode@npm:1.9.0" - checksum: 1741993e1c723f56b619a4981ec975f903886aa3f1f50c7bdb2eaa45ca4ad8d023d6ae7413ef643f060567b1f12a9dcfad6c43688879c46ee4f0b53aa71cd5c9 - languageName: node - linkType: hard - -"@webassemblyjs/helper-wasm-section@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/helper-wasm-section@npm:1.11.6" - dependencies: - "@webassemblyjs/ast": 1.11.6 - "@webassemblyjs/helper-buffer": 1.11.6 - "@webassemblyjs/helper-wasm-bytecode": 1.11.6 - "@webassemblyjs/wasm-gen": 1.11.6 - checksum: b79b19a63181f32e5ee0e786fa8264535ea5360276033911fae597d2de15e1776f028091d08c5a813a3901fd2228e74cd8c7e958fded064df734f00546bef8ce - languageName: node - linkType: hard - -"@webassemblyjs/helper-wasm-section@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/helper-wasm-section@npm:1.9.0" - dependencies: - "@webassemblyjs/ast": 1.9.0 - "@webassemblyjs/helper-buffer": 1.9.0 - "@webassemblyjs/helper-wasm-bytecode": 1.9.0 - "@webassemblyjs/wasm-gen": 1.9.0 - checksum: 2a5baa7749c50a4a428f372ab88b7e52956b48798d44e7291b4aa8558b247337dba791112ce8a4f5b2281e1b9014e6d44d0141476a5fcde6016fac2e009671e8 - languageName: node - linkType: hard - -"@webassemblyjs/ieee754@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/ieee754@npm:1.11.6" - dependencies: - "@xtuc/ieee754": ^1.2.0 - checksum: 59de0365da450322c958deadade5ec2d300c70f75e17ae55de3c9ce564deff5b429e757d107c7ec69bd0ba169c6b6cc2ff66293ab7264a7053c829b50ffa732f - languageName: node - linkType: hard - -"@webassemblyjs/ieee754@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/ieee754@npm:1.9.0" - dependencies: - "@xtuc/ieee754": ^1.2.0 - checksum: 0eff34ec7048400b30282ab9af6ad19d2852dab2f5ffaec8bdc697b8380bc2c9dbe6cadf65f49e68242c82ee3caa8aa6e46c89dbfdab37615189b4da2eab3819 - languageName: node - linkType: hard - -"@webassemblyjs/leb128@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/leb128@npm:1.11.6" - dependencies: - "@xtuc/long": 4.2.2 - checksum: cb344fc04f1968209804de4da018679c5d4708a03b472a33e0fa75657bb024978f570d3ccf9263b7f341f77ecaa75d0e051b9cd4b7bb17a339032cfd1c37f96e - languageName: node - linkType: hard - -"@webassemblyjs/leb128@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/leb128@npm:1.9.0" - dependencies: - "@xtuc/long": 4.2.2 - checksum: 441be8634733b33b710f44d4394552d6290bb1a0a8311b384b1865b58c3549d0ddeaf1c3985bbee024a8df12c597be3580fc1cde2ae003dcbf26762b493a7a2f - languageName: node - linkType: hard - -"@webassemblyjs/utf8@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/utf8@npm:1.11.6" - checksum: 14d6c24751a89ad9d801180b0d770f30a853c39f035a15fbc96266d6ac46355227abd27a3fd2eeaa97b4294ced2440a6b012750ae17bafe1a7633029a87b6bee - languageName: node - linkType: hard - -"@webassemblyjs/utf8@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/utf8@npm:1.9.0" - checksum: 9566689a1bcf555d6b79d0da79e24ff2be23c0395e5a19ed3c2ceca7831e50b867e0b1c66b3ff1b1d7f297b2d2414314967a884a77634ad0acff8a78489e2b19 - languageName: node - linkType: hard - -"@webassemblyjs/wasm-edit@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/wasm-edit@npm:1.9.0" - dependencies: - "@webassemblyjs/ast": 1.9.0 - "@webassemblyjs/helper-buffer": 1.9.0 - "@webassemblyjs/helper-wasm-bytecode": 1.9.0 - "@webassemblyjs/helper-wasm-section": 1.9.0 - "@webassemblyjs/wasm-gen": 1.9.0 - "@webassemblyjs/wasm-opt": 1.9.0 - "@webassemblyjs/wasm-parser": 1.9.0 - "@webassemblyjs/wast-printer": 1.9.0 - checksum: 07f4cb4a73989622c524f9264b6afe664d33354f081499f04db675aed2b79498bd43600c3d7bebcb9f93ccce6a094b3c28f3f7b11ea62e9e82074c2ae68dc058 - languageName: node - linkType: hard - -"@webassemblyjs/wasm-edit@npm:^1.11.5": - version: 1.11.6 - resolution: "@webassemblyjs/wasm-edit@npm:1.11.6" - dependencies: - "@webassemblyjs/ast": 1.11.6 - "@webassemblyjs/helper-buffer": 1.11.6 - "@webassemblyjs/helper-wasm-bytecode": 1.11.6 - "@webassemblyjs/helper-wasm-section": 1.11.6 - "@webassemblyjs/wasm-gen": 1.11.6 - "@webassemblyjs/wasm-opt": 1.11.6 - "@webassemblyjs/wasm-parser": 1.11.6 - "@webassemblyjs/wast-printer": 1.11.6 - checksum: 9a56b6bf635cf7aa5d6e926eaddf44c12fba050170e452a8e17ab4e1b937708678c03f5817120fb9de1e27167667ce693d16ce718d41e5a16393996a6017ab73 - languageName: node - linkType: hard - -"@webassemblyjs/wasm-gen@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/wasm-gen@npm:1.11.6" - dependencies: - "@webassemblyjs/ast": 1.11.6 - "@webassemblyjs/helper-wasm-bytecode": 1.11.6 - "@webassemblyjs/ieee754": 1.11.6 - "@webassemblyjs/leb128": 1.11.6 - "@webassemblyjs/utf8": 1.11.6 - checksum: ce9a39d3dab2eb4a5df991bc9f3609960daa4671d25d700f4617152f9f79da768547359f817bee10cd88532c3e0a8a1714d383438e0a54217eba53cb822bd5ad - languageName: node - linkType: hard - -"@webassemblyjs/wasm-gen@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/wasm-gen@npm:1.9.0" - dependencies: - "@webassemblyjs/ast": 1.9.0 - "@webassemblyjs/helper-wasm-bytecode": 1.9.0 - "@webassemblyjs/ieee754": 1.9.0 - "@webassemblyjs/leb128": 1.9.0 - "@webassemblyjs/utf8": 1.9.0 - checksum: 876826bef91f3af9e48118fb269c348871d5b6f019e071065556da56a3a5818630b00133e07c9dd2cc767e7f2c70934f3ed0060330ce3e37910e9c9df25f1600 - languageName: node - linkType: hard - -"@webassemblyjs/wasm-opt@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/wasm-opt@npm:1.11.6" - dependencies: - "@webassemblyjs/ast": 1.11.6 - "@webassemblyjs/helper-buffer": 1.11.6 - "@webassemblyjs/wasm-gen": 1.11.6 - "@webassemblyjs/wasm-parser": 1.11.6 - checksum: 82788408054171688e9f12883b693777219366d6867003e34dccc21b4a0950ef53edc9d2b4d54cabdb6ee869cf37c8718401b4baa4f70a7f7dd3867c75637298 - languageName: node - linkType: hard - -"@webassemblyjs/wasm-opt@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/wasm-opt@npm:1.9.0" - dependencies: - "@webassemblyjs/ast": 1.9.0 - "@webassemblyjs/helper-buffer": 1.9.0 - "@webassemblyjs/wasm-gen": 1.9.0 - "@webassemblyjs/wasm-parser": 1.9.0 - checksum: 3d5558e078b660cd9777950f2df60f005f3cbdbcfa6c8c19dc0cf012f44f5bfa97c991d7ac26b3e78596bad0538e92dd00b5db4b51ebc373da8e329a03639190 - languageName: node - linkType: hard - -"@webassemblyjs/wasm-parser@npm:1.11.6, @webassemblyjs/wasm-parser@npm:^1.11.5": - version: 1.11.6 - resolution: "@webassemblyjs/wasm-parser@npm:1.11.6" - dependencies: - "@webassemblyjs/ast": 1.11.6 - "@webassemblyjs/helper-api-error": 1.11.6 - "@webassemblyjs/helper-wasm-bytecode": 1.11.6 - "@webassemblyjs/ieee754": 1.11.6 - "@webassemblyjs/leb128": 1.11.6 - "@webassemblyjs/utf8": 1.11.6 - checksum: 7a97a5f34f98bdcfd812157845a06d53f3d3f67dbd4ae5d6bf66e234e17dc4a76b2b5e74e5dd70b4cab9778fc130194d50bbd6f9a1d23e15ed1ed666233d6f5f - languageName: node - linkType: hard - -"@webassemblyjs/wasm-parser@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/wasm-parser@npm:1.9.0" - dependencies: - "@webassemblyjs/ast": 1.9.0 - "@webassemblyjs/helper-api-error": 1.9.0 - "@webassemblyjs/helper-wasm-bytecode": 1.9.0 - "@webassemblyjs/ieee754": 1.9.0 - "@webassemblyjs/leb128": 1.9.0 - "@webassemblyjs/utf8": 1.9.0 - checksum: 1e8615b9f9c3c431c9635c9a9884bca89eff1ab2383ad849341c23e09899454482a8f8813d33bf86ee1b0acc97c7c83926961a9b34d4804fa5d559610ab0a4a2 - languageName: node - linkType: hard - -"@webassemblyjs/wast-parser@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/wast-parser@npm:1.9.0" - dependencies: - "@webassemblyjs/ast": 1.9.0 - "@webassemblyjs/floating-point-hex-parser": 1.9.0 - "@webassemblyjs/helper-api-error": 1.9.0 - "@webassemblyjs/helper-code-frame": 1.9.0 - "@webassemblyjs/helper-fsm": 1.9.0 - "@xtuc/long": 4.2.2 - checksum: c79952466fdf7816be527b1db102952b777b12318eabb5c40df074cd8361e3a7b0179a985534fa8b5a7b93668b07ba46875ffeb5da03ca5177c80ba960ebdffc - languageName: node - linkType: hard - -"@webassemblyjs/wast-printer@npm:1.11.6": - version: 1.11.6 - resolution: "@webassemblyjs/wast-printer@npm:1.11.6" - dependencies: - "@webassemblyjs/ast": 1.11.6 - "@xtuc/long": 4.2.2 - checksum: 916b90fa3a8aadd95ca41c21d4316d0a7582cf6d0dcf6d9db86ab0de823914df513919fba60ac1edd227ff00e93a66b927b15cbddd36b69d8a34c8815752633c - languageName: node - linkType: hard - -"@webassemblyjs/wast-printer@npm:1.9.0": - version: 1.9.0 - resolution: "@webassemblyjs/wast-printer@npm:1.9.0" - dependencies: - "@webassemblyjs/ast": 1.9.0 - "@webassemblyjs/wast-parser": 1.9.0 - "@xtuc/long": 4.2.2 - checksum: f3d106aa884cbb7687307db7adeb3b98abff9de81b9ba8c1065267340b5e9de64ffc533044ab916b1f4ce8a67fb03efa54b29b61c8e908abe4c07edf82f614cd + diff-sequences: ^29.4.3 + loupe: ^2.3.6 + pretty-format: ^29.5.0 + checksum: 5f26ec5b4a53709a50efdb57aa753e8090b3411e888774f67a0d192eb7f046ed5fcc6884eb3d6275d2674926e724b731e8d28cd3cea96a7f3d27462a0d44af9e languageName: node linkType: hard @@ -16640,27 +12129,6 @@ __metadata: languageName: node linkType: hard -"@xmldom/xmldom@npm:^0.7.2": - version: 0.7.11 - resolution: "@xmldom/xmldom@npm:0.7.11" - checksum: dc41e499266f29601a417354bb17ca40eb17b5c321807e4cc2f5155d7faca9bf54480bebbfc353cdc8a57fa36c25d3c659a7a7a39bec0b88b78a9f00ee0d529e - languageName: node - linkType: hard - -"@xtuc/ieee754@npm:^1.2.0": - version: 1.2.0 - resolution: "@xtuc/ieee754@npm:1.2.0" - checksum: a8565d29d135039bd99ae4b2220d3e167d22cf53f867e491ed479b3f84f895742d0097f935b19aab90265a23d5d46711e4204f14c479ae3637fbf06c4666882f - languageName: node - linkType: hard - -"@xtuc/long@npm:4.2.2": - version: 4.2.2 - resolution: "@xtuc/long@npm:4.2.2" - checksum: 8582cbc69c79ad2d31568c412129bf23d2b1210a1dfb60c82d5a1df93334da4ee51f3057051658569e2c196d8dc33bc05ae6b974a711d0d16e801e1d0647ccd1 - languageName: node - linkType: hard - "@yarnpkg/esbuild-plugin-pnp@npm:^3.0.0-rc.10": version: 3.0.0-rc.15 resolution: "@yarnpkg/esbuild-plugin-pnp@npm:3.0.0-rc.15" @@ -16711,14 +12179,21 @@ __metadata: languageName: node linkType: hard -"abbrev@npm:1, abbrev@npm:^1.0.0": +"abbrev@npm:1": version: 1.1.1 resolution: "abbrev@npm:1.1.1" checksum: 3f762677702acb24f65e813070e306c61fafe25d4b2583f9dfc935131f774863f3addd5741572ed576bd69cabe473c5af18e1e108b829cb7b6b4747884f726e6 languageName: node linkType: hard -"abort-controller@npm:3.0.0": +"abbrev@npm:^2.0.0": + version: 2.0.0 + resolution: "abbrev@npm:2.0.0" + checksum: f742a5a107473946f426c691c08daba61a1d15942616f300b5d32fd735be88fef5cba24201757b6c407fd564555fb48c751cfa33519b2605c8a7aadd22baf372 + languageName: node + linkType: hard + +"abort-controller@npm:3.0.0, abort-controller@npm:^3.0.0": version: 3.0.0 resolution: "abort-controller@npm:3.0.0" dependencies: @@ -16803,15 +12278,6 @@ __metadata: languageName: node linkType: hard -"acorn-import-assertions@npm:^1.9.0": - version: 1.9.0 - resolution: "acorn-import-assertions@npm:1.9.0" - peerDependencies: - acorn: ^8 - checksum: 3b4a194e128efdc9b86c2b1544f623aba4c1aa70d638f8ab7dc3971a5b4aa4c57bd62f99af6e5325bb5973c55863b4112e708a6f408bad7a138647ca72283afe - languageName: node - linkType: hard - "acorn-jsx@npm:^5.3.1, acorn-jsx@npm:^5.3.2": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" @@ -16830,7 +12296,7 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:8.2.0, acorn-walk@npm:^8.0.2, acorn-walk@npm:^8.1.1, acorn-walk@npm:^8.2.0": +"acorn-walk@npm:8.2.0": version: 8.2.0 resolution: "acorn-walk@npm:8.2.0" checksum: dbe92f5b2452c93e960c5594e666dd1fae141b965ff2cb4a1e1d0381e3e4db4274c5ce4ffa3d681a86ca2a8d4e29d5efc0670a08e23fd2800051ea387df56ca2 @@ -16851,7 +12317,14 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^6.0.1, acorn@npm:^6.4.1": +"acorn-walk@npm:^8.0.2, acorn-walk@npm:^8.1.1, acorn-walk@npm:^8.2.0": + version: 8.3.2 + resolution: "acorn-walk@npm:8.3.2" + checksum: 7e2a8dad5480df7f872569b9dccff2f3da7e65f5353686b1d6032ab9f4ddf6e3a2cb83a9b52cf50b1497fd522154dda92f0abf7153290cc79cd14721ff121e52 + languageName: node + linkType: hard + +"acorn@npm:^6.0.1": version: 6.4.2 resolution: "acorn@npm:6.4.2" bin: @@ -16869,21 +12342,12 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.1.0, acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.7.1, acorn@npm:^8.8.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": - version: 8.9.0 - resolution: "acorn@npm:8.9.0" +"acorn@npm:^8.1.0, acorn@npm:^8.10.0, acorn@npm:^8.11.3, acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.8.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": + version: 8.11.3 + resolution: "acorn@npm:8.11.3" bin: acorn: bin/acorn - checksum: 5b51689d56f1ca5d6ea1fa58af478affd8d3396403637abcbc7caf28e1a47beb537cf1654f537b6cf4c73377f3e1aa99fd4a50674e64daefe08cb25c799ded28 - languageName: node - linkType: hard - -"acorn@npm:^8.10.0": - version: 8.10.0 - resolution: "acorn@npm:8.10.0" - bin: - acorn: bin/acorn - checksum: deaeebfbea6e40f6c0e1070e9b0e16e76ba484de54cbd735914d1d41d19169a450de8630b7a3a0c4e271a3b0c0b075a3427ad1a40d8a69f8747c0e8cb02ee3e2 + checksum: 3ff155f8812e4a746fee8ecff1f227d527c4c45655bb1fad6347c3cb58e46190598217551b1500f18542d2bbe5c87120cb6927f5a074a59166fbdd9468f0a299 languageName: node linkType: hard @@ -16911,7 +12375,7 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:6, agent-base@npm:^6.0.2": +"agent-base@npm:6": version: 6.0.2 resolution: "agent-base@npm:6.0.2" dependencies: @@ -16920,23 +12384,12 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:^7.0.2": - version: 7.1.0 - resolution: "agent-base@npm:7.1.0" +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": + version: 7.1.1 + resolution: "agent-base@npm:7.1.1" dependencies: debug: ^4.3.4 - checksum: fc974ab57ffdd8421a2bc339644d312a9cca320c20c3393c9d8b1fd91731b9bbabdb985df5fc860f5b79d81c3e350daa3fcb31c5c07c0bb385aafc817df004ce - languageName: node - linkType: hard - -"agentkeepalive@npm:^4.2.1": - version: 4.3.0 - resolution: "agentkeepalive@npm:4.3.0" - dependencies: - debug: ^4.1.0 - depd: ^2.0.0 - humanize-ms: ^1.2.1 - checksum: 61cbdab12d45e82e9ae515b0aa8d09617b66f72409e541a646dd7be4b7260d335d7f56a38079ad305bf0ffb8405592a459faf1294111289107f48352a20c2799 + checksum: e59ce7bed9c63bf071a30cc471f2933862044c97fd9958967bfe22521d7a0f601ce4ed5a8c011799d0c726ca70312142ae193bbebb60f576b52be19d4a363b50 languageName: node linkType: hard @@ -16950,31 +12403,6 @@ __metadata: languageName: node linkType: hard -"airbnb-js-shims@npm:^2.2.1": - version: 2.2.1 - resolution: "airbnb-js-shims@npm:2.2.1" - dependencies: - array-includes: ^3.0.3 - array.prototype.flat: ^1.2.1 - array.prototype.flatmap: ^1.2.1 - es5-shim: ^4.5.13 - es6-shim: ^0.35.5 - function.prototype.name: ^1.1.0 - globalthis: ^1.0.0 - object.entries: ^1.1.0 - object.fromentries: ^2.0.0 || ^1.0.0 - object.getownpropertydescriptors: ^2.0.3 - object.values: ^1.1.0 - promise.allsettled: ^1.0.0 - promise.prototype.finally: ^3.1.0 - string.prototype.matchall: ^4.0.0 || ^3.0.1 - string.prototype.padend: ^3.0.0 - string.prototype.padstart: ^3.0.0 - symbol.prototype.description: ^1.0.0 - checksum: 55fdeb2673da440772d278816664b8e8da946b57adfd95b6635bc980ad235e388266c1488fdff3a055e95dc1c789e389821598b2711b59ce76ab4500f528216c - languageName: node - linkType: hard - "ajv-draft-04@npm:^1.0.0": version: 1.0.0 resolution: "ajv-draft-04@npm:1.0.0" @@ -16987,25 +12415,7 @@ __metadata: languageName: node linkType: hard -"ajv-errors@npm:^1.0.0": - version: 1.0.1 - resolution: "ajv-errors@npm:1.0.1" - peerDependencies: - ajv: ">=5.0.0" - checksum: de2d6e8100c8707ea063ee4785d53adf599b457c0d4f72c3592244d67ad16448a6d35f7ce45f12bdd2819939447c876e8ef2f1c0800896d7f2aa25c3838acdf1 - languageName: node - linkType: hard - -"ajv-keywords@npm:^3.1.0, ajv-keywords@npm:^3.4.1, ajv-keywords@npm:^3.5.2": - version: 3.5.2 - resolution: "ajv-keywords@npm:3.5.2" - peerDependencies: - ajv: ^6.9.1 - checksum: 0c57a47cbd656e8cdfd99d7c2264de5868918ffa207c8d7a72a7f63379d4333254b2ba03d69e3c035e996a3fd3eb6d5725d7a1597cca10694296e32510546360 - languageName: node - linkType: hard - -"ajv@npm:^6.1.0, ajv@npm:^6.10.0, ajv@npm:^6.10.2, ajv@npm:^6.12.2, ajv@npm:^6.12.3, ajv@npm:^6.12.4, ajv@npm:^6.12.5": +"ajv@npm:^6.10.0, ajv@npm:^6.12.3, ajv@npm:^6.12.4": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -17018,14 +12428,14 @@ __metadata: linkType: hard "ajv@npm:^8.0.1, ajv@npm:^8.12.0": - version: 8.12.0 - resolution: "ajv@npm:8.12.0" + version: 8.13.0 + resolution: "ajv@npm:8.13.0" dependencies: - fast-deep-equal: ^3.1.1 + fast-deep-equal: ^3.1.3 json-schema-traverse: ^1.0.0 require-from-string: ^2.0.2 - uri-js: ^4.2.2 - checksum: ac4f72adf727ee425e049bc9d8b31d4a57e1c90da8d28bcd23d60781b12fcd6fc3d68db5df16994c57b78b94eed7988f5a6b482fd376dc5b084125e20a0a622e + uri-js: ^4.4.1 + checksum: 14c6497b6f72843986d7344175a1aa0e2c35b1e7f7475e55bc582cddb765fca7e6bf950f465dc7846f817776d9541b706f4b5b3fbedd8dfdeb5fce6f22864264 languageName: node linkType: hard @@ -17038,13 +12448,6 @@ __metadata: languageName: node linkType: hard -"ansi-colors@npm:^3.0.0": - version: 3.2.4 - resolution: "ansi-colors@npm:3.2.4" - checksum: 1785466547bac3b1cb8055325a415c8c946a818669da4fd3d1247cab7617b845b221c2ae04756277074d278b52d90efd67f73d2dd927c7a0d1a10395c1b7665b - languageName: node - linkType: hard - "ansi-colors@npm:^4.1.1, ansi-colors@npm:^4.1.3": version: 4.1.3 resolution: "ansi-colors@npm:4.1.3" @@ -17052,13 +12455,6 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^3.1.0": - version: 3.2.0 - resolution: "ansi-escapes@npm:3.2.0" - checksum: 084e1ce38139ad2406f18a8e7efe2b850ddd06ce3c00f633392d1ce67756dab44fe290e573d09ef3c9a0cb13c12881e0e35a8f77a017d39a0a4ab85ae2fae04f - languageName: node - linkType: hard - "ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.0, ansi-escapes@npm:^4.3.2": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" @@ -17068,15 +12464,6 @@ __metadata: languageName: node linkType: hard -"ansi-html-community@npm:0.0.8, ansi-html-community@npm:^0.0.8": - version: 0.0.8 - resolution: "ansi-html-community@npm:0.0.8" - bin: - ansi-html: bin/ansi-html - checksum: 45d3a6f0b4f10b04fdd44bef62972e2470bfd917bf00439471fa7473d92d7cbe31369c73db863cc45dda115cb42527f39e232e9256115534b8ee5806b0caeed4 - languageName: node - linkType: hard - "ansi-regex@npm:^2.0.0": version: 2.1.1 resolution: "ansi-regex@npm:2.1.1" @@ -17144,17 +12531,6 @@ __metadata: languageName: node linkType: hard -"ansi-to-html@npm:^0.6.11": - version: 0.6.15 - resolution: "ansi-to-html@npm:0.6.15" - dependencies: - entities: ^2.0.0 - bin: - ansi-to-html: bin/ansi-to-html - checksum: 50fa836c3bec74b5f3d8ea630a86cad972e6463203be30171ed65073afa5f3e70946de2d0e129eb5cab391b489e99972aab3aa4fded3da45c4bd7c265bfae6f5 - languageName: node - linkType: hard - "ansicolors@npm:~0.3.2": version: 0.3.2 resolution: "ansicolors@npm:0.3.2" @@ -17179,7 +12555,7 @@ __metadata: languageName: node linkType: hard -"anymatch@npm:^3.0.0, anymatch@npm:^3.0.3, anymatch@npm:~3.1.2": +"anymatch@npm:^3.0.3, anymatch@npm:~3.1.2": version: 3.1.3 resolution: "anymatch@npm:3.1.3" dependencies: @@ -17217,40 +12593,6 @@ __metadata: languageName: node linkType: hard -"aproba@npm:^1.0.3 || ^2.0.0": - version: 2.0.0 - resolution: "aproba@npm:2.0.0" - checksum: d06e26384a8f6245d8c8896e138c0388824e259a329e0c9f196b4fa533c82502a6fd449586e3604950a0c42921832a458bb3aa0aa9f0ba449cfd4f50fd0d09b5 - languageName: node - linkType: hard - -"aproba@npm:^1.1.1": - version: 1.2.0 - resolution: "aproba@npm:1.2.0" - checksum: 2d34f008c9edfa991f42fe4b667d541d38a474a39ae0e24805350486d76744cd91ee45313283c1d39a055b14026dd0fc4d0cbfc13f210855d59d7e8b5a61dc51 - languageName: node - linkType: hard - -"are-we-there-yet@npm:^2.0.0": - version: 2.0.0 - resolution: "are-we-there-yet@npm:2.0.0" - dependencies: - delegates: ^1.0.0 - readable-stream: ^3.6.0 - checksum: 375f753c10329153c8d66dc95e8f8b6c7cc2aa66e05cb0960bd69092b10dae22900cacc7d653ad11d26b3ecbdbfe1e8bfb6ccf0265ba8077a7d979970f16b99c - languageName: node - linkType: hard - -"are-we-there-yet@npm:^3.0.0": - version: 3.0.1 - resolution: "are-we-there-yet@npm:3.0.1" - dependencies: - delegates: ^1.0.0 - readable-stream: ^3.6.0 - checksum: 8373f289ba42e4b5ec713bb585acdac14b5702c75f2a458dc985b9e4fa5762bc5b46b40a21b72418a3ed0cfb5e35bdc317ef1ae132f3035f633d581dd03168c3 - languageName: node - linkType: hard - "arg@npm:^4.1.0": version: 4.1.3 resolution: "arg@npm:4.1.3" @@ -17282,11 +12624,11 @@ __metadata: linkType: hard "aria-hidden@npm:^1.1.1": - version: 1.2.3 - resolution: "aria-hidden@npm:1.2.3" + version: 1.2.4 + resolution: "aria-hidden@npm:1.2.4" dependencies: tslib: ^2.0.0 - checksum: 46b07b7273167ad3fc2625f1ecbb43f8e6f73115c66785cbb5dcf1e2508133a43b6419d610c39676ceaeb563239efbd8974d5c0187695db8b3e8c3e11f549c2d + checksum: 8abcab2e1432efc4db415e97cb3959649ddf52c8fc815d7384f43f3d3abf56f1c12852575d00df9a8927f421d7e0712652dd5f8db244ea57634344e29ecfc74a languageName: node linkType: hard @@ -17329,24 +12671,24 @@ __metadata: languageName: node linkType: hard -"array-buffer-byte-length@npm:^1.0.0": - version: 1.0.0 - resolution: "array-buffer-byte-length@npm:1.0.0" +"array-buffer-byte-length@npm:^1.0.0, array-buffer-byte-length@npm:^1.0.1": + version: 1.0.1 + resolution: "array-buffer-byte-length@npm:1.0.1" dependencies: - call-bind: ^1.0.2 - is-array-buffer: ^3.0.1 - checksum: 12f84f6418b57a954caa41654e5e63e019142a4bbb2c6829ba86d1ba65d31ccfaf1461d1743556fd32b091fac34ff44d9dfbdb001402361c45c373b2c86f5c20 + call-bind: ^1.0.5 + is-array-buffer: ^3.0.4 + checksum: f5cdf54527cd18a3d2852ddf73df79efec03829e7373a8322ef5df2b4ef546fb365c19c71d6b42d641cb6bfe0f1a2f19bc0ece5b533295f86d7c3d522f228917 languageName: node linkType: hard "array-equal@npm:^1.0.0": - version: 1.0.0 - resolution: "array-equal@npm:1.0.0" - checksum: 5841f0b823e6806d147d40e262a0f66cb7d3272b9f9ffa8dedb868fc7799cb410ae262a32f6f358baa6c3ee7d6271eeab86b516cdfd8f9a8fa12b4f15a18e119 + version: 1.0.2 + resolution: "array-equal@npm:1.0.2" + checksum: c308184b1df488bed0eba1a8835d77789349d3859a334cb60f77df15dc4ab232c185c78b643ae68651eef1b7148942223d72fa1aba218d24ec6cf9637fb49d8e languageName: node linkType: hard -"array-find-index@npm:^1.0.1, array-find-index@npm:^1.0.2": +"array-find-index@npm:^1.0.2": version: 1.0.2 resolution: "array-find-index@npm:1.0.2" checksum: 86b9485c74ddd324feab807e10a6de3f9c1683856267236fac4bb4d4667ada6463e106db3f6c540ae6b720e0442b590ec701d13676df4c6af30ebf4da09b4f57 @@ -17360,25 +12702,17 @@ __metadata: languageName: node linkType: hard -"array-includes@npm:^3.0.3, array-includes@npm:^3.1.6": - version: 3.1.6 - resolution: "array-includes@npm:3.1.6" +"array-includes@npm:^3.1.6, array-includes@npm:^3.1.7": + version: 3.1.8 + resolution: "array-includes@npm:3.1.8" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - get-intrinsic: ^1.1.3 + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.2 + es-object-atoms: ^1.0.0 + get-intrinsic: ^1.2.4 is-string: ^1.0.7 - checksum: d0caeaa57bea7d14b8480daee30cf8611899321006b15a6cd872b831bd7aaed7649f8764e060d01c5d33b8d9e998e5de5c87f4901874e1c1f467f429b7db2929 - languageName: node - linkType: hard - -"array-union@npm:^1.0.2": - version: 1.0.2 - resolution: "array-union@npm:1.0.2" - dependencies: - array-uniq: ^1.0.1 - checksum: 18686767c0cfdae8dc4acf5ac119b0f0eacad82b7fcc0aa62cc41f93c5ad406d494b6a6e53d85e52e8f0349b67a4fec815feeb537e95c02510d747bc9a4157c7 + checksum: 5b1004d203e85873b96ddc493f090c9672fd6c80d7a60b798da8a14bff8a670ff95db5aafc9abc14a211943f05220dacf8ea17638ae0af1a6a47b8c0b48ce370 languageName: node linkType: hard @@ -17389,13 +12723,6 @@ __metadata: languageName: node linkType: hard -"array-uniq@npm:^1.0.1": - version: 1.0.3 - resolution: "array-uniq@npm:1.0.3" - checksum: 3acbaf9e6d5faeb1010e2db04ab171b8d265889e46c61762e502979bdc5e55656013726e9a61507de3c82d329a0dc1e8072630a3454b4f2b881cb19ba7fd8aa6 - languageName: node - linkType: hard - "array-unique@npm:^0.3.2": version: 0.3.2 resolution: "array-unique@npm:0.3.2" @@ -17403,66 +12730,111 @@ __metadata: languageName: node linkType: hard -"array.prototype.flat@npm:^1.2.1, array.prototype.flat@npm:^1.2.3, array.prototype.flat@npm:^1.3.1": - version: 1.3.1 - resolution: "array.prototype.flat@npm:1.3.1" +"array.prototype.findlast@npm:^1.2.4": + version: 1.2.5 + resolution: "array.prototype.findlast@npm:1.2.5" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - es-shim-unscopables: ^1.0.0 - checksum: 8eda91d6925cc84b73ebf5a3d406ff28745d93a22ef6a0afb967755107081a937cf6c4555d3c18354870b2c5366c0ff51b3f597c11079e689869810a418b1b4f + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.2 + es-errors: ^1.3.0 + es-object-atoms: ^1.0.0 + es-shim-unscopables: ^1.0.2 + checksum: ddc952b829145ab45411b9d6adcb51a8c17c76bf89c9dd64b52d5dffa65d033da8c076ed2e17091779e83bc892b9848188d7b4b33453c5565e65a92863cb2775 languageName: node linkType: hard -"array.prototype.flatmap@npm:^1.2.1, array.prototype.flatmap@npm:^1.3.1": - version: 1.3.1 - resolution: "array.prototype.flatmap@npm:1.3.1" +"array.prototype.flat@npm:^1.2.3, array.prototype.flat@npm:^1.3.1": + version: 1.3.2 + resolution: "array.prototype.flat@npm:1.3.2" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 es-shim-unscopables: ^1.0.0 - checksum: 2bd58a0e79d5d90cb4f5ef0e287edf8b28e87c65428f54025ac6b7b4c204224b92811c266f296c53a2dbc93872117c0fcea2e51d3c9e8cecfd5024d4a4a57db4 + checksum: a578ed836a786efbb6c2db0899ae80781b476200617f65a44846cb1ed8bd8b24c8821b83703375d8af639c689497b7b07277060024b9919db94ac3e10dc8a49b + languageName: node + linkType: hard + +"array.prototype.flatmap@npm:^1.3.2": + version: 1.3.2 + resolution: "array.prototype.flatmap@npm:1.3.2" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + es-shim-unscopables: ^1.0.0 + checksum: 67b3f1d602bb73713265145853128b1ad77cc0f9b833c7e1e056b323fbeac41a4ff1c9c99c7b9445903caea924d9ca2450578d9011913191aa88cc3c3a4b54f4 languageName: node linkType: hard "array.prototype.map@npm:^1.0.5": - version: 1.0.5 - resolution: "array.prototype.map@npm:1.0.5" + version: 1.0.7 + resolution: "array.prototype.map@npm:1.0.7" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.2 es-array-method-boxes-properly: ^1.0.0 + es-object-atoms: ^1.0.0 is-string: ^1.0.7 - checksum: cf44c0c958e94059d98132a3d5b7aa20d29aea34d20c515fdb236b69a95b1d3f1408f634f26fca51a9dbe06c85e93f7b351c85ea94300774af5ad2f1e8df3ae8 + checksum: 33ba6bf4e963fa18e32785f2a993a481edaec88b742a38f4da41be27e0fd4d04f49d0ae85184bf2b0d5a19789c7762b56d855d5e04c9db917e27b9375e94d66b languageName: node linkType: hard -"array.prototype.reduce@npm:^1.0.5": - version: 1.0.5 - resolution: "array.prototype.reduce@npm:1.0.5" +"array.prototype.reduce@npm:^1.0.6": + version: 1.0.7 + resolution: "array.prototype.reduce@npm:1.0.7" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.2 es-array-method-boxes-properly: ^1.0.0 + es-errors: ^1.3.0 + es-object-atoms: ^1.0.0 is-string: ^1.0.7 - checksum: 0c6c589d22d6cda4a32458c6fd57a41f420a4fa6cd184a3f6fe7b507f457bc4a073aff6accd595bcd6ac29cad856e7ac306549f127acdb098f401eea13c54901 + checksum: 97aac907d7b15088d5b991bad79de96f95ea0d47a701a034e2dc816e0aabaed2fb401d7fe65ab6fda05eafa58319aa2d1bac404f515e162b81b3b61a51224db2 languageName: node linkType: hard -"array.prototype.tosorted@npm:^1.1.1": - version: 1.1.1 - resolution: "array.prototype.tosorted@npm:1.1.1" +"array.prototype.toreversed@npm:^1.1.2": + version: 1.1.2 + resolution: "array.prototype.toreversed@npm:1.1.2" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 es-shim-unscopables: ^1.0.0 - get-intrinsic: ^1.1.3 - checksum: fd5f57aca3c7ddcd1bb83965457b625f3a67d8f334f5cbdb8ac8ef33d5b0d38281524114db2936f8c08048115d5158af216c94e6ae1eb966241b9b6f4ab8a7e8 + checksum: 2b7627ea85eae1e80ecce665a500cc0f3355ac83ee4a1a727562c7c2a1d5f1c0b4dd7b65c468ec6867207e452ba01256910a2c0b41486bfdd11acf875a7a3435 + languageName: node + linkType: hard + +"array.prototype.tosorted@npm:^1.1.3": + version: 1.1.3 + resolution: "array.prototype.tosorted@npm:1.1.3" + dependencies: + call-bind: ^1.0.5 + define-properties: ^1.2.1 + es-abstract: ^1.22.3 + es-errors: ^1.1.0 + es-shim-unscopables: ^1.0.2 + checksum: a27e1ca51168ecacf6042901f5ef021e43c8fa04b6c6b6f2a30bac3645cd2b519cecbe0bc45db1b85b843f64dc3207f0268f700b4b9fbdec076d12d432cf0865 + languageName: node + linkType: hard + +"arraybuffer.prototype.slice@npm:^1.0.3": + version: 1.0.3 + resolution: "arraybuffer.prototype.slice@npm:1.0.3" + dependencies: + array-buffer-byte-length: ^1.0.1 + call-bind: ^1.0.5 + define-properties: ^1.2.1 + es-abstract: ^1.22.3 + es-errors: ^1.2.1 + get-intrinsic: ^1.2.3 + is-array-buffer: ^3.0.4 + is-shared-array-buffer: ^1.0.2 + checksum: d32754045bcb2294ade881d45140a5e52bda2321b9e98fa514797b7f0d252c4c5ab0d1edb34112652c62fa6a9398def568da63a4d7544672229afea283358c36 languageName: node linkType: hard @@ -17473,32 +12845,6 @@ __metadata: languageName: node linkType: hard -"arrify@npm:^2.0.1": - version: 2.0.1 - resolution: "arrify@npm:2.0.1" - checksum: 3fb30b5e7c37abea1907a60b28a554d2f0fc088757ca9bf5b684786e583fdf14360721eb12575c1ce6f995282eab936712d3c4389122682eafab0e0b57f78dbb - languageName: node - linkType: hard - -"asap@npm:~2.0.3": - version: 2.0.6 - resolution: "asap@npm:2.0.6" - checksum: c6d5e39fe1f15e4b87677460bd66b66050cd14c772269cee6688824c1410a08ab20254bb6784f9afb75af9144a9f9a7692d49547f4d19d715aeb7c0318f3136d - languageName: node - linkType: hard - -"asn1.js@npm:^5.2.0": - version: 5.4.1 - resolution: "asn1.js@npm:5.4.1" - dependencies: - bn.js: ^4.0.0 - inherits: ^2.0.1 - minimalistic-assert: ^1.0.0 - safer-buffer: ^2.1.0 - checksum: b577232fa6069cc52bb128e564002c62b2b1fe47f7137bdcd709c0b8495aa79cee0f8cc458a831b2d8675900eea0d05781b006be5e1aa4f0ae3577a73ec20324 - languageName: node - linkType: hard - "asn1@npm:~0.2.3": version: 0.2.6 resolution: "asn1@npm:0.2.6" @@ -17515,17 +12861,7 @@ __metadata: languageName: node linkType: hard -"assert@npm:^1.1.1": - version: 1.5.0 - resolution: "assert@npm:1.5.0" - dependencies: - object-assign: ^4.1.1 - util: 0.10.3 - checksum: 188da37d63be479a3b14657c01080db90cdf7fa004e346af916cf8beebcaffb11359c596d0c9c3cd8174c9125a6225796ef1ce533487edc97f8ce3b18c1ab590 - languageName: node - linkType: hard - -"assert@npm:^2.0.0": +"assert@npm:^2.1.0": version: 2.1.0 resolution: "assert@npm:2.1.0" dependencies: @@ -17552,24 +12888,6 @@ __metadata: languageName: node linkType: hard -"ast-types@npm:0.15.2": - version: 0.15.2 - resolution: "ast-types@npm:0.15.2" - dependencies: - tslib: ^2.0.1 - checksum: 5b26e3656e9e8d1db8c8d14971d0cb88ca0138aacce72171cb4cd4555fc8dc53c07e821c568e57fe147366931708fefd25cb9d7e880d42ce9cb569947844c962 - languageName: node - linkType: hard - -"ast-types@npm:^0.14.2": - version: 0.14.2 - resolution: "ast-types@npm:0.14.2" - dependencies: - tslib: ^2.0.1 - checksum: 5d66d89b6c07fe092087454b6042dbaf81f2882b176db93861e2b986aafe0bce49e1f1ff59aac775d451c1426ad1e967d250e9e3548f5166ea8a3475e66c169d - languageName: node - linkType: hard - "ast-types@npm:^0.16.1": version: 0.16.1 resolution: "ast-types@npm:0.16.1" @@ -17622,9 +12940,9 @@ __metadata: linkType: hard "async@npm:^3.2.3": - version: 3.2.4 - resolution: "async@npm:3.2.4" - checksum: b5d02fed64717edf49e35b2b156debd9cf524934ea670108fa5528e7615ed66a5e0bf6c65f832c9483b63aa7f0bffe3e588ebe8d58a539b833798d324516e1c9 + version: 3.2.5 + resolution: "async@npm:3.2.5" + checksum: 1408287b26c6db67d45cb346e34892cee555b8b59e6c68e6f8c3e495cad5ca13b4f218180e871f3c2ca30df4ab52693b66f2f6ff43644760cab0b2198bda79c1 languageName: node linkType: hard @@ -17658,61 +12976,7 @@ __metadata: languageName: node linkType: hard -"autoprefixer@npm:^10.1.0": - version: 10.4.14 - resolution: "autoprefixer@npm:10.4.14" - dependencies: - browserslist: ^4.21.5 - caniuse-lite: ^1.0.30001464 - fraction.js: ^4.2.0 - normalize-range: ^0.1.2 - picocolors: ^1.0.0 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.1.0 - bin: - autoprefixer: bin/autoprefixer - checksum: 66ce961b86acd2a46e05ac1eece8657b3d9edfd2ee3abddd6cfcb32755e6865409f57acf11fe05990d6f166afda85a603678435916267a09652265cfff7b5706 - languageName: node - linkType: hard - -"autoprefixer@npm:^10.4.16": - version: 10.4.16 - resolution: "autoprefixer@npm:10.4.16" - dependencies: - browserslist: ^4.21.10 - caniuse-lite: ^1.0.30001538 - fraction.js: ^4.3.6 - normalize-range: ^0.1.2 - picocolors: ^1.0.0 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.1.0 - bin: - autoprefixer: bin/autoprefixer - checksum: e00256e754d481a026d928bca729b25954074dd142dbec022f0a7db0d3bbc0dc2e2dc7542e94fec22eff81e21fe140e6856448e2d9a002660cb1e2ad434daee0 - languageName: node - linkType: hard - -"autoprefixer@npm:^10.4.17": - version: 10.4.17 - resolution: "autoprefixer@npm:10.4.17" - dependencies: - browserslist: ^4.22.2 - caniuse-lite: ^1.0.30001578 - fraction.js: ^4.3.7 - normalize-range: ^0.1.2 - picocolors: ^1.0.0 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.1.0 - bin: - autoprefixer: bin/autoprefixer - checksum: 1d21cc8edb7bf993682094ceed03a32c18f5293f071182a64c2c6defb44bbe91d576ad775d2347469a81997b80cea0bbc4ad3eeb5b12710f9feacf2e6c04bb51 - languageName: node - linkType: hard - -"autoprefixer@npm:^10.4.19": +"autoprefixer@npm:^10.1.0, autoprefixer@npm:^10.4.16, autoprefixer@npm:^10.4.17, autoprefixer@npm:^10.4.19": version: 10.4.19 resolution: "autoprefixer@npm:10.4.19" dependencies: @@ -17730,27 +12994,12 @@ __metadata: languageName: node linkType: hard -"autoprefixer@npm:^9.8.6": - version: 9.8.8 - resolution: "autoprefixer@npm:9.8.8" +"available-typed-arrays@npm:^1.0.7": + version: 1.0.7 + resolution: "available-typed-arrays@npm:1.0.7" dependencies: - browserslist: ^4.12.0 - caniuse-lite: ^1.0.30001109 - normalize-range: ^0.1.2 - num2fraction: ^1.2.2 - picocolors: ^0.2.1 - postcss: ^7.0.32 - postcss-value-parser: ^4.1.0 - bin: - autoprefixer: bin/autoprefixer - checksum: 9b2688cd0ef7252ae1a565ca935a83ddd5c38b9b4c7bf895f36d88e91dbc36d2e7ccb2d34270e436498d8f372d7320a83af6ceb5d1c3bff8f8cbeb6ff33ac837 - languageName: node - linkType: hard - -"available-typed-arrays@npm:^1.0.5": - version: 1.0.5 - resolution: "available-typed-arrays@npm:1.0.5" - checksum: c4df567ca72d2754a6cbad20088f5f98b1065b3360178169fa9b44ea101af62c0f423fc3854fa820fd6895b6b9171b8386e71558203103ff8fc2ad503fdcc660 + possible-typed-array-names: ^1.0.0 + checksum: d07226ef4f87daa01bd0fe80f8f310982e345f372926da2e5296aecc25c41cab440916bbaa4c5e1034b453af3392f67df5961124e4b586df1e99793a1374bdb2 languageName: node linkType: hard @@ -17779,24 +13028,24 @@ __metadata: linkType: hard "axios-mock-adapter@npm:^1.19.0": - version: 1.21.5 - resolution: "axios-mock-adapter@npm:1.21.5" + version: 1.22.0 + resolution: "axios-mock-adapter@npm:1.22.0" dependencies: fast-deep-equal: ^3.1.3 is-buffer: ^2.0.5 peerDependencies: axios: ">= 0.17.0" - checksum: e90fd270439b4c09ece9b246cbf09d4098b86604e183cd604cedc9423397da20b9a1b9d7e4c2677445c7dc297bbb5424aba2d07cf1333e862150180326887e7a + checksum: d3c3631fb50116df57d11d604fa2c3dc80e769f0429728f9961c983662f60533a780f73a93fb7b20dae87995e9ae7c340619827267aeed9fdee02aded696d17a languageName: node linkType: hard "axios-retry@npm:^3.1.9": - version: 3.5.1 - resolution: "axios-retry@npm:3.5.1" + version: 3.9.1 + resolution: "axios-retry@npm:3.9.1" dependencies: "@babel/runtime": ^7.15.4 is-retry-allowed: ^2.2.0 - checksum: 710ab051cf90250540952467212258a6472cb150c1f3aea89ddd2d3833e1d581c0346ee06da77e9a71a24d7c86b229a799aac5e569bb05d2641386e779d0cd32 + checksum: 2360e59b241509b821cb6fee43bcbe0c41be4af3c50a58fa94c7b76d4705d334fa1e30160ee3be3db638e518c84c70e8ca20fb1a62987db2a415fff51c6bf5a9 languageName: node linkType: hard @@ -17903,40 +13152,6 @@ __metadata: languageName: node linkType: hard -"babel-jest@npm:^29.5.0": - version: 29.5.0 - resolution: "babel-jest@npm:29.5.0" - dependencies: - "@jest/transform": ^29.5.0 - "@types/babel__core": ^7.1.14 - babel-plugin-istanbul: ^6.1.1 - babel-preset-jest: ^29.5.0 - chalk: ^4.0.0 - graceful-fs: ^4.2.9 - slash: ^3.0.0 - peerDependencies: - "@babel/core": ^7.8.0 - checksum: 1114d3935e0f62b72e155ac79916214c078e798561be3b03d12ddd862f2849becc8516f89046719161ec457bded35d2e1fd7ddfb207a6169dd18bbb2a67ee987 - languageName: node - linkType: hard - -"babel-jest@npm:^29.6.4": - version: 29.6.4 - resolution: "babel-jest@npm:29.6.4" - dependencies: - "@jest/transform": ^29.6.4 - "@types/babel__core": ^7.1.14 - babel-plugin-istanbul: ^6.1.1 - babel-preset-jest: ^29.6.3 - chalk: ^4.0.0 - graceful-fs: ^4.2.9 - slash: ^3.0.0 - peerDependencies: - "@babel/core": ^7.8.0 - checksum: 983108bef8a65868f974c77f7a06da32fed1c63b7c15dcaec6cac278739c9790e35784197af042b6fc3a2c26e85db9355aa90cdef689d652d0736a968e7b4e6a - languageName: node - linkType: hard - "babel-jest@npm:^29.7.0": version: 29.7.0 resolution: "babel-jest@npm:29.7.0" @@ -17954,49 +13169,6 @@ __metadata: languageName: node linkType: hard -"babel-loader@npm:^8.0.0, babel-loader@npm:^8.2.3": - version: 8.3.0 - resolution: "babel-loader@npm:8.3.0" - dependencies: - find-cache-dir: ^3.3.1 - loader-utils: ^2.0.0 - make-dir: ^3.1.0 - schema-utils: ^2.6.5 - peerDependencies: - "@babel/core": ^7.0.0 - webpack: ">=2" - checksum: 7b83bae35a12fbc5cdf250e2d36a288305fe5b6d20ab044ab7c09bbf456c8895b80af7a4f1e8b64b5c07a4fd48d4b5144dab40b4bc72a4fed532dc000362f38f - languageName: node - linkType: hard - -"babel-plugin-add-react-displayname@npm:^0.0.5": - version: 0.0.5 - resolution: "babel-plugin-add-react-displayname@npm:0.0.5" - checksum: 96b363d613e3d25e55606546874f3ab34b45088ac5143a64e417976f1eb29ed3e4df90400daa5edb2026d6088ed172f7af469d89838aac4bc810ede377b63c63 - languageName: node - linkType: hard - -"babel-plugin-apply-mdx-type-prop@npm:1.6.22": - version: 1.6.22 - resolution: "babel-plugin-apply-mdx-type-prop@npm:1.6.22" - dependencies: - "@babel/helper-plugin-utils": 7.10.4 - "@mdx-js/util": 1.6.22 - peerDependencies: - "@babel/core": ^7.11.6 - checksum: d1fd88f2eee87f3d709373cfac5165f8407793b123e1c7061308311f7e6b0778e093a4a93e7130b47c5a742f2515d0c1d4f3da5097ff195ef91011688ec17ddc - languageName: node - linkType: hard - -"babel-plugin-extract-import-names@npm:1.6.22": - version: 1.6.22 - resolution: "babel-plugin-extract-import-names@npm:1.6.22" - dependencies: - "@babel/helper-plugin-utils": 7.10.4 - checksum: c7b7206222f7b70f2c9852caa621cc3742b5d9f7dd4229a6e3c560d7683b82f835a8ea46db632df5dab5ad91b1439ead3771a8576a7a14e418248c16fd1f0cc4 - languageName: node - linkType: hard - "babel-plugin-istanbul@npm:^6.0.0, babel-plugin-istanbul@npm:^6.1.1": version: 6.1.1 resolution: "babel-plugin-istanbul@npm:6.1.1" @@ -18045,18 +13217,6 @@ __metadata: languageName: node linkType: hard -"babel-plugin-jest-hoist@npm:^29.5.0": - version: 29.5.0 - resolution: "babel-plugin-jest-hoist@npm:29.5.0" - dependencies: - "@babel/template": ^7.3.3 - "@babel/types": ^7.3.3 - "@types/babel__core": ^7.1.14 - "@types/babel__traverse": ^7.0.6 - checksum: 385547c4d81647848dc3e86fecf4381032be99ed97d87aee78d422631f651042600371ee31e37ec9bb6f4a0a4f296b3b5798d69c410626ea94eae76d9c64da63 - languageName: node - linkType: hard - "babel-plugin-jest-hoist@npm:^29.6.3": version: 29.6.3 resolution: "babel-plugin-jest-hoist@npm:29.6.3" @@ -18080,98 +13240,39 @@ __metadata: languageName: node linkType: hard -"babel-plugin-polyfill-corejs2@npm:^0.4.3": - version: 0.4.3 - resolution: "babel-plugin-polyfill-corejs2@npm:0.4.3" - dependencies: - "@babel/compat-data": ^7.17.7 - "@babel/helper-define-polyfill-provider": ^0.4.0 - semver: ^6.1.1 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 27e014ab6116704a201a71aefa2a377f26d0e5432d0dcb7f71930773ef0ddac7a693f3a6699721efa15ae4c83631a35dcc52cc8b3032878b2dadd0a33aeabc59 - languageName: node - linkType: hard - -"babel-plugin-polyfill-corejs2@npm:^0.4.6": - version: 0.4.6 - resolution: "babel-plugin-polyfill-corejs2@npm:0.4.6" +"babel-plugin-polyfill-corejs2@npm:^0.4.10": + version: 0.4.11 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.11" dependencies: "@babel/compat-data": ^7.22.6 - "@babel/helper-define-polyfill-provider": ^0.4.3 + "@babel/helper-define-polyfill-provider": ^0.6.2 semver: ^6.3.1 peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 64a98811f343492aa6970ab253760194e389c0417e5b830522f944009c1f0c78e1251975fd1b9869cd48cc4623111b20a3389cf6732a1d10ba0d19de6fa5114f + checksum: b2217bc8d5976cf8142453ed44daabf0b2e0e75518f24eac83b54a8892e87a88f1bd9089daa92fd25df979ecd0acfd29b6bc28c4182c1c46344cee15ef9bce84 languageName: node linkType: hard -"babel-plugin-polyfill-corejs3@npm:^0.1.0": - version: 0.1.7 - resolution: "babel-plugin-polyfill-corejs3@npm:0.1.7" +"babel-plugin-polyfill-corejs3@npm:^0.10.1, babel-plugin-polyfill-corejs3@npm:^0.10.4": + version: 0.10.4 + resolution: "babel-plugin-polyfill-corejs3@npm:0.10.4" dependencies: - "@babel/helper-define-polyfill-provider": ^0.1.5 - core-js-compat: ^3.8.1 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: d31c7f0c210994593e2cc57d202ada8539cbbff1a112f52aa3607c8c9ba23b64e03fa52fbdc243dccbce8b8052f29f8d541bc4151e3055738cb03647708c0f42 - languageName: node - linkType: hard - -"babel-plugin-polyfill-corejs3@npm:^0.8.1": - version: 0.8.1 - resolution: "babel-plugin-polyfill-corejs3@npm:0.8.1" - dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.0 - core-js-compat: ^3.30.1 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 90320f5e5a27bcaf9a370d86ff3a9c72fd28618e51f83a7c1e31e34f9a2d671f5ca446b1c4af806cdee6388a6868da38299b3167dd860985981feeda3f2bf1c3 - languageName: node - linkType: hard - -"babel-plugin-polyfill-corejs3@npm:^0.8.5": - version: 0.8.6 - resolution: "babel-plugin-polyfill-corejs3@npm:0.8.6" - dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.3 - core-js-compat: ^3.33.1 + "@babel/helper-define-polyfill-provider": ^0.6.1 + core-js-compat: ^3.36.1 peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: 97d974c1dfbefdf27866e21a1ac757f6ab1626379b544d6f8ddb05f7bfa02173f8347b6140295b0f770394549f9321775d3048e466a9a02b99b88ad5f0346858 + checksum: 31b92cd3dfb5b417da8dfcf0deaa4b8b032b476d7bb31ca51c66127cf25d41e89260e89d17bc004b2520faa38aa9515fafabf81d89f9d4976e9dc1163e4a7c41 languageName: node linkType: hard -"babel-plugin-polyfill-regenerator@npm:^0.5.0": - version: 0.5.0 - resolution: "babel-plugin-polyfill-regenerator@npm:0.5.0" +"babel-plugin-polyfill-regenerator@npm:^0.6.1": + version: 0.6.2 + resolution: "babel-plugin-polyfill-regenerator@npm:0.6.2" dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: d33f4e6f5b925754175d4058ede4d400ea92b9ad465f07a4211e4ad01a6cdb60e3a04428150eb9dd5fb7ba9c1d0cba9e22278206462b432d46d7d851b3c3cb19 - languageName: node - linkType: hard - -"babel-plugin-polyfill-regenerator@npm:^0.5.3": - version: 0.5.3 - resolution: "babel-plugin-polyfill-regenerator@npm:0.5.3" - dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.3 + "@babel/helper-define-polyfill-provider": ^0.6.2 peerDependencies: "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 - checksum: cc32313b9ebbf1d7bedc33524a861136b9e5d3b6e9be317ac360a1c2a59ae5ed1b465a6c68b2715cdefb089780ddfb0c11f4a148e49827a947beee76e43da598 - languageName: node - linkType: hard - -"babel-plugin-react-docgen@npm:^4.2.1": - version: 4.2.1 - resolution: "babel-plugin-react-docgen@npm:4.2.1" - dependencies: - ast-types: ^0.14.2 - lodash: ^4.17.15 - react-docgen: ^5.0.0 - checksum: 9f7af20e6ebd794beae14aa1ffe4f1c1c5855821a5a9f205099602c89b557e33b9cb3dc3fe0b3a2f2ca35007c6ab45f52da9695a681d8495ad0f5494ef78ec34 + checksum: bc541037cf7620bc84ddb75a1c0ce3288f90e7d2799c070a53f8a495c8c8ae0316447becb06f958dd25dcce2a2fce855d318ecfa48036a1ddb218d55aa38a744 languageName: node linkType: hard @@ -18281,18 +13382,6 @@ __metadata: languageName: node linkType: hard -"babel-preset-jest@npm:^29.5.0": - version: 29.5.0 - resolution: "babel-preset-jest@npm:29.5.0" - dependencies: - babel-plugin-jest-hoist: ^29.5.0 - babel-preset-current-node-syntax: ^1.0.0 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 752b8682c8cf55bca46d870003f4ce43a4ba0fcaa1138ff7f0e02340628e221810b0c2c3e77a7d5070168dc163eb11907f6c9256f187242abe0f14219d1f6b12 - languageName: node - linkType: hard - "babel-preset-jest@npm:^29.6.3": version: 29.6.3 resolution: "babel-preset-jest@npm:29.6.3" @@ -18324,13 +13413,6 @@ __metadata: languageName: unknown linkType: soft -"bail@npm:^1.0.0": - version: 1.0.5 - resolution: "bail@npm:1.0.5" - checksum: 4cf7d0b5c82fdc69590b3fe85c17c4ec37647681b20875551fd6187a85c122b20178dc118001d3ebd5d0ab3dc0e95637c71f889f481882ee761db43c6b16fa05 - languageName: node - linkType: hard - "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -18338,14 +13420,7 @@ __metadata: languageName: node linkType: hard -"base16@npm:^1.0.0": - version: 1.0.0 - resolution: "base16@npm:1.0.0" - checksum: af1aee7b297d968528ef47c8de2c5274029743e8a4a5f61ec823e36b673781691d124168cb22936c7997f53d89b344c58bf7ecf93eeb148cffa7e3fb4e4b8b18 - languageName: node - linkType: hard - -"base64-js@npm:^1.0.2, base64-js@npm:^1.3.1": +"base64-js@npm:^1.3.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" checksum: f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf @@ -18392,15 +13467,6 @@ __metadata: languageName: node linkType: hard -"better-opn@npm:^2.1.1": - version: 2.1.1 - resolution: "better-opn@npm:2.1.1" - dependencies: - open: ^7.0.3 - checksum: c483f52a1c71555926df37a89ae7e521cddff6509e2a02c6af83c2c500e20cb3307417579ce1d5ec4d09855cc7d30f608b20934e7cedc54218888722d5bfc1d3 - languageName: node - linkType: hard - "better-opn@npm:^3.0.2": version: 3.0.2 resolution: "better-opn@npm:3.0.2" @@ -18419,10 +13485,10 @@ __metadata: languageName: node linkType: hard -"big-integer@npm:^1.6.44, big-integer@npm:^1.6.7": - version: 1.6.51 - resolution: "big-integer@npm:1.6.51" - checksum: c8139662d57f8833a44802f4b65be911679c569535ea73c5cfd3c1c8994eaead1b84b6f63e1db63833e4d4cacb6b6a9e5522178113dfdc8e4c81ed8436f1e8cc +"big-integer@npm:^1.6.44": + version: 1.6.52 + resolution: "big-integer@npm:1.6.52" + checksum: 9604224b4c2ab3c43c075d92da15863077a9f59e5d4205f4e7e76acd0cd47e8d469ec5e5dba8d9b32aa233951893b29329ca56ac80c20ce094b4a647a66abae0 languageName: node linkType: hard @@ -18448,18 +13514,9 @@ __metadata: linkType: hard "binary-extensions@npm:^2.0.0": - version: 2.2.0 - resolution: "binary-extensions@npm:2.2.0" - checksum: d73d8b897238a2d3ffa5f59c0241870043aa7471335e89ea5e1ff48edb7c2d0bb471517a3e4c5c3f4c043615caa2717b5f80a5e61e07503d51dc85cb848e665d - languageName: node - linkType: hard - -"bindings@npm:^1.5.0": - version: 1.5.0 - resolution: "bindings@npm:1.5.0" - dependencies: - file-uri-to-path: 1.0.0 - checksum: 3dab2491b4bb24124252a91e656803eac24292473e56554e35bbfe3cc1875332cfa77600c3bac7564049dc95075bf6fcc63a4609920ff2d64d0fe405fcf0d4ba + version: 2.3.0 + resolution: "binary-extensions@npm:2.3.0" + checksum: 75a59cafc10fb12a11d510e77110c6c7ae3f4ca22463d52487709ca7f18f69d886aa387557cc9864fbdb10153d0bdb4caacabf11541f55e89ed6e18d12ece2b5 languageName: node linkType: hard @@ -18485,27 +13542,6 @@ __metadata: languageName: node linkType: hard -"bluebird@npm:^3.5.5": - version: 3.7.2 - resolution: "bluebird@npm:3.7.2" - checksum: 680de03adc54ff925eaa6c7bb9a47a0690e8b5de60f4792604aae8ed618c65e6b63a7893b57ca924beaf53eee69c5af4f8314148c08124c550fe1df1add897d2 - languageName: node - linkType: hard - -"bn.js@npm:^4.0.0, bn.js@npm:^4.1.0, bn.js@npm:^4.11.9": - version: 4.12.0 - resolution: "bn.js@npm:4.12.0" - checksum: 9736aaa317421b6b3ed038ff3d4491935a01419ac2d83ddcfebc5717385295fcfcf0c57311d90fe49926d0abbd7a9dbefdd8861e6129939177f7e67ebc645b21 - languageName: node - linkType: hard - -"bn.js@npm:^5.0.0, bn.js@npm:^5.1.1": - version: 5.2.1 - resolution: "bn.js@npm:5.2.1" - checksum: bed3d8bd34ec89dbcf9f20f88bd7d4a49c160fda3b561c7bb227501f974d3e435a48fb9b61bc3de304acab9215a3bda0803f7017ffb4d0016a0c3a740a283caa - languageName: node - linkType: hard - "body-parser@npm:1.19.0": version: 1.19.0 resolution: "body-parser@npm:1.19.0" @@ -18524,27 +13560,7 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.20.1": - version: 1.20.1 - resolution: "body-parser@npm:1.20.1" - dependencies: - bytes: 3.1.2 - content-type: ~1.0.4 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.11.0 - raw-body: 2.5.1 - type-is: ~1.6.18 - unpipe: 1.0.0 - checksum: a202d493e2c10a33fb7413dac7d2f713be579c4b88343cd814b6df7a38e5af1901fc31044e04de176db56b16d9772aa25a7723f64478c20f4d91b1ac223bf3b8 - languageName: node - linkType: hard - -"body-parser@npm:^1.19.0": +"body-parser@npm:1.20.2, body-parser@npm:^1.19.0": version: 1.20.2 resolution: "body-parser@npm:1.20.2" dependencies: @@ -18578,7 +13594,7 @@ __metadata: languageName: node linkType: hard -"boxen@npm:^5, boxen@npm:^5.0.1, boxen@npm:^5.1.2": +"boxen@npm:^5, boxen@npm:^5.0.1": version: 5.1.2 resolution: "boxen@npm:5.1.2" dependencies: @@ -18594,15 +13610,6 @@ __metadata: languageName: node linkType: hard -"bplist-parser@npm:^0.1.0": - version: 0.1.1 - resolution: "bplist-parser@npm:0.1.1" - dependencies: - big-integer: ^1.6.7 - checksum: cd50206f956e74f6e46cb5ed14be5eb00b2e14676ea3dd36703470715177a2770fc22032eca63a36adb3b56a1e51138a95bb0fc6849a78c21e92caeedf219ea7 - languageName: node - linkType: hard - "bplist-parser@npm:^0.2.0": version: 0.2.0 resolution: "bplist-parser@npm:0.2.0" @@ -18667,13 +13674,6 @@ __metadata: languageName: node linkType: hard -"brorand@npm:^1.0.1, brorand@npm:^1.1.0": - version: 1.1.0 - resolution: "brorand@npm:1.1.0" - checksum: 6f366d7c4990f82c366e3878492ba9a372a73163c09871e80d82fb4ae0d23f9f8924cb8a662330308206e6b3b76ba1d528b4601c9ef73c2166b440b2ea3b7571 - languageName: node - linkType: hard - "brotli-size@npm:^4.0.0": version: 4.0.0 resolution: "brotli-size@npm:4.0.0" @@ -18706,70 +13706,6 @@ __metadata: languageName: node linkType: hard -"browserify-aes@npm:^1.0.0, browserify-aes@npm:^1.0.4": - version: 1.2.0 - resolution: "browserify-aes@npm:1.2.0" - dependencies: - buffer-xor: ^1.0.3 - cipher-base: ^1.0.0 - create-hash: ^1.1.0 - evp_bytestokey: ^1.0.3 - inherits: ^2.0.1 - safe-buffer: ^5.0.1 - checksum: 967f2ae60d610b7b252a4cbb55a7a3331c78293c94b4dd9c264d384ca93354c089b3af9c0dd023534efdc74ffbc82510f7ad4399cf82bc37bc07052eea485f18 - languageName: node - linkType: hard - -"browserify-cipher@npm:^1.0.0": - version: 1.0.1 - resolution: "browserify-cipher@npm:1.0.1" - dependencies: - browserify-aes: ^1.0.4 - browserify-des: ^1.0.0 - evp_bytestokey: ^1.0.0 - checksum: aa256dcb42bc53a67168bbc94ab85d243b0a3b56109dee3b51230b7d010d9b78985ffc1fb36e145c6e4db151f888076c1cfc207baf1525d3e375cbe8187fe27d - languageName: node - linkType: hard - -"browserify-des@npm:^1.0.0": - version: 1.0.2 - resolution: "browserify-des@npm:1.0.2" - dependencies: - cipher-base: ^1.0.1 - des.js: ^1.0.0 - inherits: ^2.0.1 - safe-buffer: ^5.1.2 - checksum: 943eb5d4045eff80a6cde5be4e5fbb1f2d5002126b5a4789c3c1aae3cdddb1eb92b00fb92277f512288e5c6af330730b1dbabcf7ce0923e749e151fcee5a074d - languageName: node - linkType: hard - -"browserify-rsa@npm:^4.0.0, browserify-rsa@npm:^4.0.1": - version: 4.1.0 - resolution: "browserify-rsa@npm:4.1.0" - dependencies: - bn.js: ^5.0.0 - randombytes: ^2.0.1 - checksum: fb2b5a8279d8a567a28d8ee03fb62e448428a906bab5c3dc9e9c3253ace551b5ea271db15e566ac78f1b1d71b243559031446604168b9235c351a32cae99d02a - languageName: node - linkType: hard - -"browserify-sign@npm:^4.0.0": - version: 4.2.1 - resolution: "browserify-sign@npm:4.2.1" - dependencies: - bn.js: ^5.1.1 - browserify-rsa: ^4.0.1 - create-hash: ^1.2.0 - create-hmac: ^1.1.7 - elliptic: ^6.5.3 - inherits: ^2.0.4 - parse-asn1: ^5.1.5 - readable-stream: ^3.6.0 - safe-buffer: ^5.2.0 - checksum: 8f00a370e3e97060977dc58e51251d3ca398ee73523994a44430321e8de2c7d85395362d59014b2b07efe4190f369baee2ff28eb8f405ff4660b776651cf052d - languageName: node - linkType: hard - "browserify-zlib@npm:^0.1.4": version: 0.1.4 resolution: "browserify-zlib@npm:0.1.4" @@ -18779,15 +13715,6 @@ __metadata: languageName: node linkType: hard -"browserify-zlib@npm:^0.2.0": - version: 0.2.0 - resolution: "browserify-zlib@npm:0.2.0" - dependencies: - pako: ~1.0.5 - checksum: 9ab10b6dc732c6c5ec8ebcbe5cb7fe1467f97402c9b2140113f47b5f187b9438f93a8e065d8baf8b929323c18324fbf1105af479ee86d9d36cab7d7ef3424ad9 - languageName: node - linkType: hard - "browserslist-generator@npm:^2.1.0": version: 2.1.0 resolution: "browserslist-generator@npm:2.1.0" @@ -18806,49 +13733,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.12.0, browserslist@npm:^4.14.5, browserslist@npm:^4.21.3, browserslist@npm:^4.21.4, browserslist@npm:^4.21.5, browserslist@npm:^4.21.9": - version: 4.21.9 - resolution: "browserslist@npm:4.21.9" - dependencies: - caniuse-lite: ^1.0.30001503 - electron-to-chromium: ^1.4.431 - node-releases: ^2.0.12 - update-browserslist-db: ^1.0.11 - bin: - browserslist: cli.js - checksum: 903189787141f645f47ec46ec482dc85985d1297948062690dc2ea8480eb98fd6213507234eb17177825acaae49c53888445910f1af984abce5373fb65c270b8 - languageName: node - linkType: hard - -"browserslist@npm:^4.21.10, browserslist@npm:^4.22.1": - version: 4.22.1 - resolution: "browserslist@npm:4.22.1" - dependencies: - caniuse-lite: ^1.0.30001541 - electron-to-chromium: ^1.4.535 - node-releases: ^2.0.13 - update-browserslist-db: ^1.0.13 - bin: - browserslist: cli.js - checksum: 6810f2d63f171d0b7b8d38cf091708e00cb31525501810a507839607839320d66e657293b0aa3d7f051ecbc025cb07390a90c037682c1d05d12604991e41050b - languageName: node - linkType: hard - -"browserslist@npm:^4.22.2": - version: 4.22.2 - resolution: "browserslist@npm:4.22.2" - dependencies: - caniuse-lite: ^1.0.30001565 - electron-to-chromium: ^1.4.601 - node-releases: ^2.0.14 - update-browserslist-db: ^1.0.13 - bin: - browserslist: cli.js - checksum: 2a331aab90503130043ca41dd5d281fa1e89d5e076d07a2d75e76bf4d693bd56e73d5abcd8c4f39119da6328d450578c216cf1cd5c99b82d8a90a2ae6271b465 - languageName: node - linkType: hard - -"browserslist@npm:^4.23.0": +"browserslist@npm:^4.0.0, browserslist@npm:^4.12.0, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.22.2, browserslist@npm:^4.23.0": version: 4.23.0 resolution: "browserslist@npm:4.23.0" dependencies: @@ -18908,24 +13793,6 @@ __metadata: languageName: node linkType: hard -"buffer-xor@npm:^1.0.3": - version: 1.0.3 - resolution: "buffer-xor@npm:1.0.3" - checksum: fd269d0e0bf71ecac3146187cfc79edc9dbb054e2ee69b4d97dfb857c6d997c33de391696d04bdd669272751fa48e7872a22f3a6c7b07d6c0bc31dbe02a4075c - languageName: node - linkType: hard - -"buffer@npm:^4.3.0": - version: 4.9.2 - resolution: "buffer@npm:4.9.2" - dependencies: - base64-js: ^1.0.2 - ieee754: ^1.1.4 - isarray: ^1.0.0 - checksum: dc443d7e7caab23816b58aacdde710b72f525ad6eecd7d738fcaa29f6d6c12e8d9c13fed7219fd502be51ecf0615f5c077d4bdc6f9308dde2e53f8e5393c5b21 - languageName: node - linkType: hard - "buffer@npm:^5.5.0, buffer@npm:^5.6.0": version: 5.7.1 resolution: "buffer@npm:5.7.1" @@ -18953,25 +13820,18 @@ __metadata: languageName: node linkType: hard -"builtin-status-codes@npm:^3.0.0": - version: 3.0.0 - resolution: "builtin-status-codes@npm:3.0.0" - checksum: c37bbba11a34c4431e56bd681b175512e99147defbe2358318d8152b3a01df7bf25e0305873947e5b350073d5ef41a364a22b37e48f1fb6d2fe6d5286a0f348c - languageName: node - linkType: hard - "bullmq@npm:^5.4.2": - version: 5.7.3 - resolution: "bullmq@npm:5.7.3" + version: 5.7.8 + resolution: "bullmq@npm:5.7.8" dependencies: cron-parser: ^4.6.0 - ioredis: ^5.3.2 + ioredis: ^5.4.1 msgpackr: ^1.10.1 node-abort-controller: ^3.1.1 semver: ^7.5.4 tslib: ^2.0.0 uuid: ^9.0.0 - checksum: eade5853736a9ad606fe6f7b0d000585d7122ca3f5e4b71965cef448b77f3b8748f90ea420b90cf8e2fd7db737197946cc57ffbdb7ea8e8e4945875cc54b74d5 + checksum: 49471348f6c645c58aa3105ab39a942f7537c0bbfdd3d4e9ba4c254eab941c0b3bb3301abe5dea0d19457b53661dbdb711566a34bb23d689b50bec111d9c1e98 languageName: node linkType: hard @@ -18985,13 +13845,13 @@ __metadata: linkType: hard "bundle-require@npm:^4.0.0": - version: 4.0.1 - resolution: "bundle-require@npm:4.0.1" + version: 4.1.0 + resolution: "bundle-require@npm:4.1.0" dependencies: load-tsconfig: ^0.2.3 peerDependencies: esbuild: ">=0.17" - checksum: 92a22b0618bfc4017a7873ac6f989b8fb8c4e2d483f3b05cc3e066a8410934e43f459436113c31fe19f247760bd7f9fd60c15a7a23269d749f8dda7b1b67a01b + checksum: d16f324564f9f771ac78feac8080fe9d3d5ec4008b6ba456524db5845c61d4561518d50ca7e93d371a9f197c6a55aa8533cca97de4a64a9367da058e17e2b9d6 languageName: node linkType: hard @@ -19048,28 +13908,6 @@ __metadata: languageName: node linkType: hard -"c8@npm:^7.6.0": - version: 7.14.0 - resolution: "c8@npm:7.14.0" - dependencies: - "@bcoe/v8-coverage": ^0.2.3 - "@istanbuljs/schema": ^0.1.3 - find-up: ^5.0.0 - foreground-child: ^2.0.0 - istanbul-lib-coverage: ^3.2.0 - istanbul-lib-report: ^3.0.0 - istanbul-reports: ^3.1.4 - rimraf: ^3.0.2 - test-exclude: ^6.0.0 - v8-to-istanbul: ^9.0.0 - yargs: ^16.2.0 - yargs-parser: ^20.2.9 - bin: - c8: bin/c8.js - checksum: 8946f55f2dcc85bf146f429a3deeede78502da245e515a2d181342475d8d8698b4055ec1d9b887ab8e1615f49c1a2af4d63557e68b2005844572fb785991e148 - languageName: node - linkType: hard - "cac@npm:^6.7.12, cac@npm:^6.7.14": version: 6.7.14 resolution: "cac@npm:6.7.14" @@ -19077,72 +13915,23 @@ __metadata: languageName: node linkType: hard -"cacache@npm:^12.0.2": - version: 12.0.4 - resolution: "cacache@npm:12.0.4" - dependencies: - bluebird: ^3.5.5 - chownr: ^1.1.1 - figgy-pudding: ^3.5.1 - glob: ^7.1.4 - graceful-fs: ^4.1.15 - infer-owner: ^1.0.3 - lru-cache: ^5.1.1 - mississippi: ^3.0.0 - mkdirp: ^0.5.1 - move-concurrently: ^1.0.1 - promise-inflight: ^1.0.1 - rimraf: ^2.6.3 - ssri: ^6.0.1 - unique-filename: ^1.1.1 - y18n: ^4.0.0 - checksum: b4b0aa49e3fbd3ca92f71bc62923e4afce31fd687b31d5ba524b2a54b36e96a8b027165599307dda5e4a6f7268cc951b77ca170efa00c1b72761f9daae51fdfb - languageName: node - linkType: hard - -"cacache@npm:^15.0.5": - version: 15.3.0 - resolution: "cacache@npm:15.3.0" - dependencies: - "@npmcli/fs": ^1.0.0 - "@npmcli/move-file": ^1.0.1 - chownr: ^2.0.0 - fs-minipass: ^2.0.0 - glob: ^7.1.4 - infer-owner: ^1.0.4 - lru-cache: ^6.0.0 - minipass: ^3.1.1 - minipass-collect: ^1.0.2 - minipass-flush: ^1.0.5 - minipass-pipeline: ^1.2.2 - mkdirp: ^1.0.3 - p-map: ^4.0.0 - promise-inflight: ^1.0.1 - rimraf: ^3.0.2 - ssri: ^8.0.1 - tar: ^6.0.2 - unique-filename: ^1.1.1 - checksum: 886fcc0acc4f6fd5cd142d373d8276267bc6d655d7c4ce60726fbbec10854de3395ee19bbf9e7e73308cdca9fdad0ad55060ff3bd16c6d4165c5b8d21515e1d8 - languageName: node - linkType: hard - -"cacache@npm:^17.0.0": - version: 17.1.3 - resolution: "cacache@npm:17.1.3" +"cacache@npm:^18.0.0": + version: 18.0.3 + resolution: "cacache@npm:18.0.3" dependencies: "@npmcli/fs": ^3.1.0 fs-minipass: ^3.0.0 glob: ^10.2.2 - lru-cache: ^7.7.1 - minipass: ^5.0.0 - minipass-collect: ^1.0.2 + lru-cache: ^10.0.1 + minipass: ^7.0.3 + minipass-collect: ^2.0.1 minipass-flush: ^1.0.5 minipass-pipeline: ^1.2.4 p-map: ^4.0.0 ssri: ^10.0.0 tar: ^6.1.11 unique-filename: ^3.0.0 - checksum: fcb0843c8e152b0e1440328508a2c0d6435c431198155e31daa591b348a1739b089ce2a72a4528690ed10a2bf086c180ee4980e2116457131b4c8a6e65e10976 + checksum: dfda92840bb371fb66b88c087c61a74544363b37a265023223a99965b16a16bbb87661fe4948718d79df6e0cc04e85e62784fbcf1832b2a5e54ff4c46fbb45b7 languageName: node linkType: hard @@ -19185,17 +13974,7 @@ __metadata: languageName: node linkType: hard -"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2": - version: 1.0.2 - resolution: "call-bind@npm:1.0.2" - dependencies: - function-bind: ^1.1.1 - get-intrinsic: ^1.0.2 - checksum: 74ba3f31e715456e22e451d8d098779b861eba3c7cac0d9b510049aced70d75c231ba05071f97e1812c98e34e2bee734c0c6126653e0088c2d9819ca047f4073 - languageName: node - linkType: hard - -"call-bind@npm:^1.0.7": +"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.6, call-bind@npm:^1.0.7": version: 1.0.7 resolution: "call-bind@npm:1.0.7" dependencies: @@ -19222,7 +14001,7 @@ __metadata: languageName: node linkType: hard -"camel-case@npm:^4.1.1, camel-case@npm:^4.1.2": +"camel-case@npm:^4.1.2": version: 4.1.2 resolution: "camel-case@npm:4.1.2" dependencies: @@ -19232,23 +14011,13 @@ __metadata: languageName: node linkType: hard -"camelcase-css@npm:2.0.1, camelcase-css@npm:^2.0.1": +"camelcase-css@npm:^2.0.1": version: 2.0.1 resolution: "camelcase-css@npm:2.0.1" checksum: 1a1a3137e8a781e6cbeaeab75634c60ffd8e27850de410c162cce222ea331cd1ba5364e8fb21c95e5ca76f52ac34b81a090925ca00a87221355746d049c6e273 languageName: node linkType: hard -"camelcase-keys@npm:^2.0.0": - version: 2.1.0 - resolution: "camelcase-keys@npm:2.1.0" - dependencies: - camelcase: ^2.0.0 - map-obj: ^1.0.0 - checksum: d9431f8b5ac52644cfc45377c0d3897f045137d645c8890bd2bfb48c282d22e76644974198dbba3a2d96b33f9bf3af07aacb712b0dd6d2671330a7e2531b72f9 - languageName: node - linkType: hard - "camelcase-keys@npm:^6.2.2": version: 6.2.2 resolution: "camelcase-keys@npm:6.2.2" @@ -19260,13 +14029,6 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:^2.0.0": - version: 2.1.1 - resolution: "camelcase@npm:2.1.1" - checksum: 610db65fa7dd50a400525ec2188fd65a1939dda4afe5de7d08608670013269c3743c3737fb0f138d1df8aa74e257cc83e3b756e776b604af16dac297b4a0d054 - languageName: node - linkType: hard - "camelcase@npm:^5.0.0, camelcase@npm:^5.3.1": version: 5.3.1 resolution: "camelcase@npm:5.3.1" @@ -19300,38 +14062,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001109, caniuse-lite@npm:^1.0.30001464, caniuse-lite@npm:^1.0.30001503": - version: 1.0.30001511 - resolution: "caniuse-lite@npm:1.0.30001511" - checksum: c7dc67cdd13f57d9a1bd66d438c8eb2194c8903b9199fc5ccfffe972b483de7ca2c2652543f789a7abb21356aec14d3bc83efc93d72be4c38b178b9efa7f886e - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001518, caniuse-lite@npm:^1.0.30001541": - version: 1.0.30001554 - resolution: "caniuse-lite@npm:1.0.30001554" - checksum: 1ef7647d005ff4b6d2797dd3d4d47cf66733531999e40b50dcbe3c84f59f8ecac92ffba7ca35b932bd1ce5f8aedbf22f3bd464898be00874e3db99ef869bd726 - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001565": - version: 1.0.30001572 - resolution: "caniuse-lite@npm:1.0.30001572" - checksum: 7d02570fa576b158d96739f2c65ea3ad22e90a8b028a343902de1f13b7db8512144870f1d29ec5e9ae7189d96158d9643871b6e902e6680a06b27a9afe556da2 - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001578": - version: 1.0.30001583 - resolution: "caniuse-lite@npm:1.0.30001583" - checksum: 9ce61437e7a0c8e69bdb3480962dca7d7a9e9fa8d7c56ae411454d8b101d7c83d71f6c7fa74450c131f6c14e35e347042b3e1787b15edbfaba0e05fd75ab2625 - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001587, caniuse-lite@npm:^1.0.30001599": - version: 1.0.30001610 - resolution: "caniuse-lite@npm:1.0.30001610" - checksum: 015956a0bf2e3e233da3dc00c5632bbb4d416bcd6ced2f839e33e45b197a856234f97cb046e7427b83d7e3a3d6df314dfab1c86eb9d970970e00ad85a50b4933 +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001518, caniuse-lite@npm:^1.0.30001587, caniuse-lite@npm:^1.0.30001599": + version: 1.0.30001616 + resolution: "caniuse-lite@npm:1.0.30001616" + checksum: 4c29f0a6c65ec888fadf5112cffc3b162872b74dce6ca4964d242c1c0fd05ab284f8e500f85739d5c96573589cf6e0e911424646b1009440a7c142ef6a5187ce languageName: node linkType: hard @@ -19356,13 +14090,6 @@ __metadata: languageName: node linkType: hard -"case-sensitive-paths-webpack-plugin@npm:^2.3.0": - version: 2.4.0 - resolution: "case-sensitive-paths-webpack-plugin@npm:2.4.0" - checksum: 310dab619b661a7fa44ed773870be6d6d7373faff6953ad92720f9553e2579e46dda5b9a79eae6d25ff3733cc15aa466b96e5811af16213f23c115aa220b4ab4 - languageName: node - linkType: hard - "caseless@npm:~0.12.0": version: 0.12.0 resolution: "caseless@npm:0.12.0" @@ -19370,16 +14097,9 @@ __metadata: languageName: node linkType: hard -"ccount@npm:^1.0.0": - version: 1.1.0 - resolution: "ccount@npm:1.1.0" - checksum: 9ccfddfa45c8d6d01411b8e30d2ce03c55c33f32a69bdb84ee44d743427cdb01b03159954917023d0dac960c34973ba42626bb9fa883491ebb663a53a6713d43 - languageName: node - linkType: hard - "chai@npm:^4.3.7": - version: 4.3.10 - resolution: "chai@npm:4.3.10" + version: 4.4.1 + resolution: "chai@npm:4.4.1" dependencies: assertion-error: ^1.1.0 check-error: ^1.0.3 @@ -19388,7 +14108,7 @@ __metadata: loupe: ^2.3.6 pathval: ^1.1.1 type-detect: ^4.0.8 - checksum: c887d24f67be6fb554c7ebbde3bb0568697a8833d475e4768296916891ba143f25fc079f6eb34146f3dd5a3279d34c1f387c32c9a6ab288e579f948d9ccf53fe + checksum: 91590a8fe18bd6235dece04ccb2d5b4ecec49984b50924499bdcd7a95c02cb1fd2a689407c19bb854497bde534ef57525cfad6c7fdd2507100fd802fbc2aefbd languageName: node linkType: hard @@ -19412,7 +14132,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^2.0.0, chalk@npm:^2.1.0, chalk@npm:^2.4.1, chalk@npm:^2.4.2": +"chalk@npm:^2.1.0, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: @@ -19450,27 +14170,6 @@ __metadata: languageName: node linkType: hard -"character-entities-legacy@npm:^1.0.0": - version: 1.1.4 - resolution: "character-entities-legacy@npm:1.1.4" - checksum: ea4ca9c29887335eed86d78fc67a640168342b1274da84c097abb0575a253d1265281a5052f9a863979e952bcc267b4ecaaf4fe233a7e1e0d8a47806c65b96c7 - languageName: node - linkType: hard - -"character-entities@npm:^1.0.0": - version: 1.2.4 - resolution: "character-entities@npm:1.2.4" - checksum: ad015c3d7163563b8a0ee1f587fb0ef305ef344e9fd937f79ca51cccc233786a01d591d989d5bf7b2e66b528ac9efba47f3b1897358324e69932f6d4b25adfe1 - languageName: node - linkType: hard - -"character-reference-invalid@npm:^1.0.0": - version: 1.1.4 - resolution: "character-reference-invalid@npm:1.1.4" - checksum: 29f05081c5817bd1e975b0bf61e77b60a40f62ad371d0f0ce0fdb48ab922278bc744d1fbe33771dced751887a8403f265ff634542675c8d7375f6ff4811efd0e - languageName: node - linkType: hard - "chardet@npm:^0.7.0": version: 0.7.0 resolution: "chardet@npm:0.7.0" @@ -19487,7 +14186,7 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:3.5.3, chokidar@npm:^3.4.0, chokidar@npm:^3.4.1, chokidar@npm:^3.4.2, chokidar@npm:^3.5.1, chokidar@npm:^3.5.2, chokidar@npm:^3.5.3": +"chokidar@npm:3.5.3": version: 3.5.3 resolution: "chokidar@npm:3.5.3" dependencies: @@ -19506,26 +14205,22 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:^2.1.8": - version: 2.1.8 - resolution: "chokidar@npm:2.1.8" +"chokidar@npm:^3.4.0, chokidar@npm:^3.4.2, chokidar@npm:^3.5.1, chokidar@npm:^3.5.2, chokidar@npm:^3.5.3, chokidar@npm:^3.6.0": + version: 3.6.0 + resolution: "chokidar@npm:3.6.0" dependencies: - anymatch: ^2.0.0 - async-each: ^1.0.1 - braces: ^2.3.2 - fsevents: ^1.2.7 - glob-parent: ^3.1.0 - inherits: ^2.0.3 - is-binary-path: ^1.0.0 - is-glob: ^4.0.0 - normalize-path: ^3.0.0 - path-is-absolute: ^1.0.0 - readdirp: ^2.2.1 - upath: ^1.1.1 + anymatch: ~3.1.2 + braces: ~3.0.2 + fsevents: ~2.3.2 + glob-parent: ~5.1.2 + is-binary-path: ~2.1.0 + is-glob: ~4.0.1 + normalize-path: ~3.0.0 + readdirp: ~3.6.0 dependenciesMeta: fsevents: optional: true - checksum: 5631cc00080224f9482cf5418dcbea111aec02fa8d81a8cfe37e47b9cf36089e071de52d503647e3a821a01426a40adc926ba899f657af86a51b8f8d4eef12a7 + checksum: 8361dcd013f2ddbe260eacb1f3cb2f2c6f2b0ad118708a343a5ed8158941a39cb8fb1d272e0f389712e74ee90ce8ba864eece9e0e62b9705cb468a2f6d917462 languageName: node linkType: hard @@ -19554,13 +14249,6 @@ __metadata: languageName: node linkType: hard -"chrome-trace-event@npm:^1.0.2": - version: 1.0.3 - resolution: "chrome-trace-event@npm:1.0.3" - checksum: 080ce2d20c2b9e0f8461a380e9585686caa768b1c834a464470c9dc74cda07f27611c7b727a2cd768a9cecd033297fdec4ce01f1e58b62227882c1059dec321c - languageName: node - linkType: hard - "ci-info@npm:^2.0.0": version: 2.0.0 resolution: "ci-info@npm:2.0.0" @@ -19568,20 +14256,19 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^3.1.0, ci-info@npm:^3.2.0": - version: 3.8.0 - resolution: "ci-info@npm:3.8.0" - checksum: 0d3052193b58356372b34ab40d2668c3e62f1006d5ca33726d1d3c423853b19a85508eadde7f5908496fb41448f465263bf61c1ee58b7832cb6a924537e3863a +"ci-info@npm:^3.2.0, ci-info@npm:^3.7.0": + version: 3.9.0 + resolution: "ci-info@npm:3.9.0" + checksum: 6f0109e36e111684291d46123d491bc4e7b7a1934c3a20dea28cba89f1d4a03acd892f5f6a81ed3855c38647e285a150e3c9ba062e38943bef57fee6c1554c3a languageName: node linkType: hard -"cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3": - version: 1.0.4 - resolution: "cipher-base@npm:1.0.4" +"citty@npm:^0.1.6": + version: 0.1.6 + resolution: "citty@npm:0.1.6" dependencies: - inherits: ^2.0.1 - safe-buffer: ^5.0.1 - checksum: d8d005f8b64d8a77b3d3ce531301ae7b45902c9cab4ec8b66bdbd2bf2a1d9fceb9a2133c293eb3c060b2d964da0f14c47fb740366081338aa3795dd1faa8984b + consola: ^3.2.3 + checksum: d26ad82a9a4a8858c7e149d90b878a3eceecd4cfd3e2ed3cd5f9a06212e451fb4f8cbe0fa39a3acb1b3e8f18e22db8ee5def5829384bad50e823d4b301609b48 languageName: node linkType: hard @@ -19593,9 +14280,9 @@ __metadata: linkType: hard "cjs-module-lexer@npm:^1.0.0": - version: 1.2.3 - resolution: "cjs-module-lexer@npm:1.2.3" - checksum: 0de9a9c3fad03a46804c0d38e7b712fb282584a9c7ef1ed44cae22fb71d9bb600309d66a9711ac36a596fd03422f5bb03e021e8f369c12a39fa1786ae531baab + version: 1.3.1 + resolution: "cjs-module-lexer@npm:1.3.1" + checksum: cd98fbf3c7f4272fb0ebf71d08d0c54bc75ce0e30b9d186114e15b4ba791f3d310af65a339eea2a0318599af2818cdd8886d353b43dfab94468f72987397ad16 languageName: node linkType: hard @@ -19619,29 +14306,20 @@ __metadata: linkType: hard "class-validator@npm:^0.14.0": - version: 0.14.0 - resolution: "class-validator@npm:0.14.0" + version: 0.14.1 + resolution: "class-validator@npm:0.14.1" dependencies: - "@types/validator": ^13.7.10 - libphonenumber-js: ^1.10.14 - validator: ^13.7.0 - checksum: 1f7c34052f0c342b1d27c5aec7c42b646bb77a56874acc0d8003e2ad8f0294e7da18b43e9caaac8e8817cbb309cf9f14bcebe4611994390ca4818f3b393783dc + "@types/validator": ^13.11.8 + libphonenumber-js: ^1.10.53 + validator: ^13.9.0 + checksum: 946e914e47548b5081449c720ea6a4877bac63dc960e14fca4b990b56e64efe3802d12f07ec22d6420c290245b72ea2d646939239f2a3b597794e6c4c2a4f2ae languageName: node linkType: hard -"classnames@npm:^2.3.1": - version: 2.3.2 - resolution: "classnames@npm:2.3.2" - checksum: cd50ead57b4f97436aaa9f9885c6926323efc7c2bea8e3d4eb10e4e972aa6a1cfca1c7a0e06f8a199ca7498d4339e30bb6002e589e61c9f21248cbf3e8b0b18d - languageName: node - linkType: hard - -"clean-css@npm:^4.2.3": - version: 4.2.4 - resolution: "clean-css@npm:4.2.4" - dependencies: - source-map: ~0.6.0 - checksum: 0e41795fdc9d65e5e17a3b0016d90bf2a653e3a680829b5bcebdbab48604cfe36d96d8af6346338d2c2aca8aa9af024ac4fb752ac3eb5b71bef68a34a129b58a +"classnames@npm:^2.3.2": + version: 2.5.1 + resolution: "classnames@npm:2.5.1" + checksum: afff4f77e62cea2d79c39962980bf316bacb0d7c49e13a21adaadb9221e1c6b9d3cdb829d8bb1b23c406f4e740507f37e1dcf506f7e3b7113d17c5bab787aa69 languageName: node linkType: hard @@ -19711,14 +14389,7 @@ __metadata: languageName: node linkType: hard -"cli-spinners@npm:^2.5.0": - version: 2.9.0 - resolution: "cli-spinners@npm:2.9.0" - checksum: c0d5437acc1ace7361b1c58a4fda3c92c2d8691ff3169ac658ce30faee71280b7aa706c072bcb6d0e380c232f3495f7d5ad4668c1391fe02c4d3a39d37798f44 - languageName: node - linkType: hard - -"cli-spinners@npm:^2.6.1": +"cli-spinners@npm:^2.5.0, cli-spinners@npm:^2.6.1": version: 2.9.2 resolution: "cli-spinners@npm:2.9.2" checksum: 907a1c227ddf0d7a101e7ab8b300affc742ead4b4ebe920a5bf1bc6d45dce2958fcd195eb28fa25275062fe6fa9b109b93b63bc8033396ed3bcb50297008b3a3 @@ -19726,15 +14397,15 @@ __metadata: linkType: hard "cli-table3@npm:^0.6.1": - version: 0.6.3 - resolution: "cli-table3@npm:0.6.3" + version: 0.6.4 + resolution: "cli-table3@npm:0.6.4" dependencies: "@colors/colors": 1.5.0 string-width: ^4.2.0 dependenciesMeta: "@colors/colors": optional: true - checksum: 39e580cb346c2eaf1bd8f4ff055ae644e902b8303c164a1b8894c0dc95941f92e001db51f49649011be987e708d9fa3183ccc2289a4d376a057769664048cc0c + checksum: 8233c3d588db19122ed62a64256c7f0208232d2cece89a6cd7732481887fd9dcef69d976c4719149e77ccbf0a68f637bd5923536adccf6cdea051eeffa0ef1c2 languageName: node linkType: hard @@ -19863,13 +14534,20 @@ __metadata: languageName: node linkType: hard -"clsx@npm:^1.1.0, clsx@npm:^1.1.1, clsx@npm:^1.2.1": +"clsx@npm:^1.1.0, clsx@npm:^1.2.1": version: 1.2.1 resolution: "clsx@npm:1.2.1" checksum: 34dead8bee24f5e96f6e7937d711978380647e936a22e76380290e35486afd8634966ce300fc4b74a32f3762c7d4c0303f442c3e259f4ce02374eb0c82834f27 languageName: node linkType: hard +"clsx@npm:^2.0.0": + version: 2.1.1 + resolution: "clsx@npm:2.1.1" + checksum: c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839 + languageName: node + linkType: hard + "cluster-key-slot@npm:^1.1.0": version: 1.1.2 resolution: "cluster-key-slot@npm:1.1.2" @@ -19878,15 +14556,14 @@ __metadata: linkType: hard "cmdk@npm:^0.2.0": - version: 0.2.0 - resolution: "cmdk@npm:0.2.0" + version: 0.2.1 + resolution: "cmdk@npm:0.2.1" dependencies: "@radix-ui/react-dialog": 1.0.0 - command-score: 0.1.2 peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: bd706c78fc933562acc5723bb4663bad68b34f4e065405de16d400a76ed4c36633de63ac3b6458e8aa93aba10ca5116563d1fc00b9fb298f6876175e190c3479 + checksum: 8cc3f256a5e40f7ac535dd6b3eabfeff2ff817d694dd569047efafb8620fff9575d0612ed023886e98e8f8595947458fee562389b19be2eb2f3c4835117cac7c languageName: node linkType: hard @@ -19904,17 +14581,10 @@ __metadata: languageName: node linkType: hard -"collapse-white-space@npm:^1.0.2": - version: 1.0.6 - resolution: "collapse-white-space@npm:1.0.6" - checksum: 7fd27a883eee1ddd5e39c53fbcd4a42dfe2a65dfac70e2c442d20827f5258202b360a12e99b4f0128c3addd2d64796bb2eb1bb8a3b75d5a2e9c061adb549c36b - languageName: node - linkType: hard - "collect-v8-coverage@npm:^1.0.0": - version: 1.0.1 - resolution: "collect-v8-coverage@npm:1.0.1" - checksum: df8192811a773d10978fd25060124e4228d9a86bab40de3f18df5ce1a3730832351a52ba1c0e3915d5bd638298fc7bc9723760d25f534462746e269a6f0ac91c + version: 1.0.2 + resolution: "collect-v8-coverage@npm:1.0.2" + checksum: ed7008e2e8b6852c5483b444a3ae6e976e088d4335a85aa0a9db2861c5f1d31bd2d7ff97a60469b3388deeba661a619753afbe201279fb159b4b9548ab8269a1 languageName: node linkType: hard @@ -19970,15 +14640,6 @@ __metadata: languageName: node linkType: hard -"color-support@npm:^1.1.2, color-support@npm:^1.1.3": - version: 1.1.3 - resolution: "color-support@npm:1.1.3" - bin: - color-support: bin.js - checksum: 8ffeaa270a784dc382f62d9be0a98581db43e11eee301af14734a6d089bd456478b1a8b3e7db7ca7dc5b18a75f828f775c44074020b51c05fc00e6d0992b1cc6 - languageName: node - linkType: hard - "color@npm:^3.1.3": version: 3.2.1 resolution: "color@npm:3.2.1" @@ -20010,20 +14671,13 @@ __metadata: languageName: node linkType: hard -"colorette@npm:^2.0.16, colorette@npm:^2.0.20": +"colorette@npm:^2.0.16": version: 2.0.20 resolution: "colorette@npm:2.0.20" checksum: e94116ff33b0ff56f3b83b9ace895e5bf87c2a7a47b3401b8c3f3226e050d5ef76cf4072fb3325f9dc24d1698f9b730baf4e05eeaf861d74a1883073f4c98a40 languageName: node linkType: hard -"colors@npm:~1.2.1": - version: 1.2.5 - resolution: "colors@npm:1.2.5" - checksum: f4acebf2d2da9b4f8afb770361d14c01034bcb43add4cae493e7d186dcd7e0c5e2b440520fbfdf636e872606a0eb86b1f69fcf2f087df2876a4e222612539ee0 - languageName: node - linkType: hard - "colorspace@npm:1.1.x": version: 1.1.4 resolution: "colorspace@npm:1.1.4" @@ -20043,20 +14697,6 @@ __metadata: languageName: node linkType: hard -"comma-separated-tokens@npm:^1.0.0": - version: 1.0.8 - resolution: "comma-separated-tokens@npm:1.0.8" - checksum: c3bcfeaa6d50313528a006a40bcc0f9576086665c9b48d4b3a76ddd63e7d6174734386c98be1881cbf6ecfc25e1db61cd775a7b896d2ea7a65de28f83a0f9b17 - languageName: node - linkType: hard - -"command-score@npm:0.1.2": - version: 0.1.2 - resolution: "command-score@npm:0.1.2" - checksum: 0fe355e311f339c217befade6337e734c8e199eaf8442cf65233461134b6bac8a53c85c2c1c929f1b1b8c6125772a50d55991a27ea486cdd846e8c083c852706 - languageName: node - linkType: hard - "commander@npm:*": version: 12.0.0 resolution: "commander@npm:12.0.0" @@ -20092,14 +14732,14 @@ __metadata: languageName: node linkType: hard -"commander@npm:^2.19.0, commander@npm:^2.20.0": +"commander@npm:^2.20.0": version: 2.20.3 resolution: "commander@npm:2.20.3" checksum: 74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288 languageName: node linkType: hard -"commander@npm:^4.0.0, commander@npm:^4.0.1, commander@npm:^4.1.1": +"commander@npm:^4.0.0, commander@npm:^4.0.1": version: 4.1.1 resolution: "commander@npm:4.1.1" checksum: 84a76c08fe6cc08c9c93f62ac573d2907d8e79138999312c92d4155bc2325d487d64d13f669b2000c9f8caf70493c1be2dac74fec3c51d5a04f8bc3ae1830bab @@ -20150,13 +14790,6 @@ __metadata: languageName: node linkType: hard -"common-path-prefix@npm:^3.0.0": - version: 3.0.0 - resolution: "common-path-prefix@npm:3.0.0" - checksum: c4a74294e1b1570f4a8ab435285d185a03976c323caa16359053e749db4fde44e3e6586c29cd051100335e11895767cbbd27ea389108e327d62f38daf4548fdb - languageName: node - linkType: hard - "commondir@npm:^1.0.1": version: 1.0.1 resolution: "commondir@npm:1.0.1" @@ -20176,9 +14809,9 @@ __metadata: linkType: hard "component-emitter@npm:^1.2.0, component-emitter@npm:^1.2.1": - version: 1.3.0 - resolution: "component-emitter@npm:1.3.0" - checksum: 68774a0a3754fb6c0ba53c2e88886dfbd0c773931066abb1d7fd1b0c893b2a838d8f088ab4dca1f18cc1a4fc2e6932019eba3ded2d931b5ba2241ce40e93a24f + version: 1.3.1 + resolution: "component-emitter@npm:1.3.1" + checksum: e4900b1b790b5e76b8d71b328da41482118c0f3523a516a41be598dc2785a07fd721098d9bf6e22d89b19f4fa4e1025160dc00317ea111633a3e4f75c2b86032 languageName: node linkType: hard @@ -20213,7 +14846,7 @@ __metadata: languageName: node linkType: hard -"concat-stream@npm:^1.5.0, concat-stream@npm:^1.5.2, concat-stream@npm:^1.6.2": +"concat-stream@npm:^1.5.2, concat-stream@npm:^1.6.2": version: 1.6.2 resolution: "concat-stream@npm:1.6.2" dependencies: @@ -20234,6 +14867,13 @@ __metadata: languageName: node linkType: hard +"confbox@npm:^0.1.7": + version: 0.1.7 + resolution: "confbox@npm:0.1.7" + checksum: 18b40c2f652196a833f3f1a5db2326a8a579cd14eacabfe637e4fc8cb9b68d7cf296139a38c5e7c688ce5041bf46f9adce05932d43fde44cf7e012840b5da111 + languageName: node + linkType: hard + "configstore@npm:5.0.1, configstore@npm:^5.0.1": version: 5.0.1 resolution: "configstore@npm:5.0.1" @@ -20268,24 +14908,10 @@ __metadata: languageName: node linkType: hard -"console-browserify@npm:^1.1.0": - version: 1.2.0 - resolution: "console-browserify@npm:1.2.0" - checksum: 89b99a53b7d6cee54e1e64fa6b1f7ac24b844b4019c5d39db298637e55c1f4ffa5c165457ad984864de1379df2c8e1886cbbdac85d9dbb6876a9f26c3106f226 - languageName: node - linkType: hard - -"console-control-strings@npm:^1.0.0, console-control-strings@npm:^1.1.0": - version: 1.1.0 - resolution: "console-control-strings@npm:1.1.0" - checksum: 7ab51d30b52d461412cd467721bb82afe695da78fff8f29fe6f6b9cbaac9a2328e27a22a966014df9532100f6dd85370460be8130b9c677891ba36d96a343f50 - languageName: node - linkType: hard - -"constants-browserify@npm:^1.0.0": - version: 1.0.0 - resolution: "constants-browserify@npm:1.0.0" - checksum: ab49b1d59a433ed77c964d90d19e08b2f77213fb823da4729c0baead55e3c597f8f97ebccfdfc47bd896d43854a117d114c849a6f659d9986420e97da0f83ac5 +"consola@npm:^3.2.3": + version: 3.2.3 + resolution: "consola@npm:3.2.3" + checksum: c606220524ec88a05bb1baf557e9e0e04a0c08a9c35d7a08652d99de195c4ddcb6572040a7df57a18ff38bbc13ce9880ad032d56630cef27bef72768ef0ac078 languageName: node linkType: hard @@ -20345,6 +14971,13 @@ __metadata: languageName: node linkType: hard +"cookie-signature@npm:1.0.7": + version: 1.0.7 + resolution: "cookie-signature@npm:1.0.7" + checksum: e7731ad2995ae2efeed6435ec1e22cdd21afef29d300c27281438b1eab2bae04ef0d1a203928c0afec2cee72aa36540b8747406ebe308ad23c8e8cc3c26c9c51 + languageName: node + linkType: hard + "cookie@npm:0.4.0": version: 0.4.0 resolution: "cookie@npm:0.4.0" @@ -20359,17 +14992,10 @@ __metadata: languageName: node linkType: hard -"cookie@npm:0.4.2, cookie@npm:^0.4.1": - version: 0.4.2 - resolution: "cookie@npm:0.4.2" - checksum: beab41fbd7c20175e3a2799ba948c1dcc71ef69f23fe14eeeff59fc09f50c517b0f77098db87dbb4c55da802f9d86ee86cdc1cd3efd87760341551838d53fca2 - languageName: node - linkType: hard - -"cookie@npm:0.5.0": - version: 0.5.0 - resolution: "cookie@npm:0.5.0" - checksum: c01ca3ef8d7b8187bae434434582288681273b5a9ed27521d4d7f9f7928fe0c920df0decd9f9d3bbd2d14ac432b8c8cf42b98b3bdd5bfe0e6edddeebebe8b61d +"cookie@npm:0.6.0": + version: 0.6.0 + resolution: "cookie@npm:0.6.0" + checksum: f2318b31af7a31b4ddb4a678d024514df5e705f9be5909a192d7f116cfb6d45cbacf96a473fa733faa95050e7cff26e7832bb3ef94751592f1387b71c8956686 languageName: node linkType: hard @@ -20390,20 +15016,6 @@ __metadata: languageName: node linkType: hard -"copy-concurrently@npm:^1.0.0": - version: 1.0.5 - resolution: "copy-concurrently@npm:1.0.5" - dependencies: - aproba: ^1.1.1 - fs-write-stream-atomic: ^1.0.8 - iferr: ^0.1.5 - mkdirp: ^0.5.1 - rimraf: ^2.5.4 - run-queue: ^1.0.0 - checksum: c2ce213cb27ee3df584d16eb6c9bfe99cfb531585007533c3e4c752521b4fbf0b2f7f90807d79c496683330808ecd9fdbd9ab9ddfa0913150b7f5097423348ce - languageName: node - linkType: hard - "copy-descriptor@npm:^0.1.0": version: 0.1.1 resolution: "copy-descriptor@npm:0.1.1" @@ -20420,25 +15032,7 @@ __metadata: languageName: node linkType: hard -"core-js-compat@npm:^3.30.1, core-js-compat@npm:^3.30.2, core-js-compat@npm:^3.8.1": - version: 3.31.0 - resolution: "core-js-compat@npm:3.31.0" - dependencies: - browserslist: ^4.21.5 - checksum: 09cca4c2565ddea1fb65324ef17c2dcc61e6c3ec089d8b343e6cbea2b42a9c3ae5e76a42c6faff3759a321c5e7165201db93b7b47912c4c2d1c3d6afad44f7fc - languageName: node - linkType: hard - -"core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.33.1": - version: 3.33.1 - resolution: "core-js-compat@npm:3.33.1" - dependencies: - browserslist: ^4.22.1 - checksum: 9c7361b370eac30756e6ec52469988d62c6110759efa1c85edd15e6b30f05ace8319a9cc0671bf596a98e7e81c67ad693ceaab2691b85cb62c636da1afe8feb9 - languageName: node - linkType: hard - -"core-js-compat@npm:^3.6.2": +"core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.36.1, core-js-compat@npm:^3.6.2": version: 3.37.0 resolution: "core-js-compat@npm:3.37.0" dependencies: @@ -20447,24 +15041,10 @@ __metadata: languageName: node linkType: hard -"core-js-pure@npm:^3.23.3": - version: 3.31.0 - resolution: "core-js-pure@npm:3.31.0" - checksum: fd3f003391bf13722ab40de30c1e0bad9284a2289303ce34db119906eb0f26df677d1f755d07628a1d595d7728c51cea9d41f5dc8fe1b5d4e4214817c557a01a - languageName: node - linkType: hard - -"core-js@npm:^3.0.4, core-js@npm:^3.30.2, core-js@npm:^3.6.5, core-js@npm:^3.7.0, core-js@npm:^3.8.2": - version: 3.31.0 - resolution: "core-js@npm:3.31.0" - checksum: 6216c7ada80b2468b1297d844fa99a99da97d6156cb05270b3627d8c463fb8c17baeff74ef204ef1c905712930fe82740ba2a74e2f957e4909fd241416fe5735 - languageName: node - linkType: hard - -"core-js@npm:^3.32.1": - version: 3.35.1 - resolution: "core-js@npm:3.35.1" - checksum: ebc8e22c36d13bcf2140cbc1d8ad65d1b08192bff4c43ade70c72eac103cb4dcfbc521f2b1ad1c74881b0a4353e64986537893ae4f07888e49228340efa13ae6 +"core-js@npm:^3.30.2, core-js@npm:^3.32.1, core-js@npm:^3.6.5, core-js@npm:^3.7.0": + version: 3.37.0 + resolution: "core-js@npm:3.37.0" + checksum: 7e00331f346318ca3f595c08ce9e74ddae744715aef137486c1399163afd79792fb94c3161280863adfdc3e30f8026912d56bd3036f93cacfc689d33e185f2ee languageName: node linkType: hard @@ -20492,19 +15072,6 @@ __metadata: languageName: node linkType: hard -"cosmiconfig@npm:^6.0.0": - version: 6.0.0 - resolution: "cosmiconfig@npm:6.0.0" - dependencies: - "@types/parse-json": ^4.0.0 - import-fresh: ^3.1.0 - parse-json: ^5.0.0 - path-type: ^4.0.0 - yaml: ^1.7.2 - checksum: 666ed8732d0bf7d7fe6f8516c8ee6041e0622032e8fa26201577b883d2767ad105d03f38b34b93d1f02f26b22a89e7bab4443b9d2e7f931f48d0e944ffa038b5 - languageName: node - linkType: hard - "cosmiconfig@npm:^7.0.0, cosmiconfig@npm:^7.0.1": version: 7.1.0 resolution: "cosmiconfig@npm:7.1.0" @@ -20518,81 +15085,20 @@ __metadata: languageName: node linkType: hard -"cosmiconfig@npm:^8.1.3, cosmiconfig@npm:^8.2.0": - version: 8.2.0 - resolution: "cosmiconfig@npm:8.2.0" +"cosmiconfig@npm:^8.1.3, cosmiconfig@npm:^8.3.5": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" dependencies: - import-fresh: ^3.2.1 + import-fresh: ^3.3.0 js-yaml: ^4.1.0 - parse-json: ^5.0.0 + parse-json: ^5.2.0 path-type: ^4.0.0 - checksum: 4180aa6d1881b75ba591b2fc04b022741a3a4b67e9e243c0eb8d169b6e1efbd3cdf7e8ca19243c0f2e53a9d59ac3eccd5cad5f95f487fcbf4e740f9e86745747 - languageName: node - linkType: hard - -"cp-file@npm:^7.0.0": - version: 7.0.0 - resolution: "cp-file@npm:7.0.0" - dependencies: - graceful-fs: ^4.1.2 - make-dir: ^3.0.0 - nested-error-stacks: ^2.0.0 - p-event: ^4.1.0 - checksum: db3ef3e3e466742f392ae71edb9b2cdbb314e855d97630a65de57bc1097bacf6e844f6d9d44882b8678c0de26ba7e656c2c915960435970067823372e807eafa - languageName: node - linkType: hard - -"cpy@npm:^8.1.2": - version: 8.1.2 - resolution: "cpy@npm:8.1.2" - dependencies: - arrify: ^2.0.1 - cp-file: ^7.0.0 - globby: ^9.2.0 - has-glob: ^1.0.0 - junk: ^3.1.0 - nested-error-stacks: ^2.1.0 - p-all: ^2.1.0 - p-filter: ^2.1.0 - p-map: ^3.0.0 - checksum: 84611fdd526a0582ae501a0fa1e1d55e16348c69110eb17be5fc0c087b7b2aa6caec014286b669e4f123750d01e0c4db77d32fdcdb9840c3df4d161a137a345a - languageName: node - linkType: hard - -"create-ecdh@npm:^4.0.0": - version: 4.0.4 - resolution: "create-ecdh@npm:4.0.4" - dependencies: - bn.js: ^4.1.0 - elliptic: ^6.5.3 - checksum: 77b11a51360fec9c3bce7a76288fc0deba4b9c838d5fb354b3e40c59194d23d66efe6355fd4b81df7580da0661e1334a235a2a5c040b7569ba97db428d466e7f - languageName: node - linkType: hard - -"create-hash@npm:^1.1.0, create-hash@npm:^1.1.2, create-hash@npm:^1.2.0": - version: 1.2.0 - resolution: "create-hash@npm:1.2.0" - dependencies: - cipher-base: ^1.0.1 - inherits: ^2.0.1 - md5.js: ^1.3.4 - ripemd160: ^2.0.1 - sha.js: ^2.4.0 - checksum: d402e60e65e70e5083cb57af96d89567954d0669e90550d7cec58b56d49c4b193d35c43cec8338bc72358198b8cbf2f0cac14775b651e99238e1cf411490f915 - languageName: node - linkType: hard - -"create-hmac@npm:^1.1.0, create-hmac@npm:^1.1.4, create-hmac@npm:^1.1.7": - version: 1.1.7 - resolution: "create-hmac@npm:1.1.7" - dependencies: - cipher-base: ^1.0.3 - create-hash: ^1.1.0 - inherits: ^2.0.1 - ripemd160: ^2.0.0 - safe-buffer: ^5.0.1 - sha.js: ^2.4.8 - checksum: 24332bab51011652a9a0a6d160eed1e8caa091b802335324ae056b0dcb5acbc9fcf173cf10d128eba8548c3ce98dfa4eadaa01bd02f44a34414baee26b651835 + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 0382a9ed13208f8bfc22ca2f62b364855207dffdb73dc26e150ade78c3093f1cf56172df2dd460c8caf2afa91c0ed4ec8a88c62f8f9cd1cf423d26506aa8797a languageName: node linkType: hard @@ -20666,11 +15172,11 @@ __metadata: linkType: hard "cron-parser@npm:^4.2.0, cron-parser@npm:^4.6.0": - version: 4.8.1 - resolution: "cron-parser@npm:4.8.1" + version: 4.9.0 + resolution: "cron-parser@npm:4.9.0" dependencies: luxon: ^3.2.1 - checksum: d14bb09277969085068e97b9d65b71175f66065c842f11499890903ac137d476e7d349cf2c026d8e53ac4a5503101ca1f96b6ecfb646063a1ed2440533729776 + checksum: 348622bdcd1a15695b61fc33af8a60133e5913a85cf99f6344367579e7002896514ba3b0a9d6bb569b02667d6b06836722bf2295fcd101b3de378f71d37bed0b languageName: node linkType: hard @@ -20707,12 +15213,12 @@ __metadata: languageName: node linkType: hard -"cross-fetch@npm:^3.1.5": - version: 3.1.8 - resolution: "cross-fetch@npm:3.1.8" +"cross-inspect@npm:1.0.0": + version: 1.0.0 + resolution: "cross-inspect@npm:1.0.0" dependencies: - node-fetch: ^2.6.12 - checksum: 4c5e022ffe6abdf380faa6e2373c0c4ed7ef75e105c95c972b6f627c3f083170b6886f19fb488a7fa93971f4f69dcc890f122b0d97f0bf5f41ca1d9a8f58c8af + tslib: ^2.4.0 + checksum: 53530865c357c69a5a0543e2f2c61d3d46c9c316a19169372f5094cfb0a7c7e674f2daf2d5253a6731dfd9a8538aa4a4e13c6b4613b6f72b48bb0c41d2015ff4 languageName: node linkType: hard @@ -20760,25 +15266,6 @@ __metadata: languageName: node linkType: hard -"crypto-browserify@npm:^3.11.0": - version: 3.12.0 - resolution: "crypto-browserify@npm:3.12.0" - dependencies: - browserify-cipher: ^1.0.0 - browserify-sign: ^4.0.0 - create-ecdh: ^4.0.0 - create-hash: ^1.1.0 - create-hmac: ^1.1.0 - diffie-hellman: ^5.0.0 - inherits: ^2.0.1 - pbkdf2: ^3.0.3 - public-encrypt: ^4.0.0 - randombytes: ^2.0.0 - randomfill: ^1.0.3 - checksum: 0c20198886576050a6aa5ba6ae42f2b82778bfba1753d80c5e7a090836890dc372bdc780986b2568b4fb8ed2a91c958e61db1f0b6b1cc96af4bd03ffc298ba92 - languageName: node - linkType: hard - "crypto-random-string@npm:^2.0.0": version: 2.0.0 resolution: "crypto-random-string@npm:2.0.0" @@ -20803,52 +15290,35 @@ __metadata: linkType: hard "css-declaration-sorter@npm:^6.3.1": - version: 6.4.0 - resolution: "css-declaration-sorter@npm:6.4.0" + version: 6.4.1 + resolution: "css-declaration-sorter@npm:6.4.1" peerDependencies: postcss: ^8.0.9 - checksum: aef4d5927e576bae04349457be0607af44525cf5f4b28a91843c7b7f28fcbb302ba149385bb0e2172380556994e31680c5177b42d03502c417789b139e20cbc2 - languageName: node - linkType: hard - -"css-loader@npm:^3.6.0": - version: 3.6.0 - resolution: "css-loader@npm:3.6.0" - dependencies: - camelcase: ^5.3.1 - cssesc: ^3.0.0 - icss-utils: ^4.1.1 - loader-utils: ^1.2.3 - normalize-path: ^3.0.0 - postcss: ^7.0.32 - postcss-modules-extract-imports: ^2.0.0 - postcss-modules-local-by-default: ^3.0.2 - postcss-modules-scope: ^2.2.0 - postcss-modules-values: ^3.0.0 - postcss-value-parser: ^4.1.0 - schema-utils: ^2.7.0 - semver: ^6.3.0 - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: ba9065a63f7531d50197207f2c9abb4d75f7e46db27bcfeb6b615a9fb1b1bf48ef4ccdf0f161ff6d35b6fe8752ee3259ee8eeca492666fd2703277d4d3c83534 + checksum: b8b664338dac528266a1ed9b27927ac51a907fb16bc1954fa9038b5286c442603bd494cc920c6a3616111309d18ee6b5a85b6d9927938efc942af452a5145160 languageName: node linkType: hard "css-loader@npm:^6.7.3": - version: 6.8.1 - resolution: "css-loader@npm:6.8.1" + version: 6.11.0 + resolution: "css-loader@npm:6.11.0" dependencies: icss-utils: ^5.1.0 - postcss: ^8.4.21 - postcss-modules-extract-imports: ^3.0.0 - postcss-modules-local-by-default: ^4.0.3 - postcss-modules-scope: ^3.0.0 + postcss: ^8.4.33 + postcss-modules-extract-imports: ^3.1.0 + postcss-modules-local-by-default: ^4.0.5 + postcss-modules-scope: ^3.2.0 postcss-modules-values: ^4.0.0 postcss-value-parser: ^4.2.0 - semver: ^7.3.8 + semver: ^7.5.4 peerDependencies: + "@rspack/core": 0.x || 1.x webpack: ^5.0.0 - checksum: a6e23de4ec1d2832f10b8ca3cfec6b6097a97ca3c73f64338ae5cd110ac270f1b218ff0273d39f677a7a561f1a9d9b0d332274664d0991bcfafaae162c2669c4 + peerDependenciesMeta: + "@rspack/core": + optional: true + webpack: + optional: true + checksum: bb52434138085fed06a33e2ffbdae9ee9014ad23bf60f59d6b7ee67f28f26c6b1764024d3030bd19fd884d6ee6ee2224eaed64ad19eb18fbbb23d148d353a965 languageName: node linkType: hard @@ -20899,7 +15369,7 @@ __metadata: languageName: node linkType: hard -"css-tree@npm:^2.2.1": +"css-tree@npm:^2.3.1": version: 2.3.1 resolution: "css-tree@npm:2.3.1" dependencies: @@ -21060,13 +15530,20 @@ __metadata: languageName: node linkType: hard -"csstype@npm:3.1.2, csstype@npm:^3.0.2": +"csstype@npm:3.1.2": version: 3.1.2 resolution: "csstype@npm:3.1.2" checksum: 32c038af259897c807ac738d9eab16b3d86747c72b09d5c740978e06f067f9b7b1737e1b75e407c7ab1fe1543dc95f20e202b4786aeb1b8d3bdf5d5ce655e6c6 languageName: node linkType: hard +"csstype@npm:^3.0.2": + version: 3.1.3 + resolution: "csstype@npm:3.1.3" + checksum: 80c089d6f7e0c5b2bd83cf0539ab41474198579584fa10d86d0cafe0642202343cbc119e076a0b1aece191989477081415d66c9fefbf3c957fc2fc4b7009f248 + languageName: node + linkType: hard + "csv-generate@npm:^3.4.3": version: 3.4.3 resolution: "csv-generate@npm:3.4.3" @@ -21100,15 +15577,6 @@ __metadata: languageName: node linkType: hard -"currently-unhandled@npm:^0.4.1": - version: 0.4.1 - resolution: "currently-unhandled@npm:0.4.1" - dependencies: - array-find-index: ^1.0.1 - checksum: 32d197689ec32f035910202c1abb0dc6424dce01d7b51779c685119b380d98535c110ffff67a262fc7e367612a7dfd30d3d3055f9a6634b5a9dd1302de7ef11c - languageName: node - linkType: hard - "cva@npm:1.0.0-beta.1": version: 1.0.0-beta.1 resolution: "cva@npm:1.0.0-beta.1" @@ -21123,13 +15591,6 @@ __metadata: languageName: node linkType: hard -"cyclist@npm:^1.0.1": - version: 1.0.2 - resolution: "cyclist@npm:1.0.2" - checksum: 163e2f7207180ccf2bb5a6ca8a7360469c13fad631509ef96de02397266b3a42089e2b2b51b97d3d8fdc4709d2fbe651c309670e5cc28b0ae445b1e5a34a98e2 - languageName: node - linkType: hard - "dashdash@npm:^1.12.0": version: 1.14.1 resolution: "dashdash@npm:1.14.1" @@ -21190,6 +15651,39 @@ __metadata: languageName: node linkType: hard +"data-view-buffer@npm:^1.0.1": + version: 1.0.1 + resolution: "data-view-buffer@npm:1.0.1" + dependencies: + call-bind: ^1.0.6 + es-errors: ^1.3.0 + is-data-view: ^1.0.1 + checksum: 8984119e59dbed906a11fcfb417d7d861936f16697a0e7216fe2c6c810f6b5e8f4a5281e73f2c28e8e9259027190ac4a33e2a65fdd7fa86ac06b76e838918583 + languageName: node + linkType: hard + +"data-view-byte-length@npm:^1.0.1": + version: 1.0.1 + resolution: "data-view-byte-length@npm:1.0.1" + dependencies: + call-bind: ^1.0.7 + es-errors: ^1.3.0 + is-data-view: ^1.0.1 + checksum: b7d9e48a0cf5aefed9ab7d123559917b2d7e0d65531f43b2fd95b9d3a6b46042dd3fca597c42bba384e66b70d7ad66ff23932f8367b241f53d93af42cfe04ec2 + languageName: node + linkType: hard + +"data-view-byte-offset@npm:^1.0.0": + version: 1.0.0 + resolution: "data-view-byte-offset@npm:1.0.0" + dependencies: + call-bind: ^1.0.6 + es-errors: ^1.3.0 + is-data-view: ^1.0.1 + checksum: 21b0d2e53fd6e20cc4257c873bf6d36d77bd6185624b84076c0a1ddaa757b49aaf076254006341d35568e89f52eecd1ccb1a502cfb620f2beca04f48a6a62a8f + languageName: node + linkType: hard + "dataloader@npm:^1.4.0": version: 1.4.0 resolution: "dataloader@npm:1.4.0" @@ -21197,7 +15691,7 @@ __metadata: languageName: node linkType: hard -"date-fns@npm:^2.29.3, date-fns@npm:^2.30.0": +"date-fns@npm:^2.30.0": version: 2.30.0 resolution: "date-fns@npm:2.30.0" dependencies: @@ -21207,9 +15701,9 @@ __metadata: linkType: hard "date-fns@npm:^3.2.0": - version: 3.2.0 - resolution: "date-fns@npm:3.2.0" - checksum: f93e987f785d7f2b7349986d150b014ce21fa6425e2e1edea6f0e01731dceef68deabf0f723689c28604e857648ac708a52b924cb7584e4321835686aa665371 + version: 3.6.0 + resolution: "date-fns@npm:3.6.0" + checksum: 0b5fb981590ef2f8e5a3ba6cd6d77faece0ea7f7158948f2eaae7bbb7c80a8f63ae30b01236c2923cf89bb3719c33aeb150c715ea4fe4e86e37dcf06bed42fb6 languageName: node linkType: hard @@ -21220,6 +15714,13 @@ __metadata: languageName: node linkType: hard +"dayjs@npm:^1.11.9": + version: 1.11.11 + resolution: "dayjs@npm:1.11.11" + checksum: 0131d10516b9945f05a57e13f4af49a6814de5573a494824e103131a3bbe4cc470b1aefe8e17e51f9a478a22cd116084be1ee5725cedb66ec4c3f9091202dc4b + languageName: node + linkType: hard + "debug@npm:2.6.9, debug@npm:^2.2.0, debug@npm:^2.3.3, debug@npm:^2.6.9": version: 2.6.9 resolution: "debug@npm:2.6.9" @@ -21229,7 +15730,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:4.3.4, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": +"debug@npm:4, debug@npm:4.3.4, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -21241,7 +15742,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:^3.0.0, debug@npm:^3.1.0, debug@npm:^3.2.7": +"debug@npm:^3.1.0, debug@npm:^3.2.7": version: 3.2.7 resolution: "debug@npm:3.2.7" dependencies: @@ -21260,7 +15761,7 @@ __metadata: languageName: node linkType: hard -"decamelize@npm:^1.1.0, decamelize@npm:^1.1.2, decamelize@npm:^1.2.0": +"decamelize@npm:^1.1.0, decamelize@npm:^1.2.0": version: 1.2.0 resolution: "decamelize@npm:1.2.0" checksum: 85c39fe8fbf0482d4a1e224ef0119db5c1897f8503bcef8b826adff7a1b11414972f6fef2d7dec2ee0b4be3863cf64ac1439137ae9e6af23a3d8dcbe26a5b4b2 @@ -21305,14 +15806,14 @@ __metadata: linkType: hard "dedent@npm:^1.0.0": - version: 1.5.1 - resolution: "dedent@npm:1.5.1" + version: 1.5.3 + resolution: "dedent@npm:1.5.3" peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: babel-plugin-macros: optional: true - checksum: f8612cd5b00aab58b18bb95572dca08dc2d49720bfa7201a444c3dae430291e8a06d4928614a6ec8764d713927f44bce9c990d3b8238fca2f430990ddc17c070 + checksum: d94bde6e6f780be4da4fd760288fcf755ec368872f4ac5218197200d86430aeb8d90a003a840bff1c20221188e3f23adced0119cb811c6873c70d0ac66d12832 languageName: node linkType: hard @@ -21326,13 +15827,13 @@ __metadata: linkType: hard "deep-equal@npm:^2.0.5": - version: 2.2.1 - resolution: "deep-equal@npm:2.2.1" + version: 2.2.3 + resolution: "deep-equal@npm:2.2.3" dependencies: array-buffer-byte-length: ^1.0.0 - call-bind: ^1.0.2 + call-bind: ^1.0.5 es-get-iterator: ^1.1.3 - get-intrinsic: ^1.2.0 + get-intrinsic: ^1.2.2 is-arguments: ^1.1.1 is-array-buffer: ^3.0.2 is-date-object: ^1.0.5 @@ -21342,12 +15843,12 @@ __metadata: object-is: ^1.1.5 object-keys: ^1.1.1 object.assign: ^4.1.4 - regexp.prototype.flags: ^1.5.0 + regexp.prototype.flags: ^1.5.1 side-channel: ^1.0.4 which-boxed-primitive: ^1.0.2 which-collection: ^1.0.1 - which-typed-array: ^1.1.9 - checksum: 9e32606f0e24ef4d6b100c68cadae81495c3638944e933afc4b8389b042e95c5fe1381492cf7a6d385bcbae564c9cfb7086f37f277e37521a632b008a6b208dc + which-typed-array: ^1.1.13 + checksum: a48244f90fa989f63ff5ef0cc6de1e4916b48ea0220a9c89a378561960814794a5800c600254482a2c8fd2e49d6c2e196131dc983976adb024c94a42dfe4949f languageName: node linkType: hard @@ -21375,19 +15876,6 @@ __metadata: languageName: node linkType: hard -"default-browser-id@npm:^1.0.4": - version: 1.0.4 - resolution: "default-browser-id@npm:1.0.4" - dependencies: - bplist-parser: ^0.1.0 - meow: ^3.1.0 - untildify: ^2.0.0 - bin: - default-browser-id: cli.js - checksum: a00a2ab66beab70490b4d76258a1f2eadfadca6414bf67ab78aa25b33dc3de0c4c813bb8f204271aa7a08281c39474487db0229e325112456464fb97a0522a8a - languageName: node - linkType: hard - "default-browser@npm:^4.0.0": version: 4.0.0 resolution: "default-browser@npm:4.0.0" @@ -21426,7 +15914,7 @@ __metadata: languageName: node linkType: hard -"define-data-property@npm:^1.1.4": +"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": version: 1.1.4 resolution: "define-data-property@npm:1.1.4" dependencies: @@ -21451,13 +15939,14 @@ __metadata: languageName: node linkType: hard -"define-properties@npm:^1.1.2, define-properties@npm:^1.1.3, define-properties@npm:^1.1.4, define-properties@npm:^1.2.0": - version: 1.2.0 - resolution: "define-properties@npm:1.2.0" +"define-properties@npm:^1.1.3, define-properties@npm:^1.2.0, define-properties@npm:^1.2.1": + version: 1.2.1 + resolution: "define-properties@npm:1.2.1" dependencies: + define-data-property: ^1.0.1 has-property-descriptors: ^1.0.0 object-keys: ^1.1.1 - checksum: 34b58cae4651936a3c8c720310ce393a3227f5123640ab5402e7d6e59bb44f8295b789cb5d74e7513682b2e60ff20586d6f52b726d964d617abffa3da76344e0 + checksum: 88a152319ffe1396ccc6ded510a3896e77efac7a1bfbaa174a7b00414a1747377e0bb525d303794a47cf30e805c2ec84e575758512c6e44a993076d29fd4e6c3 languageName: node linkType: hard @@ -21489,10 +15978,10 @@ __metadata: languageName: node linkType: hard -"defu@npm:^6.1.2": - version: 6.1.3 - resolution: "defu@npm:6.1.3" - checksum: 60d0d9a6e328148d5313fe0239ba3777701291f35570b52562454653d953fec5281b084514540f8d3b60d61bad9e39b52e95b3c0451631ded220ad8fdc893455 +"defu@npm:^6.1.4": + version: 6.1.4 + resolution: "defu@npm:6.1.4" + checksum: 2d6cc366262dc0cb8096e429368e44052fdf43ed48e53ad84cc7c9407f890301aa5fcb80d0995abaaf842b3949f154d060be4160f7a46cb2bc2f7726c81526f5 languageName: node linkType: hard @@ -21519,13 +16008,6 @@ __metadata: languageName: node linkType: hard -"delegates@npm:^1.0.0": - version: 1.0.0 - resolution: "delegates@npm:1.0.0" - checksum: ba05874b91148e1db4bf254750c042bf2215febd23a6d3cda2e64896aef79745fbd4b9996488bd3cafb39ce19dbce0fd6e3b6665275638befffe1c9b312b91b5 - languageName: node - linkType: hard - "denque@npm:^2.1.0": version: 2.1.0 resolution: "denque@npm:2.1.0" @@ -21533,7 +16015,7 @@ __metadata: languageName: node linkType: hard -"depd@npm:2.0.0, depd@npm:^2.0.0, depd@npm:~2.0.0": +"depd@npm:2.0.0, depd@npm:~2.0.0": version: 2.0.0 resolution: "depd@npm:2.0.0" checksum: 58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c @@ -21554,16 +16036,6 @@ __metadata: languageName: node linkType: hard -"des.js@npm:^1.0.0": - version: 1.1.0 - resolution: "des.js@npm:1.1.0" - dependencies: - inherits: ^2.0.1 - minimalistic-assert: ^1.0.0 - checksum: 671354943ad67493e49eb4c555480ab153edd7cee3a51c658082fcde539d2690ed2a4a0b5d1f401f9cde822edf3939a6afb2585f32c091f2d3a1b1665cd45236 - languageName: node - linkType: hard - "destroy@npm:1.2.0": version: 1.2.0 resolution: "destroy@npm:1.2.0" @@ -21578,15 +16050,6 @@ __metadata: languageName: node linkType: hard -"detab@npm:2.0.4": - version: 2.0.4 - resolution: "detab@npm:2.0.4" - dependencies: - repeat-string: ^1.5.4 - checksum: 969c7f5a04fc3f8c52eb3b9db2fd4ba20b9b9ce56c5659ebf4cf93ba6c1be68b651665d053affbe99e76733cf7d134546cdd6be038af368f8365f42a646d5fb8 - languageName: node - linkType: hard - "detect-indent@npm:^6.0.0, detect-indent@npm:^6.1.0": version: 6.1.0 resolution: "detect-indent@npm:6.1.0" @@ -21658,14 +16121,7 @@ __metadata: languageName: node linkType: hard -"diff-sequences@npm:^29.4.3": - version: 29.4.3 - resolution: "diff-sequences@npm:29.4.3" - checksum: 183800b9fd8523a05a3a50ade0fafe81d4b8a8ac113b077d2bc298052ccdc081e3b896f19bf65768b536daebd8169a493c4764cb70a2195e14c442c12538d121 - languageName: node - linkType: hard - -"diff-sequences@npm:^29.6.3": +"diff-sequences@npm:^29.4.3, diff-sequences@npm:^29.6.3": version: 29.6.3 resolution: "diff-sequences@npm:29.6.3" checksum: 32e27ac7dbffdf2fb0eb5a84efd98a9ad084fbabd5ac9abb8757c6770d5320d2acd172830b28c4add29bb873d59420601dfc805ac4064330ce59b1adfd0593b2 @@ -21679,26 +16135,6 @@ __metadata: languageName: node linkType: hard -"diffie-hellman@npm:^5.0.0": - version: 5.0.3 - resolution: "diffie-hellman@npm:5.0.3" - dependencies: - bn.js: ^4.1.0 - miller-rabin: ^4.0.0 - randombytes: ^2.0.0 - checksum: ce53ccafa9ca544b7fc29b08a626e23a9b6562efc2a98559a0c97b4718937cebaa9b5d7d0a05032cc9c1435e9b3c1532b9e9bf2e0ede868525922807ad6e1ecf - languageName: node - linkType: hard - -"dir-glob@npm:^2.2.2": - version: 2.2.2 - resolution: "dir-glob@npm:2.2.2" - dependencies: - path-type: ^3.0.0 - checksum: 67575fd496df80ec90969f1a9f881f03b4ef614ca2c07139df81a12f9816250780dff906f482def0f897dd748d22fa13c076b52ac635e0024f7d434846077a3a - languageName: node - linkType: hard - "dir-glob@npm:^3.0.1": version: 3.0.1 resolution: "dir-glob@npm:3.0.1" @@ -21740,15 +16176,6 @@ __metadata: languageName: node linkType: hard -"dom-converter@npm:^0.2.0": - version: 0.2.0 - resolution: "dom-converter@npm:0.2.0" - dependencies: - utila: ~0.4 - checksum: e96aa63bd8c6ee3cd9ce19c3aecfc2c42e50a460e8087114794d4f5ecf3a4f052b34ea3bf2d73b5d80b4da619073b49905e6d7d788ceb7814ca4c29be5354a11 - languageName: node - linkType: hard - "dom-serializer@npm:^1.0.1": version: 1.4.1 resolution: "dom-serializer@npm:1.4.1" @@ -21778,13 +16205,6 @@ __metadata: languageName: node linkType: hard -"domain-browser@npm:^1.1.1": - version: 1.2.0 - resolution: "domain-browser@npm:1.2.0" - checksum: a955f482f4b4710fbd77c12a33e77548d63603c30c80f61a80519f27e3db1ba8530b914584cc9e9365d2038753d6b5bd1f4e6c81e432b007b0ec95b8b5e69b1b - languageName: node - linkType: hard - "domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0, domelementtype@npm:^2.3.0": version: 2.3.0 resolution: "domelementtype@npm:2.3.0" @@ -21819,7 +16239,7 @@ __metadata: languageName: node linkType: hard -"domhandler@npm:^4.0.0, domhandler@npm:^4.2.0, domhandler@npm:^4.3.1": +"domhandler@npm:^4.2.0, domhandler@npm:^4.3.1": version: 4.3.1 resolution: "domhandler@npm:4.3.1" dependencies: @@ -21844,14 +16264,14 @@ __metadata: languageName: node linkType: hard -"dompurify@npm:^2.2.8": - version: 2.4.5 - resolution: "dompurify@npm:2.4.5" - checksum: 90d880e04c8476041778777d412eaa3d204448f1be67b9c72f76374f8f113e04552d5abbcee2d76fe36d03db9f9cb97b2cfa48cd7440b20fbcae2e1c7131e9de +"dompurify@npm:^3.0.6": + version: 3.1.2 + resolution: "dompurify@npm:3.1.2" + checksum: 6f072da177ba850c196184d76a277933a19831e59313edd90f094e8884579c8193b21ea105889d89059771f058f4b2e0c14fc5a58f19f7dad2a6756be807d091 languageName: node linkType: hard -"domutils@npm:^2.5.2, domutils@npm:^2.8.0": +"domutils@npm:^2.8.0": version: 2.8.0 resolution: "domutils@npm:2.8.0" dependencies: @@ -21908,28 +16328,21 @@ __metadata: languageName: node linkType: hard -"dotenv-expand@npm:^5.1.0": - version: 5.1.0 - resolution: "dotenv-expand@npm:5.1.0" - checksum: 24ac633de853ef474d0421cc639328b7134109c8dc2baaa5e3afb7495af5e9237136d7e6971e55668e4dce915487eb140967cdd2b3e99aa439e0f6bf8b56faeb - languageName: node - linkType: hard - -"dotenv@npm:16.3.1, dotenv@npm:^16.0.0, dotenv@npm:^16.0.3": +"dotenv@npm:16.3.1": version: 16.3.1 resolution: "dotenv@npm:16.3.1" checksum: b95ff1bbe624ead85a3cd70dbd827e8e06d5f05f716f2d0cbc476532d54c7c9469c3bc4dd93ea519f6ad711cb522c00ac9a62b6eb340d5affae8008facc3fbd7 languageName: node linkType: hard -"dotenv@npm:^16.4.5": +"dotenv@npm:^16.0.0, dotenv@npm:^16.0.3, dotenv@npm:^16.4.5": version: 16.4.5 resolution: "dotenv@npm:16.4.5" checksum: 48d92870076832af0418b13acd6e5a5a3e83bb00df690d9812e94b24aff62b88ade955ac99a05501305b8dc8f1b0ee7638b18493deb6fe93d680e5220936292f languageName: node linkType: hard -"dotenv@npm:^8.0.0, dotenv@npm:^8.1.0": +"dotenv@npm:^8.1.0": version: 8.6.0 resolution: "dotenv@npm:8.6.0" checksum: 6750431dea8efbd54b9f2d9681b04e1ccc7989486461dcf058bb708d9e3d63b04115fcdf8840e38ad1e24a4a2e1e7c1560626c5e3ac7bc09371b127c49e2d45f @@ -21937,9 +16350,9 @@ __metadata: linkType: hard "dset@npm:^3.1.2": - version: 3.1.2 - resolution: "dset@npm:3.1.2" - checksum: a10d5f214ccd53e7d2e79215473256b74cb98fd3f20ad4f4684ab575b19bac71e5dda524d6febcf42854062e3f575a2dbfca4d53d2ffb9ae238eecdcc97a095b + version: 3.1.3 + resolution: "dset@npm:3.1.3" + checksum: b1ff68f1f42af373baa85b00b04d89094cd0d7f74f94bd11364cba575f2762ed52a0a0503bbfcc92eccd07c6d55426813c8a7a6cfa020338eaea1f4edfd332c2 languageName: node linkType: hard @@ -21967,7 +16380,7 @@ __metadata: languageName: node linkType: hard -"duplexify@npm:^3.4.2, duplexify@npm:^3.5.0, duplexify@npm:^3.6.0": +"duplexify@npm:^3.5.0, duplexify@npm:^3.6.0": version: 3.7.1 resolution: "duplexify@npm:3.7.1" dependencies: @@ -22013,56 +16426,20 @@ __metadata: linkType: hard "ejs@npm:^3.1.8": - version: 3.1.9 - resolution: "ejs@npm:3.1.9" + version: 3.1.10 + resolution: "ejs@npm:3.1.10" dependencies: jake: ^10.8.5 bin: ejs: bin/cli.js - checksum: f0e249c79128810f5f6d5cbf347fc906d86bb9384263db0b2a9004aea649f2bc2d112736de5716c509c80afb4721c47281bd5b57c757d3b63f1bf5ac5f885893 - languageName: node - linkType: hard - -"electron-to-chromium@npm:^1.4.431": - version: 1.4.447 - resolution: "electron-to-chromium@npm:1.4.447" - checksum: 00940838d6bea4dcf206acbb1074ec92039b74074722cd327c439aa302fe2ed6f6f6cc065a1fc067b610e157b89390433b402f8ba66b200bb9933f4d1d39eeb2 - languageName: node - linkType: hard - -"electron-to-chromium@npm:^1.4.535": - version: 1.4.566 - resolution: "electron-to-chromium@npm:1.4.566" - checksum: 9df1aed0ecbf0026e8b2b055169aac0b73c1077d809430801093f0d5e19e82e8466c273eddc1c0b7d9f63f598546421c42fedee93c341b8f7c38e6bb9286d0e7 - languageName: node - linkType: hard - -"electron-to-chromium@npm:^1.4.601": - version: 1.4.616 - resolution: "electron-to-chromium@npm:1.4.616" - checksum: a02416f3293d28120d5132546a6aea614ebd2d820a684f41b1c20138331922ddc672c4a59bfc4b91bb5aee1ba608f6c10cd3f69c344cd434397e7f14a4c97348 + checksum: 52eade9e68416ed04f7f92c492183340582a36482836b11eab97b159fcdcfdedc62233a1bf0bf5e5e1851c501f2dca0e2e9afd111db2599e4e7f53ee29429ae1 languageName: node linkType: hard "electron-to-chromium@npm:^1.4.668": - version: 1.4.736 - resolution: "electron-to-chromium@npm:1.4.736" - checksum: f3acb515dcb9333b318f9a8ee80a0c3975162da6cc45d9c00152e0de7004b2bfe1246fe6cdf0c41a1b7016780bd4324aff848830aba4227cb55480c1aa32d248 - languageName: node - linkType: hard - -"elliptic@npm:^6.5.3": - version: 6.5.4 - resolution: "elliptic@npm:6.5.4" - dependencies: - bn.js: ^4.11.9 - brorand: ^1.1.0 - hash.js: ^1.0.0 - hmac-drbg: ^1.0.1 - inherits: ^2.0.4 - minimalistic-assert: ^1.0.1 - minimalistic-crypto-utils: ^1.0.1 - checksum: 5f361270292c3b27cf0843e84526d11dec31652f03c2763c6c2b8178548175ff5eba95341dd62baff92b2265d1af076526915d8af6cc9cb7559c44a62f8ca6e2 + version: 1.4.757 + resolution: "electron-to-chromium@npm:1.4.757" + checksum: 77fddf3870ff66280f4b639c409ff0a82661ba50e6519b571bb79325e6ea2c4fef645bcf65dcc1ced8b6151cc78083af8b781877247e62986ce39dee1d642cfe languageName: node linkType: hard @@ -22159,44 +16536,13 @@ __metadata: languageName: node linkType: hard -"endent@npm:^2.0.1": - version: 2.1.0 - resolution: "endent@npm:2.1.0" - dependencies: - dedent: ^0.7.0 - fast-json-parse: ^1.0.3 - objectorarray: ^1.0.5 - checksum: 8cd6dae45e693ae2b2cbff2384348d3a5e2a06cc0396dddca8165e46bd2fd8d5394d44d338ba653bbfce4aead90eca1ec1abe7203843c84155c645d283b6b884 - languageName: node - linkType: hard - -"enhanced-resolve@npm:^4.5.0": - version: 4.5.0 - resolution: "enhanced-resolve@npm:4.5.0" - dependencies: - graceful-fs: ^4.1.2 - memory-fs: ^0.5.0 - tapable: ^1.0.0 - checksum: d95fc630606ea35bed21c4a029bbb1681919571a2d1d2011c7fc42a26a9e48ed3d74a89949ce331e1fd3229850a303e3218b887b92951330f16bdfbb93a10e64 - languageName: node - linkType: hard - -"enhanced-resolve@npm:^5.15.0": - version: 5.15.0 - resolution: "enhanced-resolve@npm:5.15.0" - dependencies: - graceful-fs: ^4.2.4 - tapable: ^2.2.0 - checksum: 69984a7990913948b4150855aed26a84afb4cb1c5a94fb8e3a65bd00729a73fc2eaff6871fb8e345377f294831afe349615c93560f2f54d61b43cdfdf668f19a - languageName: node - linkType: hard - "enquirer@npm:^2.3.0, enquirer@npm:^2.3.5, enquirer@npm:^2.3.6": - version: 2.3.6 - resolution: "enquirer@npm:2.3.6" + version: 2.4.1 + resolution: "enquirer@npm:2.4.1" dependencies: ansi-colors: ^4.1.1 - checksum: 8e070e052c2c64326a2803db9084d21c8aaa8c688327f133bf65c4a712586beb126fd98c8a01cfb0433e82a4bd3b6262705c55a63e0f7fb91d06b9cedbde9a11 + strip-ansi: ^6.0.1 + checksum: 43850479d7a51d36a9c924b518dcdc6373b5a8ae3401097d336b7b7e258324749d0ad37a1fcaa5706f04799baa05585cd7af19ebdf7667673e7694435fcea918 languageName: node linkType: hard @@ -22231,11 +16577,11 @@ __metadata: linkType: hard "envinfo@npm:^7.7.3": - version: 7.10.0 - resolution: "envinfo@npm:7.10.0" + version: 7.13.0 + resolution: "envinfo@npm:7.13.0" bin: envinfo: dist/cli.js - checksum: ebc7792fbedca72bc829913abe0c2a3384b883903012f97b56085afd4e83d26f7dd0652403fedd99cd3e1c93d4fb0706f5d2c3dc06ac6a1eda348280a06a9dcf + checksum: 9c279213cbbb353b3171e8e333fd2ed564054abade08ab3d735fe136e10a0e14e0588e1ce77e6f01285f2462eaca945d64f0778be5ae3d9e82804943e36a4411 languageName: node linkType: hard @@ -22246,7 +16592,7 @@ __metadata: languageName: node linkType: hard -"errno@npm:^0.1.3, errno@npm:~0.1.1, errno@npm:~0.1.7": +"errno@npm:~0.1.1": version: 0.1.8 resolution: "errno@npm:0.1.8" dependencies: @@ -22257,7 +16603,7 @@ __metadata: languageName: node linkType: hard -"error-ex@npm:^1.2.0, error-ex@npm:^1.3.1": +"error-ex@npm:^1.3.1": version: 1.3.2 resolution: "error-ex@npm:1.3.2" dependencies: @@ -22266,69 +16612,73 @@ __metadata: languageName: node linkType: hard -"error-stack-parser@npm:^2.0.6": - version: 2.1.4 - resolution: "error-stack-parser@npm:2.1.4" +"es-abstract@npm:^1.22.1, es-abstract@npm:^1.22.3, es-abstract@npm:^1.23.0, es-abstract@npm:^1.23.1, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3": + version: 1.23.3 + resolution: "es-abstract@npm:1.23.3" dependencies: - stackframe: ^1.3.4 - checksum: 7679b780043c98b01fc546725484e0cfd3071bf5c906bbe358722972f04abf4fc3f0a77988017665bab367f6ef3fc2d0185f7528f45966b83e7c99c02d5509b9 - languageName: node - linkType: hard - -"es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4, es-abstract@npm:^1.21.2": - version: 1.21.2 - resolution: "es-abstract@npm:1.21.2" - dependencies: - array-buffer-byte-length: ^1.0.0 - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - es-set-tostringtag: ^2.0.1 + array-buffer-byte-length: ^1.0.1 + arraybuffer.prototype.slice: ^1.0.3 + available-typed-arrays: ^1.0.7 + call-bind: ^1.0.7 + data-view-buffer: ^1.0.1 + data-view-byte-length: ^1.0.1 + data-view-byte-offset: ^1.0.0 + es-define-property: ^1.0.0 + es-errors: ^1.3.0 + es-object-atoms: ^1.0.0 + es-set-tostringtag: ^2.0.3 es-to-primitive: ^1.2.1 - function.prototype.name: ^1.1.5 - get-intrinsic: ^1.2.0 - get-symbol-description: ^1.0.0 + function.prototype.name: ^1.1.6 + get-intrinsic: ^1.2.4 + get-symbol-description: ^1.0.2 globalthis: ^1.0.3 gopd: ^1.0.1 - has: ^1.0.3 - has-property-descriptors: ^1.0.0 - has-proto: ^1.0.1 + has-property-descriptors: ^1.0.2 + has-proto: ^1.0.3 has-symbols: ^1.0.3 - internal-slot: ^1.0.5 - is-array-buffer: ^3.0.2 + hasown: ^2.0.2 + internal-slot: ^1.0.7 + is-array-buffer: ^3.0.4 is-callable: ^1.2.7 - is-negative-zero: ^2.0.2 + is-data-view: ^1.0.1 + is-negative-zero: ^2.0.3 is-regex: ^1.1.4 - is-shared-array-buffer: ^1.0.2 + is-shared-array-buffer: ^1.0.3 is-string: ^1.0.7 - is-typed-array: ^1.1.10 + is-typed-array: ^1.1.13 is-weakref: ^1.0.2 - object-inspect: ^1.12.3 + object-inspect: ^1.13.1 object-keys: ^1.1.1 - object.assign: ^4.1.4 - regexp.prototype.flags: ^1.4.3 - safe-regex-test: ^1.0.0 - string.prototype.trim: ^1.2.7 - string.prototype.trimend: ^1.0.6 - string.prototype.trimstart: ^1.0.6 - typed-array-length: ^1.0.4 + object.assign: ^4.1.5 + regexp.prototype.flags: ^1.5.2 + safe-array-concat: ^1.1.2 + safe-regex-test: ^1.0.3 + string.prototype.trim: ^1.2.9 + string.prototype.trimend: ^1.0.8 + string.prototype.trimstart: ^1.0.8 + typed-array-buffer: ^1.0.2 + typed-array-byte-length: ^1.0.1 + typed-array-byte-offset: ^1.0.2 + typed-array-length: ^1.0.6 unbox-primitive: ^1.0.2 - which-typed-array: ^1.1.9 - checksum: 7dc2c882bafbb13609b9c35c29f0717ebf5a4dbde23a73803be821f349aa38d55f324318ccebb6da83c074260622f11d0a7f4cd1e0e19f52cc03b6b5386693fb + which-typed-array: ^1.1.15 + checksum: d27e9afafb225c6924bee9971a7f25f20c314f2d6cb93a63cada4ac11dcf42040896a6c22e5fb8f2a10767055ed4ddf400be3b1eb12297d281726de470b75666 languageName: node linkType: hard -"es-aggregate-error@npm:^1.0.9": - version: 1.0.9 - resolution: "es-aggregate-error@npm:1.0.9" +"es-aggregate-error@npm:^1.0.10": + version: 1.0.13 + resolution: "es-aggregate-error@npm:1.0.13" dependencies: - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - function-bind: ^1.1.1 - functions-have-names: ^1.2.3 - get-intrinsic: ^1.1.3 + define-data-property: ^1.1.4 + define-properties: ^1.2.1 + es-abstract: ^1.23.2 + es-errors: ^1.3.0 + function-bind: ^1.1.2 globalthis: ^1.0.3 - has-property-descriptors: ^1.0.0 - checksum: b977bfd94546b0f853b93112e0804a0901fd6bca4829012265f8d8266c6ef20f68b2e6cbae23425926920e37fc91b18eff1142c7481a25670d054dea9790827c + has-property-descriptors: ^1.0.2 + set-function-name: ^2.0.2 + checksum: 4cbf777c46991b527bbdb97668eaa5a663c764a0886a62d9a30836451c47162d01364733489543a0521ccd3cb318432d12f9b915d82442aae8974ed18abaa5ba languageName: node linkType: hard @@ -22348,7 +16698,7 @@ __metadata: languageName: node linkType: hard -"es-errors@npm:^1.3.0": +"es-errors@npm:^1.1.0, es-errors@npm:^1.2.1, es-errors@npm:^1.3.0": version: 1.3.0 resolution: "es-errors@npm:1.3.0" checksum: 0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85 @@ -22372,6 +16722,28 @@ __metadata: languageName: node linkType: hard +"es-iterator-helpers@npm:^1.0.17": + version: 1.0.19 + resolution: "es-iterator-helpers@npm:1.0.19" + dependencies: + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.3 + es-errors: ^1.3.0 + es-set-tostringtag: ^2.0.3 + function-bind: ^1.1.2 + get-intrinsic: ^1.2.4 + globalthis: ^1.0.3 + has-property-descriptors: ^1.0.2 + has-proto: ^1.0.3 + has-symbols: ^1.0.3 + internal-slot: ^1.0.7 + iterator.prototype: ^1.1.2 + safe-array-concat: ^1.1.2 + checksum: ae8f0241e383b3d197383b9842c48def7fce0255fb6ed049311b686ce295595d9e389b466f6a1b7d4e7bb92d82f5e716d6fae55e20c1040249bf976743b038c5 + languageName: node + linkType: hard + "es-module-lexer@npm:^0.9.3": version: 0.9.3 resolution: "es-module-lexer@npm:0.9.3" @@ -22379,30 +16751,39 @@ __metadata: languageName: node linkType: hard -"es-module-lexer@npm:^1.0.5, es-module-lexer@npm:^1.2.1": - version: 1.3.0 - resolution: "es-module-lexer@npm:1.3.0" - checksum: cbd9bdc65458d4c4bd0d22a1c792926bfdf7bb6a96a9ed04da7d31f317159bd4945d2dbeb318717f9214f9695ee85a8fae64a5d25bf360baa82b58079032fc7a +"es-module-lexer@npm:^1.0.5": + version: 1.5.2 + resolution: "es-module-lexer@npm:1.5.2" + checksum: 20b6c668691ee81781a0ae56930560c23aa28fb934fce9137820f12ae3726a25626010cbd8ed1775c217d3bae108e23dd7b805f923133dc633bfbbc2b0020524 languageName: node linkType: hard -"es-set-tostringtag@npm:^2.0.1": - version: 2.0.1 - resolution: "es-set-tostringtag@npm:2.0.1" - dependencies: - get-intrinsic: ^1.1.3 - has: ^1.0.3 - has-tostringtag: ^1.0.0 - checksum: 9af096365e3861bb29755cc5f76f15f66a7eab0e83befca396129090c1d9737e54090278b8e5357e97b5f0a5b0459fca07c40c6740884c2659cbf90ef8e508cc - languageName: node - linkType: hard - -"es-shim-unscopables@npm:^1.0.0": +"es-object-atoms@npm:^1.0.0": version: 1.0.0 - resolution: "es-shim-unscopables@npm:1.0.0" + resolution: "es-object-atoms@npm:1.0.0" dependencies: - has: ^1.0.3 - checksum: d54a66239fbd19535b3e50333913260394f14d2d7adb136a95396a13ca584bab400cf9cb2ffd9232f3fe2f0362540bd3a708240c493e46e13fe0b90cfcfedc3d + es-errors: ^1.3.0 + checksum: 1fed3d102eb27ab8d983337bb7c8b159dd2a1e63ff833ec54eea1311c96d5b08223b433060ba240541ca8adba9eee6b0a60cdbf2f80634b784febc9cc8b687b4 + languageName: node + linkType: hard + +"es-set-tostringtag@npm:^2.0.3": + version: 2.0.3 + resolution: "es-set-tostringtag@npm:2.0.3" + dependencies: + get-intrinsic: ^1.2.4 + has-tostringtag: ^1.0.2 + hasown: ^2.0.1 + checksum: f22aff1585eb33569c326323f0b0d175844a1f11618b86e193b386f8be0ea9474cfbe46df39c45d959f7aa8f6c06985dc51dd6bce5401645ec5a74c4ceaa836a + languageName: node + linkType: hard + +"es-shim-unscopables@npm:^1.0.0, es-shim-unscopables@npm:^1.0.2": + version: 1.0.2 + resolution: "es-shim-unscopables@npm:1.0.2" + dependencies: + hasown: ^2.0.0 + checksum: f495af7b4b7601a4c0cfb893581c352636e5c08654d129590386a33a0432cf13a7bdc7b6493801cadd990d838e2839b9013d1de3b880440cb537825e834fe783 languageName: node linkType: hard @@ -22417,13 +16798,6 @@ __metadata: languageName: node linkType: hard -"es5-shim@npm:^4.5.13": - version: 4.6.7 - resolution: "es5-shim@npm:4.6.7" - checksum: f285a58ed1901d46872828776164c0837272d28374a3c74b31a893dc6b16c67d417509c4f587a87c7cdfa9faf9c97c70d774c81d8bf9dcca6d3d6bfdf4a7a28e - languageName: node - linkType: hard - "es6-promise@npm:^3.2.1": version: 3.3.1 resolution: "es6-promise@npm:3.3.1" @@ -22431,13 +16805,6 @@ __metadata: languageName: node linkType: hard -"es6-shim@npm:^0.35.5": - version: 0.35.8 - resolution: "es6-shim@npm:0.35.8" - checksum: e54e147677b9cd57c96bbc2332c3096ab861040b22daa27728204cacf9aa656d6a3eeb5367a037b276bfbe442ec866938a95b4612accf0cd24d01c209e48eaf9 - languageName: node - linkType: hard - "esbuild-plugin-alias@npm:^0.2.1": version: 0.2.1 resolution: "esbuild-plugin-alias@npm:0.2.1" @@ -22456,83 +16823,6 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:^0.17.6": - version: 0.17.19 - resolution: "esbuild@npm:0.17.19" - dependencies: - "@esbuild/android-arm": 0.17.19 - "@esbuild/android-arm64": 0.17.19 - "@esbuild/android-x64": 0.17.19 - "@esbuild/darwin-arm64": 0.17.19 - "@esbuild/darwin-x64": 0.17.19 - "@esbuild/freebsd-arm64": 0.17.19 - "@esbuild/freebsd-x64": 0.17.19 - "@esbuild/linux-arm": 0.17.19 - "@esbuild/linux-arm64": 0.17.19 - "@esbuild/linux-ia32": 0.17.19 - "@esbuild/linux-loong64": 0.17.19 - "@esbuild/linux-mips64el": 0.17.19 - "@esbuild/linux-ppc64": 0.17.19 - "@esbuild/linux-riscv64": 0.17.19 - "@esbuild/linux-s390x": 0.17.19 - "@esbuild/linux-x64": 0.17.19 - "@esbuild/netbsd-x64": 0.17.19 - "@esbuild/openbsd-x64": 0.17.19 - "@esbuild/sunos-x64": 0.17.19 - "@esbuild/win32-arm64": 0.17.19 - "@esbuild/win32-ia32": 0.17.19 - "@esbuild/win32-x64": 0.17.19 - dependenciesMeta: - "@esbuild/android-arm": - optional: true - "@esbuild/android-arm64": - optional: true - "@esbuild/android-x64": - optional: true - "@esbuild/darwin-arm64": - optional: true - "@esbuild/darwin-x64": - optional: true - "@esbuild/freebsd-arm64": - optional: true - "@esbuild/freebsd-x64": - optional: true - "@esbuild/linux-arm": - optional: true - "@esbuild/linux-arm64": - optional: true - "@esbuild/linux-ia32": - optional: true - "@esbuild/linux-loong64": - optional: true - "@esbuild/linux-mips64el": - optional: true - "@esbuild/linux-ppc64": - optional: true - "@esbuild/linux-riscv64": - optional: true - "@esbuild/linux-s390x": - optional: true - "@esbuild/linux-x64": - optional: true - "@esbuild/netbsd-x64": - optional: true - "@esbuild/openbsd-x64": - optional: true - "@esbuild/sunos-x64": - optional: true - "@esbuild/win32-arm64": - optional: true - "@esbuild/win32-ia32": - optional: true - "@esbuild/win32-x64": - optional: true - bin: - esbuild: bin/esbuild - checksum: c7ac14bfaaebe4745d5d18347b4f6854fd1140acb9389e88dbfa5c20d4e2122451d9647d5498920470a880a605d6e5502b5c2102da6c282b01f129ddd49d2874 - languageName: node - linkType: hard - "esbuild@npm:^0.18.0, esbuild@npm:^0.18.10, esbuild@npm:^0.18.11, esbuild@npm:^0.18.2": version: 0.18.20 resolution: "esbuild@npm:0.18.20" @@ -22611,32 +16901,32 @@ __metadata: linkType: hard "esbuild@npm:^0.19.2, esbuild@npm:^0.19.3": - version: 0.19.11 - resolution: "esbuild@npm:0.19.11" + version: 0.19.12 + resolution: "esbuild@npm:0.19.12" dependencies: - "@esbuild/aix-ppc64": 0.19.11 - "@esbuild/android-arm": 0.19.11 - "@esbuild/android-arm64": 0.19.11 - "@esbuild/android-x64": 0.19.11 - "@esbuild/darwin-arm64": 0.19.11 - "@esbuild/darwin-x64": 0.19.11 - "@esbuild/freebsd-arm64": 0.19.11 - "@esbuild/freebsd-x64": 0.19.11 - "@esbuild/linux-arm": 0.19.11 - "@esbuild/linux-arm64": 0.19.11 - "@esbuild/linux-ia32": 0.19.11 - "@esbuild/linux-loong64": 0.19.11 - "@esbuild/linux-mips64el": 0.19.11 - "@esbuild/linux-ppc64": 0.19.11 - "@esbuild/linux-riscv64": 0.19.11 - "@esbuild/linux-s390x": 0.19.11 - "@esbuild/linux-x64": 0.19.11 - "@esbuild/netbsd-x64": 0.19.11 - "@esbuild/openbsd-x64": 0.19.11 - "@esbuild/sunos-x64": 0.19.11 - "@esbuild/win32-arm64": 0.19.11 - "@esbuild/win32-ia32": 0.19.11 - "@esbuild/win32-x64": 0.19.11 + "@esbuild/aix-ppc64": 0.19.12 + "@esbuild/android-arm": 0.19.12 + "@esbuild/android-arm64": 0.19.12 + "@esbuild/android-x64": 0.19.12 + "@esbuild/darwin-arm64": 0.19.12 + "@esbuild/darwin-x64": 0.19.12 + "@esbuild/freebsd-arm64": 0.19.12 + "@esbuild/freebsd-x64": 0.19.12 + "@esbuild/linux-arm": 0.19.12 + "@esbuild/linux-arm64": 0.19.12 + "@esbuild/linux-ia32": 0.19.12 + "@esbuild/linux-loong64": 0.19.12 + "@esbuild/linux-mips64el": 0.19.12 + "@esbuild/linux-ppc64": 0.19.12 + "@esbuild/linux-riscv64": 0.19.12 + "@esbuild/linux-s390x": 0.19.12 + "@esbuild/linux-x64": 0.19.12 + "@esbuild/netbsd-x64": 0.19.12 + "@esbuild/openbsd-x64": 0.19.12 + "@esbuild/sunos-x64": 0.19.12 + "@esbuild/win32-arm64": 0.19.12 + "@esbuild/win32-ia32": 0.19.12 + "@esbuild/win32-x64": 0.19.12 dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -22686,14 +16976,14 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 0fd913124089e26d30ec30f73b94d4ef9607935251df3253f869106980a5d4c78aa517738c8746abe6e933262e91a77d31427ce468ed8fc7fe498a20f7f92fbc + checksum: 0f2d21ffe24ebead64843f87c3aebe2e703a5ed9feb086a0728b24907fac2eb9923e4a79857d3df9059c915739bd7a870dd667972eae325c67f478b592b8582d languageName: node linkType: hard -"escalade@npm:^3.1.1": - version: 3.1.1 - resolution: "escalade@npm:3.1.1" - checksum: afd02e6ca91ffa813e1108b5e7756566173d6bc0d1eb951cb44d6b21702ec17c1cf116cfe75d4a2b02e05acb0b808a7a9387d0d1ca5cf9c04ad03a8445c3e46d +"escalade@npm:^3.1.1, escalade@npm:^3.1.2": + version: 3.1.2 + resolution: "escalade@npm:3.1.2" + checksum: 6b4adafecd0682f3aa1cd1106b8fff30e492c7015b178bc81b2d2f75106dabea6c6d6e8508fc491bd58e597c74abb0e8e2368f943ecb9393d4162e3c2f3cf287 languageName: node linkType: hard @@ -22771,18 +17061,7 @@ __metadata: languageName: node linkType: hard -"eslint-config-prettier@npm:^8.5.0": - version: 8.8.0 - resolution: "eslint-config-prettier@npm:8.8.0" - peerDependencies: - eslint: ">=7.0.0" - bin: - eslint-config-prettier: bin/cli.js - checksum: 9e3bb602184b7ec59239d2f901b1594cd7cc59ff38c3ddcd812137817e50840f4d65d62b61c515c7eae86d85f8b6fb2ebda659a3f83b2f2c5da75feb15531508 - languageName: node - linkType: hard - -"eslint-config-prettier@npm:^8.8.0": +"eslint-config-prettier@npm:^8.5.0, eslint-config-prettier@npm:^8.8.0": version: 8.10.0 resolution: "eslint-config-prettier@npm:8.10.0" peerDependencies: @@ -22809,45 +17088,48 @@ __metadata: linkType: hard "eslint-plugin-react-hooks@npm:^4.6.0": - version: 4.6.0 - resolution: "eslint-plugin-react-hooks@npm:4.6.0" + version: 4.6.2 + resolution: "eslint-plugin-react-hooks@npm:4.6.2" peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - checksum: 58c7e10ea5792c33346fcf5cb4024e14837035ce412ff99c2dcb7c4f903dc9b17939078f80bfef826301ce326582c396c00e8e0ac9d10ac2cde2b42d33763c65 + checksum: 4844e58c929bc05157fb70ba1e462e34f1f4abcbc8dd5bbe5b04513d33e2699effb8bca668297976ceea8e7ebee4e8fc29b9af9d131bcef52886feaa2308b2cc languageName: node linkType: hard "eslint-plugin-react-refresh@npm:^0.4.5": - version: 0.4.5 - resolution: "eslint-plugin-react-refresh@npm:0.4.5" + version: 0.4.6 + resolution: "eslint-plugin-react-refresh@npm:0.4.6" peerDependencies: eslint: ">=7" - checksum: ea696811c6264d2efee10efe07f80aaae75ded66c941d8d5ce65e15e6c4bb8ad50ac225310ed04f35ed68d2d57937ba4c6f06d9306e78931d583648abf496a41 + checksum: 931d5623c7c694526e9d34f61af856bb1949a0b9b9b509da29cba6c3c68fd4e1e7e36d8a340f6aecfd22329d0425c7fbb2388dd7d24b0d05218067747f5d6fe3 languageName: node linkType: hard "eslint-plugin-react@npm:^7.31.11": - version: 7.32.2 - resolution: "eslint-plugin-react@npm:7.32.2" + version: 7.34.1 + resolution: "eslint-plugin-react@npm:7.34.1" dependencies: - array-includes: ^3.1.6 - array.prototype.flatmap: ^1.3.1 - array.prototype.tosorted: ^1.1.1 + array-includes: ^3.1.7 + array.prototype.findlast: ^1.2.4 + array.prototype.flatmap: ^1.3.2 + array.prototype.toreversed: ^1.1.2 + array.prototype.tosorted: ^1.1.3 doctrine: ^2.1.0 + es-iterator-helpers: ^1.0.17 estraverse: ^5.3.0 jsx-ast-utils: ^2.4.1 || ^3.0.0 minimatch: ^3.1.2 - object.entries: ^1.1.6 - object.fromentries: ^2.0.6 - object.hasown: ^1.1.2 - object.values: ^1.1.6 + object.entries: ^1.1.7 + object.fromentries: ^2.0.7 + object.hasown: ^1.1.3 + object.values: ^1.1.7 prop-types: ^15.8.1 - resolve: ^2.0.0-next.4 - semver: ^6.3.0 - string.prototype.matchall: ^4.0.8 + resolve: ^2.0.0-next.5 + semver: ^6.3.1 + string.prototype.matchall: ^4.0.10 peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: 9ddd5cfc508555a5cb3edbdcc9138dd472d269d3a45da0be3e267ea2b3fa1b5990823675208c0e11376c9c55e46aaad5b7a5f46c965eb4dcf6f1eebcebf174c3 + checksum: 7c61b1314d37a4ac2f2474f9571f801f1a1a5d81dcd4abbb5d07145406518722fb792367267757ee116bde254be9753242d6b93c9619110398b3fe1746e4848c languageName: node linkType: hard @@ -22897,26 +17179,6 @@ __metadata: languageName: node linkType: hard -"eslint-scope@npm:^4.0.3": - version: 4.0.3 - resolution: "eslint-scope@npm:4.0.3" - dependencies: - esrecurse: ^4.1.0 - estraverse: ^4.1.1 - checksum: a2a3fe5845938ce7cfd2e658c309a9bb27a7f9ce94f0cc447ed5f9fa95b16451556d7e1db4c8e5d2aaa02d02850f5346d23091bbe94f7097412ce846504b4dcc - languageName: node - linkType: hard - -"eslint-scope@npm:^7.2.0": - version: 7.2.0 - resolution: "eslint-scope@npm:7.2.0" - dependencies: - esrecurse: ^4.3.0 - estraverse: ^5.2.0 - checksum: 5b48a3cc2485a3a58ca0bdecfb557c349009308a9b2afb24d070b1c0c254d445ee86d78bfee2c4ed6d1b8944307604a987c92f6d7e611e29de5d06256747a0ff - languageName: node - linkType: hard - "eslint-scope@npm:^7.2.2": version: 7.2.2 resolution: "eslint-scope@npm:7.2.2" @@ -22950,14 +17212,7 @@ __metadata: languageName: node linkType: hard -"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1": - version: 3.4.1 - resolution: "eslint-visitor-keys@npm:3.4.1" - checksum: b4ebd35aed5426cd81b1fb92487825f1acf47a31e91d76597a3ee0664d69627140c4dafaf9b319cfeb1f48c1113a393e21a734c669e6565a72e6fcc311bd9911 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^3.4.3": +"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": version: 3.4.3 resolution: "eslint-visitor-keys@npm:3.4.3" checksum: 92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 @@ -23014,56 +17269,7 @@ __metadata: languageName: node linkType: hard -"eslint@npm:^8.23.0": - version: 8.44.0 - resolution: "eslint@npm:8.44.0" - dependencies: - "@eslint-community/eslint-utils": ^4.2.0 - "@eslint-community/regexpp": ^4.4.0 - "@eslint/eslintrc": ^2.1.0 - "@eslint/js": 8.44.0 - "@humanwhocodes/config-array": ^0.11.10 - "@humanwhocodes/module-importer": ^1.0.1 - "@nodelib/fs.walk": ^1.2.8 - ajv: ^6.10.0 - chalk: ^4.0.0 - cross-spawn: ^7.0.2 - debug: ^4.3.2 - doctrine: ^3.0.0 - escape-string-regexp: ^4.0.0 - eslint-scope: ^7.2.0 - eslint-visitor-keys: ^3.4.1 - espree: ^9.6.0 - esquery: ^1.4.2 - esutils: ^2.0.2 - fast-deep-equal: ^3.1.3 - file-entry-cache: ^6.0.1 - find-up: ^5.0.0 - glob-parent: ^6.0.2 - globals: ^13.19.0 - graphemer: ^1.4.0 - ignore: ^5.2.0 - import-fresh: ^3.0.0 - imurmurhash: ^0.1.4 - is-glob: ^4.0.0 - is-path-inside: ^3.0.3 - js-yaml: ^4.1.0 - json-stable-stringify-without-jsonify: ^1.0.1 - levn: ^0.4.1 - lodash.merge: ^4.6.2 - minimatch: ^3.1.2 - natural-compare: ^1.4.0 - optionator: ^0.9.3 - strip-ansi: ^6.0.1 - strip-json-comments: ^3.1.0 - text-table: ^0.2.0 - bin: - eslint: bin/eslint.js - checksum: a31ca4571a67012629936d891141a4a5747d5902fb7f4e10119a5acd632e0976b9ba1b761d8c81cff8a9cc3e796df2c56f86c02535fd977de962a98ce585624a - languageName: node - linkType: hard - -"eslint@npm:^8.40.0": +"eslint@npm:^8.23.0, eslint@npm:^8.40.0": version: 8.57.0 resolution: "eslint@npm:8.57.0" dependencies: @@ -23129,18 +17335,7 @@ __metadata: languageName: node linkType: hard -"espree@npm:^9.6.0": - version: 9.6.0 - resolution: "espree@npm:9.6.0" - dependencies: - acorn: ^8.9.0 - acorn-jsx: ^5.3.2 - eslint-visitor-keys: ^3.4.1 - checksum: f064a43bcf7f435d34e600c056320dde1c15b3eeb5da24e7585ed6cf83adcbbeafb4fa4d062ff14281b0d246b0a9645dd9d3796a638099f19595004eee4ac8be - languageName: node - linkType: hard - -"espree@npm:^9.6.1": +"espree@npm:^9.6.0, espree@npm:^9.6.1": version: 9.6.1 resolution: "espree@npm:9.6.1" dependencies: @@ -23170,7 +17365,7 @@ __metadata: languageName: node linkType: hard -"esrecurse@npm:^4.1.0, esrecurse@npm:^4.3.0": +"esrecurse@npm:^4.3.0": version: 4.3.0 resolution: "esrecurse@npm:4.3.0" dependencies: @@ -23193,17 +17388,6 @@ __metadata: languageName: node linkType: hard -"estree-to-babel@npm:^3.1.0": - version: 3.2.1 - resolution: "estree-to-babel@npm:3.2.1" - dependencies: - "@babel/traverse": ^7.1.6 - "@babel/types": ^7.2.0 - c8: ^7.6.0 - checksum: c7949b141f569528b2608ab715d593a04f7e2e529df04e0b595d0a7dea819b410e71d1f04716e43ac1480942afc5701cb5151ad2906ee8402969651a389881bb - languageName: node - linkType: hard - "estree-walker@npm:^0.6.1": version: 0.6.1 resolution: "estree-walker@npm:0.6.1" @@ -23246,28 +17430,17 @@ __metadata: languageName: node linkType: hard -"eventemitter3@npm:^4.0.4, eventemitter3@npm:^4.0.7": +"eventemitter3@npm:^4.0.4": version: 4.0.7 resolution: "eventemitter3@npm:4.0.7" checksum: 5f6d97cbcbac47be798e6355e3a7639a84ee1f7d9b199a07017f1d2f1e2fe236004d14fa5dfaeba661f94ea57805385e326236a6debbc7145c8877fbc0297c6b languageName: node linkType: hard -"events@npm:^3.0.0, events@npm:^3.2.0, events@npm:^3.3.0": - version: 3.3.0 - resolution: "events@npm:3.3.0" - checksum: d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6 - languageName: node - linkType: hard - -"evp_bytestokey@npm:^1.0.0, evp_bytestokey@npm:^1.0.3": - version: 1.0.3 - resolution: "evp_bytestokey@npm:1.0.3" - dependencies: - md5.js: ^1.3.4 - node-gyp: latest - safe-buffer: ^5.1.1 - checksum: 77fbe2d94a902a80e9b8f5a73dcd695d9c14899c5e82967a61b1fc6cbbb28c46552d9b127cff47c45fcf684748bdbcfa0a50410349109de87ceb4b199ef6ee99 +"eventemitter3@npm:^5.0.1": + version: 5.0.1 + resolution: "eventemitter3@npm:5.0.1" + checksum: 4ba5c00c506e6c786b4d6262cfbce90ddc14c10d4667e5c83ae993c9de88aa856033994dd2b35b83e8dc1170e224e66a319fa80adc4c32adcd2379bbc75da814 languageName: node linkType: hard @@ -23362,6 +17535,23 @@ __metadata: languageName: node linkType: hard +"execa@npm:^8.0.1": + version: 8.0.1 + resolution: "execa@npm:8.0.1" + dependencies: + cross-spawn: ^7.0.3 + get-stream: ^8.0.1 + human-signals: ^5.0.0 + is-stream: ^3.0.0 + merge-stream: ^2.0.0 + npm-run-path: ^5.1.0 + onetime: ^6.0.0 + signal-exit: ^4.1.0 + strip-final-newline: ^3.0.0 + checksum: 2c52d8775f5bf103ce8eec9c7ab3059909ba350a5164744e9947ed14a53f51687c040a250bda833f906d1283aa8803975b84e6c8f7a7c42f99dc8ef80250d1af + languageName: node + linkType: hard + "exit@npm:^0.1.2": version: 0.1.2 resolution: "exit@npm:0.1.2" @@ -23437,32 +17627,6 @@ __metadata: languageName: node linkType: hard -"expect@npm:^29.5.0": - version: 29.5.0 - resolution: "expect@npm:29.5.0" - dependencies: - "@jest/expect-utils": ^29.5.0 - jest-get-type: ^29.4.3 - jest-matcher-utils: ^29.5.0 - jest-message-util: ^29.5.0 - jest-util: ^29.5.0 - checksum: 3c9382967217ad1453e9271e0da3f83c4aeb12272968007b90fc5873340e7fb64bf4852e1522bdf27556623d031ce62f82aaac09e485a15c6d0589d50999422d - languageName: node - linkType: hard - -"expect@npm:^29.6.4": - version: 29.6.4 - resolution: "expect@npm:29.6.4" - dependencies: - "@jest/expect-utils": ^29.6.4 - jest-get-type: ^29.6.3 - jest-matcher-utils: ^29.6.4 - jest-message-util: ^29.6.3 - jest-util: ^29.6.3 - checksum: d3f4ed2fcc33f743b1dd9cf25a07c2f56c9ddd7e1b327d3e74b5febfc90880a9e2ab10c56b3bf31e14d5ead69dc4cb68f718b7fbc3fae8571f8e18675ffe8080 - languageName: node - linkType: hard - "exponential-backoff@npm:^3.1.1": version: 3.1.1 resolution: "exponential-backoff@npm:3.1.1" @@ -23471,18 +17635,18 @@ __metadata: linkType: hard "express-session@npm:^1.17.3": - version: 1.17.3 - resolution: "express-session@npm:1.17.3" + version: 1.18.0 + resolution: "express-session@npm:1.18.0" dependencies: - cookie: 0.4.2 - cookie-signature: 1.0.6 + cookie: 0.6.0 + cookie-signature: 1.0.7 debug: 2.6.9 depd: ~2.0.0 on-headers: ~1.0.2 parseurl: ~1.3.3 safe-buffer: 5.2.1 uid-safe: ~2.1.5 - checksum: 6b53da479b46c58c480d00fc9a76e5cc22a706404ae6eb8eb7b09148f7a0c07517bb8957397eae4dbe72a3e4d79b39b69da448b3fb94744b28713c716355dec9 + checksum: 5c3f1237f2789cf32f9cd668d3217c228916edfd3b5a686a894a80c7cca63f9ef66bb86a8457074b9b4cc4b2ee97e16781dd4e0cff7829b671ab0db5da0db638 languageName: node linkType: hard @@ -23525,15 +17689,15 @@ __metadata: linkType: hard "express@npm:^4.17.1, express@npm:^4.17.3, express@npm:^4.18.2": - version: 4.18.2 - resolution: "express@npm:4.18.2" + version: 4.19.2 + resolution: "express@npm:4.19.2" dependencies: accepts: ~1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.1 + body-parser: 1.20.2 content-disposition: 0.5.4 content-type: ~1.0.4 - cookie: 0.5.0 + cookie: 0.6.0 cookie-signature: 1.0.6 debug: 2.6.9 depd: 2.0.0 @@ -23559,7 +17723,7 @@ __metadata: type-is: ~1.6.18 utils-merge: 1.0.1 vary: ~1.1.2 - checksum: 75af556306b9241bc1d7bdd40c9744b516c38ce50ae3210658efcbf96e3aed4ab83b3432f06215eae5610c123bc4136957dc06e50dfc50b7d4d775af56c4c59c + checksum: e82e2662ea9971c1407aea9fc3c16d6b963e55e3830cd0ef5e00b533feda8b770af4e3be630488ef8a752d7c75c4fcefb15892868eeaafe7353cb9e3e269fdcb languageName: node linkType: hard @@ -23665,13 +17829,6 @@ __metadata: languageName: node linkType: hard -"faker@npm:^6.6.6": - version: 6.6.6 - resolution: "faker@npm:6.6.6" - checksum: 21f6a57adc921ffb61e5ff767024a699a414047264ff4bbb080bd4994ec5a8061e1828aae9a4be812f6f356f1b6fd082bc2d54df7c37163b943a421a8f7f7079 - languageName: node - linkType: hard - "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -23686,50 +17843,16 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^2.2.6": - version: 2.2.7 - resolution: "fast-glob@npm:2.2.7" - dependencies: - "@mrmlnc/readdir-enhanced": ^2.2.1 - "@nodelib/fs.stat": ^1.1.2 - glob-parent: ^3.1.0 - is-glob: ^4.0.0 - merge2: ^1.2.3 - micromatch: ^3.1.10 - checksum: 85bc858e298423d5a1b6eed6eee8556005a19d245c4ae9aceac04d56699ea9885ca0a2afc4f76b562416e94fe2048df6b2f306f3d4b7e51ed37b7a52fc1e4fc7 - languageName: node - linkType: hard - -"fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9": - version: 3.3.0 - resolution: "fast-glob@npm:3.3.0" +"fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0": + version: 3.3.2 + resolution: "fast-glob@npm:3.3.2" dependencies: "@nodelib/fs.stat": ^2.0.2 "@nodelib/fs.walk": ^1.2.3 glob-parent: ^5.1.2 merge2: ^1.3.0 micromatch: ^4.0.4 - checksum: 4700063a2d7c9aae178f575648580bee1fc3f02ab3f358236d77811f52332bc10a398e75c6d5ecde61216996f3308247b37d70e2ee605a0748abe147f01b8f64 - languageName: node - linkType: hard - -"fast-glob@npm:^3.3.0": - version: 3.3.1 - resolution: "fast-glob@npm:3.3.1" - dependencies: - "@nodelib/fs.stat": ^2.0.2 - "@nodelib/fs.walk": ^1.2.3 - glob-parent: ^5.1.2 - merge2: ^1.3.0 - micromatch: ^4.0.4 - checksum: b68431128fb6ce4b804c5f9622628426d990b66c75b21c0d16e3d80e2d1398bf33f7e1724e66a2e3f299285dcf5b8d745b122d0304e7dd66f5231081f33ec67c - languageName: node - linkType: hard - -"fast-json-parse@npm:^1.0.3": - version: 1.0.3 - resolution: "fast-json-parse@npm:1.0.3" - checksum: 2c58c7a0f7f1725c9da1272839f9bee3ccc13b77672b18ab4ac470c707999bca39828cd7e79b87c73017f21c3ddff37992d03fa2fd2da124d9bd06c1d02c9b7e + checksum: 42baad7b9cd40b63e42039132bde27ca2cb3a4950d0a0f9abe4639ea1aa9d3e3b40f98b1fe31cbc0cc17b664c9ea7447d911a152fa34ec5b72977b125a6fc845 languageName: node linkType: hard @@ -23766,11 +17889,11 @@ __metadata: linkType: hard "fastq@npm:^1.6.0": - version: 1.15.0 - resolution: "fastq@npm:1.15.0" + version: 1.17.1 + resolution: "fastq@npm:1.17.1" dependencies: reusify: ^1.0.4 - checksum: 5ce4f83afa5f88c9379e67906b4d31bc7694a30826d6cc8d0f0473c966929017fda65c2174b0ec89f064ede6ace6c67f8a4fe04cef42119b6a55b0d465554c24 + checksum: 1095f16cea45fb3beff558bb3afa74ca7a9250f5a670b65db7ed585f92b4b48381445cd328b3d87323da81e43232b5d5978a8201bde84e0cd514310f1ea6da34 languageName: node linkType: hard @@ -23783,37 +17906,6 @@ __metadata: languageName: node linkType: hard -"fbemitter@npm:^3.0.0": - version: 3.0.0 - resolution: "fbemitter@npm:3.0.0" - dependencies: - fbjs: ^3.0.0 - checksum: f130dd8e15dc3fc6709a26586b7a589cd994e1d1024b624f2cc8ef1b12401536a94bb30038e68150a24f9ba18863e9a3fe87941ade2c87667bfbd17f4848d5c7 - languageName: node - linkType: hard - -"fbjs-css-vars@npm:^1.0.0": - version: 1.0.2 - resolution: "fbjs-css-vars@npm:1.0.2" - checksum: dfb64116b125a64abecca9e31477b5edb9a2332c5ffe74326fe36e0a72eef7fc8a49b86adf36c2c293078d79f4524f35e80f5e62546395f53fb7c9e69821f54f - languageName: node - linkType: hard - -"fbjs@npm:^3.0.0, fbjs@npm:^3.0.1": - version: 3.0.5 - resolution: "fbjs@npm:3.0.5" - dependencies: - cross-fetch: ^3.1.5 - fbjs-css-vars: ^1.0.0 - loose-envify: ^1.0.0 - object-assign: ^4.1.0 - promise: ^7.1.1 - setimmediate: ^1.0.5 - ua-parser-js: ^1.0.35 - checksum: 66d0a2fc9a774f9066e35ac2ac4bf1245931d27f3ac287c7d47e6aa1fc152b243c2109743eb8f65341e025621fb51a12038fadb9fd8fda2e3ddae04ebab06f91 - languageName: node - linkType: hard - "fd-slicer@npm:~1.1.0": version: 1.1.0 resolution: "fd-slicer@npm:1.1.0" @@ -23879,19 +17971,12 @@ __metadata: languageName: node linkType: hard -"figgy-pudding@npm:^3.5.1": - version: 3.5.2 - resolution: "figgy-pudding@npm:3.5.2" - checksum: b21c7adaeb8485ef3c50e056b5dc8c3a6461818343aba141e0d7927aad47a0cb9f1d207ffdf494c380cd60d7c848c46a5ce5cb06987d10e9226fcec419c8af90 - languageName: node - linkType: hard - "figlet@npm:^1.5.2": - version: 1.6.0 - resolution: "figlet@npm:1.6.0" + version: 1.7.0 + resolution: "figlet@npm:1.7.0" bin: figlet: bin/index.js - checksum: 98e19ee0c112b3a0c9a23751842c97c0c11d748b485674b9bf4037338fe98afbc6f943e3514949ae4bf75dc759322452bdf2487c4b000d17514e98f176849d1b + checksum: bedd97fe5fa604002ae8c6bc0b08dea6f9701e0b268f42e601668956f50ff377ef592e24e182a6174a775abde9e2aa77697e324b8681619ae23bc85078439393 languageName: node linkType: hard @@ -23923,18 +18008,6 @@ __metadata: languageName: node linkType: hard -"file-loader@npm:^6.2.0": - version: 6.2.0 - resolution: "file-loader@npm:6.2.0" - dependencies: - loader-utils: ^2.0.0 - schema-utils: ^3.0.0 - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: e176a57c2037ab0f78e5755dbf293a6b7f0f8392350a120bd03cc2ce2525bea017458ba28fea14ca535ff1848055e86d1a3a216bdb2561ef33395b27260a1dd3 - languageName: node - linkType: hard - "file-system-cache@npm:2.3.0": version: 2.3.0 resolution: "file-system-cache@npm:2.3.0" @@ -23945,23 +18018,6 @@ __metadata: languageName: node linkType: hard -"file-system-cache@npm:^1.0.5": - version: 1.1.0 - resolution: "file-system-cache@npm:1.1.0" - dependencies: - fs-extra: ^10.1.0 - ramda: ^0.28.0 - checksum: a04322ab12e77b5b5d3bed1259f9aa431d26b9e161445f25eb8e539845cc0051a4d501840a726cad83db727b40b88dd113a7e97e8b136690ce108f363eb116e9 - languageName: node - linkType: hard - -"file-uri-to-path@npm:1.0.0": - version: 1.0.0 - resolution: "file-uri-to-path@npm:1.0.0" - checksum: 3b545e3a341d322d368e880e1c204ef55f1d45cdea65f7efc6c6ce9e0c4d22d802d5629320eb779d006fe59624ac17b0e848d83cc5af7cd101f206cb704f5519 - languageName: node - linkType: hard - "filelist@npm:^1.0.4": version: 1.0.4 resolution: "filelist@npm:1.0.4" @@ -24029,7 +18085,7 @@ __metadata: languageName: node linkType: hard -"find-cache-dir@npm:^2.0.0, find-cache-dir@npm:^2.1.0": +"find-cache-dir@npm:^2.0.0": version: 2.1.0 resolution: "find-cache-dir@npm:2.1.0" dependencies: @@ -24051,16 +18107,6 @@ __metadata: languageName: node linkType: hard -"find-up@npm:^1.0.0": - version: 1.1.2 - resolution: "find-up@npm:1.1.2" - dependencies: - path-exists: ^2.0.0 - pinkie-promise: ^2.0.0 - checksum: 51e35c62d9b7efe82d7d5cce966bfe10c2eaa78c769333f8114627e3a8a4a4f50747f5f50bff50b1094cbc6527776f0d3b9ff74d3561ef714a5290a17c80c2bc - languageName: node - linkType: hard - "find-up@npm:^3.0.0": version: 3.0.0 resolution: "find-up@npm:3.0.0" @@ -24110,48 +18156,27 @@ __metadata: linkType: hard "flat-cache@npm:^3.0.4": - version: 3.0.4 - resolution: "flat-cache@npm:3.0.4" + version: 3.2.0 + resolution: "flat-cache@npm:3.2.0" dependencies: - flatted: ^3.1.0 + flatted: ^3.2.9 + keyv: ^4.5.3 rimraf: ^3.0.2 - checksum: f274dcbadb09ad8d7b6edf2ee9b034bc40bf0c12638f6c4084e9f1d39208cb104a5ebbb24b398880ef048200eaa116852f73d2d8b72e8c9627aba8c3e27ca057 + checksum: b76f611bd5f5d68f7ae632e3ae503e678d205cf97a17c6ab5b12f6ca61188b5f1f7464503efae6dc18683ed8f0b41460beb48ac4b9ac63fe6201296a91ba2f75 languageName: node linkType: hard -"flatted@npm:^3.1.0": - version: 3.2.7 - resolution: "flatted@npm:3.2.7" - checksum: 207a87c7abfc1ea6928ea16bac84f9eaa6d44d365620ece419e5c41cf44a5e9902b4c1f59c9605771b10e4565a0cb46e99d78e0464e8aabb42c97de880642257 +"flatted@npm:^3.2.9": + version: 3.3.1 + resolution: "flatted@npm:3.3.1" + checksum: 324166b125ee07d4ca9bcf3a5f98d915d5db4f39d711fba640a3178b959919aae1f7cfd8aabcfef5826ed8aa8a2aa14cc85b2d7d18ff638ddf4ae3df39573eaf languageName: node linkType: hard "flow-parser@npm:0.*": - version: 0.219.4 - resolution: "flow-parser@npm:0.219.4" - checksum: 4a85ddd4b137c46664be4ab8ba8b9883ddc58564017d3fa5223a9b7087b441d474b8cb8589ffbeeb3e5f6ea37bef9153ebd5075a1722c6d550974f1eefefa999 - languageName: node - linkType: hard - -"flush-write-stream@npm:^1.0.0": - version: 1.1.1 - resolution: "flush-write-stream@npm:1.1.1" - dependencies: - inherits: ^2.0.3 - readable-stream: ^2.3.6 - checksum: 2cd4f65b728d5f388197a03dafabc6a5e4f0c2ed1a2d912e288f7aa1c2996dd90875e55b50cf32c78dca55ad2e2dfae5d3db09b223838388033d87cf5920dd87 - languageName: node - linkType: hard - -"flux@npm:^4.0.1": - version: 4.0.4 - resolution: "flux@npm:4.0.4" - dependencies: - fbemitter: ^3.0.0 - fbjs: ^3.0.1 - peerDependencies: - react: ^15.0.2 || ^16.0.0 || ^17.0.0 - checksum: 948bc01b97ff21babc8bfe5c40543d643ca126b71edd447a9ac051b05d20fd549a6bcc4afe043bcde56201782e688a5eaeda1bd8e3e58915641abdd5b3ea21e0 + version: 0.235.1 + resolution: "flow-parser@npm:0.235.1" + checksum: 6960c7374a88e8b3341bc23d69e63f59aee405f202380c2494a1986c1f33af7a9986e62ad2dbc7cc4d914134db6c53d715f08eb6bc978275b64f0515e995a252 languageName: node linkType: hard @@ -24162,17 +18187,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.4": - version: 1.15.2 - resolution: "follow-redirects@npm:1.15.2" - peerDependenciesMeta: - debug: - optional: true - checksum: da5932b70e63944d38eecaa16954bac4347036f08303c913d166eda74809d8797d38386e3a0eb1d2fe37d2aaff2764cce8e9dbd99459d860cf2cdfa237923b5f - languageName: node - linkType: hard - -"follow-redirects@npm:^1.15.0, follow-redirects@npm:^1.15.6": +"follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.4, follow-redirects@npm:^1.15.0, follow-redirects@npm:^1.15.6": version: 1.15.6 resolution: "follow-redirects@npm:1.15.6" peerDependenciesMeta: @@ -24205,16 +18220,6 @@ __metadata: languageName: node linkType: hard -"foreground-child@npm:^2.0.0": - version: 2.0.0 - resolution: "foreground-child@npm:2.0.0" - dependencies: - cross-spawn: ^7.0.0 - signal-exit: ^3.0.2 - checksum: 6719982783a448162f9a01500757fb2053bc5dcd4d67c7cd30739b38ccc01b39f84e408c30989d1d8774519c021c0498e2450ab127690fb09d7f2568fd94ffcc - languageName: node - linkType: hard - "foreground-child@npm:^3.1.0": version: 3.1.1 resolution: "foreground-child@npm:3.1.1" @@ -24232,52 +18237,6 @@ __metadata: languageName: node linkType: hard -"fork-ts-checker-webpack-plugin@npm:^4.1.6": - version: 4.1.6 - resolution: "fork-ts-checker-webpack-plugin@npm:4.1.6" - dependencies: - "@babel/code-frame": ^7.5.5 - chalk: ^2.4.1 - micromatch: ^3.1.10 - minimatch: ^3.0.4 - semver: ^5.6.0 - tapable: ^1.0.0 - worker-rpc: ^0.1.0 - checksum: 2dddbe0d3bf2b84f4a5daada41091003decf881cffdef3bab72a699d0bfe3003e2d312405b304894153b5cfd0d0180d47f547e256525cdeb20f95de3df14a223 - languageName: node - linkType: hard - -"fork-ts-checker-webpack-plugin@npm:^6.0.4": - version: 6.5.3 - resolution: "fork-ts-checker-webpack-plugin@npm:6.5.3" - dependencies: - "@babel/code-frame": ^7.8.3 - "@types/json-schema": ^7.0.5 - chalk: ^4.1.0 - chokidar: ^3.4.2 - cosmiconfig: ^6.0.0 - deepmerge: ^4.2.2 - fs-extra: ^9.0.0 - glob: ^7.1.6 - memfs: ^3.1.2 - minimatch: ^3.0.4 - schema-utils: 2.7.0 - semver: ^7.3.2 - tapable: ^1.0.0 - peerDependencies: - eslint: ">= 6" - typescript: ">= 2.7" - vue-template-compiler: "*" - webpack: ">= 4" - peerDependenciesMeta: - eslint: - optional: true - vue-template-compiler: - optional: true - checksum: 0885ea75474de011d4068ca3e2d3ca6e4cd318f5cfa018e28ff8fef23ef3a1f1c130160ef192d3e5d31ef7b6fe9f8fb1d920eab5e9e449fb30ce5cc96647245c - languageName: node - linkType: hard - "form-data@npm:4.0.0, form-data@npm:^4.0.0": version: 4.0.0 resolution: "form-data@npm:4.0.0" @@ -24345,14 +18304,7 @@ __metadata: languageName: node linkType: hard -"fraction.js@npm:^4.2.0": - version: 4.2.0 - resolution: "fraction.js@npm:4.2.0" - checksum: b16c0a6a7f045b3416c1afbb174b7afca73bd7eb0c62598a0c734a8b1f888cb375684174daf170abfba314da9f366b7d6445e396359d5fae640883bdb2ed18cb - languageName: node - linkType: hard - -"fraction.js@npm:^4.3.6, fraction.js@npm:^4.3.7": +"fraction.js@npm:^4.3.7": version: 4.3.7 resolution: "fraction.js@npm:4.3.7" checksum: df291391beea9ab4c263487ffd9d17fed162dbb736982dee1379b2a8cc94e4e24e46ed508c6d278aded9080ba51872f1bc5f3a5fd8d7c74e5f105b508ac28711 @@ -24369,23 +18321,22 @@ __metadata: linkType: hard "framer-motion@npm:^11.0.3": - version: 11.0.3 - resolution: "framer-motion@npm:11.0.3" + version: 11.1.8 + resolution: "framer-motion@npm:11.1.8" dependencies: - "@emotion/is-prop-valid": ^0.8.2 tslib: ^2.4.0 peerDependencies: + "@emotion/is-prop-valid": "*" react: ^18.0.0 react-dom: ^18.0.0 - dependenciesMeta: + peerDependenciesMeta: "@emotion/is-prop-valid": optional: true - peerDependenciesMeta: react: optional: true react-dom: optional: true - checksum: a9a70196ea5d264f749a7dea1ccb7c33decf969680a907c595eb48d84510b60fb51e3e0d16d5bcac0997eea041f796f2cba4a5505e0a00f373ffbadfb5f36564 + checksum: ff7073ca011936fcf0e4af54ff93824609cf03b556def5a69d21f44674c44ec0429a450b419bb4ae89d5b7af9d7b0e88ed57d3eff1ff668ed2a52b42a60375dd languageName: node linkType: hard @@ -24396,16 +18347,6 @@ __metadata: languageName: node linkType: hard -"from2@npm:^2.1.0": - version: 2.3.0 - resolution: "from2@npm:2.3.0" - dependencies: - inherits: ^2.0.1 - readable-stream: ^2.0.0 - checksum: f87f7a2e4513244d551454a7f8324ef1f7837864a8701c536417286ec19ff4915606b1dfa8909a21b7591ebd8440ffde3642f7c303690b9a4d7c832d62248aa1 - languageName: node - linkType: hard - "fs-constants@npm:^1.0.0": version: 1.0.0 resolution: "fs-constants@npm:1.0.0" @@ -24420,7 +18361,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:11.1.1, fs-extra@npm:^11.1.0": +"fs-extra@npm:11.1.1": version: 11.1.1 resolution: "fs-extra@npm:11.1.1" dependencies: @@ -24453,7 +18394,18 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^7.0.1": +"fs-extra@npm:^11.1.0": + version: 11.2.0 + resolution: "fs-extra@npm:11.2.0" + dependencies: + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: d77a9a9efe60532d2e790e938c81a02c1b24904ef7a3efb3990b835514465ba720e99a6ea56fd5e2db53b4695319b644d76d5a0e9988a2beef80aa7b1da63398 + languageName: node + linkType: hard + +"fs-extra@npm:^7.0.1, fs-extra@npm:~7.0.1": version: 7.0.1 resolution: "fs-extra@npm:7.0.1" dependencies: @@ -24464,7 +18416,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^9.0.0, fs-extra@npm:^9.0.1": +"fs-extra@npm:^9.0.1": version: 9.1.0 resolution: "fs-extra@npm:9.1.0" dependencies: @@ -24486,18 +18438,11 @@ __metadata: linkType: hard "fs-minipass@npm:^3.0.0": - version: 3.0.2 - resolution: "fs-minipass@npm:3.0.2" + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" dependencies: - minipass: ^5.0.0 - checksum: 34726f25b968ac05f6122ea7e9457fe108c7ae3b82beff0256953b0e405def61af2850570e32be2eb05c1e7660b663f24e14b6ab882d1d8a858314faacc4c972 - languageName: node - linkType: hard - -"fs-monkey@npm:^1.0.4": - version: 1.0.4 - resolution: "fs-monkey@npm:1.0.4" - checksum: eeb2457ec50f7202c44273de2a42b50868c8e6b2ab4825d517947143d4e727c028e24f6d0f46e6f3e7a149a1c9e7d8b3ca28243c3b10366d280a08016483e829 + minipass: ^7.0.3 + checksum: 63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 languageName: node linkType: hard @@ -24508,18 +18453,6 @@ __metadata: languageName: node linkType: hard -"fs-write-stream-atomic@npm:^1.0.8": - version: 1.0.10 - resolution: "fs-write-stream-atomic@npm:1.0.10" - dependencies: - graceful-fs: ^4.1.2 - iferr: ^0.1.5 - imurmurhash: ^0.1.4 - readable-stream: 1 || 2 - checksum: 293b2b4ed346d35a28f8637a20cb2aef31be86503da501c42c2eda8fefed328bac16ce0e5daa7019f9329d73930c58031eaea2ce0c70f1680943fbfb7cff808b - languageName: node - linkType: hard - "fs.realpath@npm:^1.0.0": version: 1.0.0 resolution: "fs.realpath@npm:1.0.0" @@ -24527,28 +18460,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:^1.2.7": - version: 1.2.13 - resolution: "fsevents@npm:1.2.13" - dependencies: - bindings: ^1.5.0 - nan: ^2.12.1 - checksum: 4427ff08db9ee7327f2c3ad58ec56f9096a917eed861bfffaa2e2be419479cdf37d00750869ab9ecbf5f59f32ad999bd59577d73fc639193e6c0ce52bb253e02 - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@npm:^2.1.2, fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": - version: 2.3.2 - resolution: "fsevents@npm:2.3.2" - dependencies: - node-gyp: latest - checksum: be78a3efa3e181cda3cf7a4637cb527bcebb0bd0ea0440105a3bb45b86f9245b307dc10a2507e8f4498a7d4ec349d1910f4d73e4d4495b16103106e07eee735b - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@npm:~2.3.3": +"fsevents@npm:^2.1.2, fsevents@npm:^2.3.2, fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": version: 2.3.3 resolution: "fsevents@npm:2.3.3" dependencies: @@ -24558,26 +18470,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@^1.2.7#~builtin": - version: 1.2.13 - resolution: "fsevents@patch:fsevents@npm%3A1.2.13#~builtin::version=1.2.13&hash=18f3a7" - dependencies: - bindings: ^1.5.0 - nan: ^2.12.1 - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@^2.1.2#~builtin, fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": - version: 2.3.2 - resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=18f3a7" - dependencies: - node-gyp: latest - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@~2.3.3#~builtin": +"fsevents@patch:fsevents@^2.1.2#~builtin, fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin, fsevents@patch:fsevents@~2.3.3#~builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=18f3a7" dependencies: @@ -24586,13 +18479,6 @@ __metadata: languageName: node linkType: hard -"function-bind@npm:^1.1.1": - version: 1.1.1 - resolution: "function-bind@npm:1.1.1" - checksum: 60b74b2407e1942e1ed7f8c284f8ef714d0689dcfce5319985a5b7da3fc727f40b4a59ec72dc55aa83365ad7b8fa4fac3a30d93c850a2b452f29ae03dbc10a1e - languageName: node - linkType: hard - "function-bind@npm:^1.1.2": version: 1.1.2 resolution: "function-bind@npm:1.1.2" @@ -24600,15 +18486,15 @@ __metadata: languageName: node linkType: hard -"function.prototype.name@npm:^1.1.0, function.prototype.name@npm:^1.1.5": - version: 1.1.5 - resolution: "function.prototype.name@npm:1.1.5" +"function.prototype.name@npm:^1.1.5, function.prototype.name@npm:^1.1.6": + version: 1.1.6 + resolution: "function.prototype.name@npm:1.1.6" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.3 - es-abstract: ^1.19.0 - functions-have-names: ^1.2.2 - checksum: b75fb8c5261f03a54f7cb53a8c99e0c40297efc3cf750c51d3a2e56f6741701c14eda51986d30c24063136a4c32d1643df9d1dd2f2a14b64fa011edd3e7117ae + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + functions-have-names: ^1.2.3 + checksum: 9eae11294905b62cb16874adb4fc687927cda3162285e0ad9612e6a1d04934005d46907362ea9cdb7428edce05a2f2c3dabc3b2d21e9fd343e9bb278230ad94b languageName: node linkType: hard @@ -24619,46 +18505,13 @@ __metadata: languageName: node linkType: hard -"functions-have-names@npm:^1.2.2, functions-have-names@npm:^1.2.3": +"functions-have-names@npm:^1.2.3": version: 1.2.3 resolution: "functions-have-names@npm:1.2.3" checksum: 33e77fd29bddc2d9bb78ab3eb854c165909201f88c75faa8272e35899e2d35a8a642a15e7420ef945e1f64a9670d6aa3ec744106b2aa42be68ca5114025954ca languageName: node linkType: hard -"gauge@npm:^3.0.0": - version: 3.0.2 - resolution: "gauge@npm:3.0.2" - dependencies: - aproba: ^1.0.3 || ^2.0.0 - color-support: ^1.1.2 - console-control-strings: ^1.0.0 - has-unicode: ^2.0.1 - object-assign: ^4.1.1 - signal-exit: ^3.0.0 - string-width: ^4.2.3 - strip-ansi: ^6.0.1 - wide-align: ^1.1.2 - checksum: 75230ccaf216471e31025c7d5fcea1629596ca20792de50c596eb18ffb14d8404f927cd55535aab2eeecd18d1e11bd6f23ec3c2e9878d2dda1dc74bccc34b913 - languageName: node - linkType: hard - -"gauge@npm:^4.0.3": - version: 4.0.4 - resolution: "gauge@npm:4.0.4" - dependencies: - aproba: ^1.0.3 || ^2.0.0 - color-support: ^1.1.3 - console-control-strings: ^1.1.0 - has-unicode: ^2.0.1 - signal-exit: ^3.0.7 - string-width: ^4.2.3 - strip-ansi: ^6.0.1 - wide-align: ^1.1.5 - checksum: ef10d7981113d69225135f994c9f8c4369d945e64a8fc721d655a3a38421b738c9fe899951721d1b47b73c41fdb5404ac87cc8903b2ecbed95d2800363e7e58c - languageName: node - linkType: hard - "generic-names@npm:^4.0.0": version: 4.0.0 resolution: "generic-names@npm:4.0.0" @@ -24668,7 +18521,7 @@ __metadata: languageName: node linkType: hard -"gensync@npm:^1.0.0-beta.1, gensync@npm:^1.0.0-beta.2": +"gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" checksum: 782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8 @@ -24689,19 +18542,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0": - version: 1.2.1 - resolution: "get-intrinsic@npm:1.2.1" - dependencies: - function-bind: ^1.1.1 - has: ^1.0.3 - has-proto: ^1.0.1 - has-symbols: ^1.0.3 - checksum: 49eab47f9de8f1a4f9b458b8b74ee5199fb2614414a91973eb175e07db56b52b6df49b255cc7ff704cb0786490fb93bfe8f2ad138b590a8de09b47116a366bc9 - languageName: node - linkType: hard - -"get-intrinsic@npm:^1.2.4": +"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": version: 1.2.4 resolution: "get-intrinsic@npm:1.2.4" dependencies: @@ -24722,9 +18563,9 @@ __metadata: linkType: hard "get-npm-tarball-url@npm:^2.0.3": - version: 2.0.3 - resolution: "get-npm-tarball-url@npm:2.0.3" - checksum: fdf7a830d2602dd3d86285f412c9b2984ffe6ce854e1854e9548ea2b2f09f663b83791a31703552f8c72266d67c72e94c70f8d50a886fe5179d2f07a383660d8 + version: 2.1.0 + resolution: "get-npm-tarball-url@npm:2.1.0" + checksum: af779fa5b9c89a3deaf9640630a23368f5ba6a028a1179872aaf581a59485fb2c2c6bd9b94670de228cfc5f23600c89a01e594879085f7fb4dddf820a63105b8 languageName: node linkType: hard @@ -24756,13 +18597,6 @@ __metadata: languageName: node linkType: hard -"get-stdin@npm:^4.0.1": - version: 4.0.1 - resolution: "get-stdin@npm:4.0.1" - checksum: 68fc39a0af6050bcad791fb3df72999e7636401f11f574bf24af07b1c640d30c01cf38aa39ee55665a93ee7a7753eeb6d1fce6c434dd1f458ee0f8fd02775809 - languageName: node - linkType: hard - "get-stream@npm:^4.0.0": version: 4.1.0 resolution: "get-stream@npm:4.1.0" @@ -24788,13 +18622,21 @@ __metadata: languageName: node linkType: hard -"get-symbol-description@npm:^1.0.0": - version: 1.0.0 - resolution: "get-symbol-description@npm:1.0.0" +"get-stream@npm:^8.0.1": + version: 8.0.1 + resolution: "get-stream@npm:8.0.1" + checksum: 5c2181e98202b9dae0bb4a849979291043e5892eb40312b47f0c22b9414fc9b28a3b6063d2375705eb24abc41ecf97894d9a51f64ff021511b504477b27b4290 + languageName: node + linkType: hard + +"get-symbol-description@npm:^1.0.2": + version: 1.0.2 + resolution: "get-symbol-description@npm:1.0.2" dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.1 - checksum: 23bc3b44c221cdf7669a88230c62f4b9e30393b61eb21ba4400cb3e346801bd8f95fe4330ee78dbae37aecd874646d53e3e76a17a654d0c84c77f6690526d6bb + call-bind: ^1.0.5 + es-errors: ^1.3.0 + get-intrinsic: ^1.2.4 + checksum: 867be6d63f5e0eb026cb3b0ef695ec9ecf9310febb041072d2e142f260bd91ced9eeb426b3af98791d1064e324e653424afa6fd1af17dee373bea48ae03162bc languageName: node linkType: hard @@ -24822,19 +18664,20 @@ __metadata: linkType: hard "giget@npm:^1.0.0": - version: 1.1.3 - resolution: "giget@npm:1.1.3" + version: 1.2.3 + resolution: "giget@npm:1.2.3" dependencies: - colorette: ^2.0.20 - defu: ^6.1.2 - https-proxy-agent: ^7.0.2 - mri: ^1.2.0 - node-fetch-native: ^1.4.0 - pathe: ^1.1.1 + citty: ^0.1.6 + consola: ^3.2.3 + defu: ^6.1.4 + node-fetch-native: ^1.6.3 + nypm: ^0.3.8 + ohash: ^1.1.3 + pathe: ^1.1.2 tar: ^6.2.0 bin: giget: dist/cli.mjs - checksum: 7f3d3628f4c488ab543e2edcd93b6899b2486a0afc2caab748ad65714d631f5cdfc9cf00404ed21b390c070cf5214037dffb593cd667c54b97adc6a1c657cdf9 + checksum: 0e82836783c704346fdda83e23d144e97f28a959320b1d8ee73c69a5af562362bcb727cf6ad99f90e45ed8a6abec140833534bb1fedcaa1c06fa026daaf3119c languageName: node linkType: hard @@ -24873,17 +18716,6 @@ __metadata: languageName: node linkType: hard -"glob-promise@npm:^3.4.0": - version: 3.4.0 - resolution: "glob-promise@npm:3.4.0" - dependencies: - "@types/glob": "*" - peerDependencies: - glob: "*" - checksum: 8862e309f46a97c9491d35900257c9174f72b8358a8f485cdba88eb2d5b0f9cf496dfe635711bbd871e89165f50ec3acd435cbef5bfc5efbc14508abced778ac - languageName: node - linkType: hard - "glob-promise@npm:^4.2.0": version: 4.2.2 resolution: "glob-promise@npm:4.2.2" @@ -24895,13 +18727,6 @@ __metadata: languageName: node linkType: hard -"glob-to-regexp@npm:^0.3.0": - version: 0.3.0 - resolution: "glob-to-regexp@npm:0.3.0" - checksum: f7e8091288d88b397b715281560d86ba4998246c300cb0d51db483db0a4c68cb48b489af8da9c03262745e8aa5337ba596d82dee61ff9467c5d7c27d70b676aa - languageName: node - linkType: hard - "glob-to-regexp@npm:^0.4.1": version: 0.4.1 resolution: "glob-to-regexp@npm:0.4.1" @@ -24909,62 +18734,18 @@ __metadata: languageName: node linkType: hard -"glob@npm:7.1.6": - version: 7.1.6 - resolution: "glob@npm:7.1.6" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^3.0.4 - once: ^1.3.0 - path-is-absolute: ^1.0.0 - checksum: 2575cce9306ac534388db751f0aa3e78afedb6af8f3b529ac6b2354f66765545145dba8530abf7bff49fb399a047d3f9b6901c38ee4c9503f592960d9af67763 - languageName: node - linkType: hard - -"glob@npm:^10.0.0": - version: 10.3.10 - resolution: "glob@npm:10.3.10" +"glob@npm:^10.0.0, glob@npm:^10.2.2, glob@npm:^10.2.5, glob@npm:^10.3.10, glob@npm:^10.3.7": + version: 10.3.12 + resolution: "glob@npm:10.3.12" dependencies: foreground-child: ^3.1.0 - jackspeak: ^2.3.5 + jackspeak: ^2.3.6 minimatch: ^9.0.1 - minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 - path-scurry: ^1.10.1 + minipass: ^7.0.4 + path-scurry: ^1.10.2 bin: glob: dist/esm/bin.mjs - checksum: 13d8a1feb7eac7945f8c8480e11cd4a44b24d26503d99a8d8ac8d5aefbf3e9802a2b6087318a829fad04cb4e829f25c5f4f1110c68966c498720dd261c7e344d - languageName: node - linkType: hard - -"glob@npm:^10.2.2": - version: 10.3.3 - resolution: "glob@npm:10.3.3" - dependencies: - foreground-child: ^3.1.0 - jackspeak: ^2.0.3 - minimatch: ^9.0.1 - minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 - path-scurry: ^1.10.1 - bin: - glob: dist/cjs/src/bin.js - checksum: 50effa4208762e508def5688e4d88242db80b5913f65e9c5d5aefb707c59e66a27e845fbf18127157189f6ed0f055e2c94d7112c97a065b9cbfe002e1b26d330 - languageName: node - linkType: hard - -"glob@npm:^10.2.5": - version: 10.3.1 - resolution: "glob@npm:10.3.1" - dependencies: - foreground-child: ^3.1.0 - jackspeak: ^2.0.3 - minimatch: ^9.0.1 - minipass: ^5.0.0 || ^6.0.2 - path-scurry: ^1.10.0 - bin: - glob: dist/cjs/src/bin.js - checksum: b39d24c093ce2ffa992dc5b412dbc871af0ccd38a6b2356f67dc906857f0c4c811039a4a4665d19443e1bb484ce2d97855cc7fcfb9a7d0b7e0dadfef4dad5b82 + checksum: f60cefdc1cf3f958b2bb5823e1b233727f04916d489dc4641d76914f016e6704421e06a83cbb68b0cb1cb9382298b7a88075b844ad2127fc9727ea22b18b0711 languageName: node linkType: hard @@ -25026,20 +18807,21 @@ __metadata: linkType: hard "globals@npm:^13.19.0, globals@npm:^13.6.0, globals@npm:^13.9.0": - version: 13.20.0 - resolution: "globals@npm:13.20.0" + version: 13.24.0 + resolution: "globals@npm:13.24.0" dependencies: type-fest: ^0.20.2 - checksum: 9a028f136f1e7a3574689f430f7d57faa0d699c4c7e92ade00b02882a892be31c314d50dff07b48e607283013117bb8a997406d03a1f7ab4a33a005eb16efd6c + checksum: d3c11aeea898eb83d5ec7a99508600fbe8f83d2cf00cbb77f873dbf2bcb39428eff1b538e4915c993d8a3b3473fa71eeebfe22c9bb3a3003d1e26b1f2c8a42cd languageName: node linkType: hard -"globalthis@npm:^1.0.0, globalthis@npm:^1.0.3": - version: 1.0.3 - resolution: "globalthis@npm:1.0.3" +"globalthis@npm:^1.0.3": + version: 1.0.4 + resolution: "globalthis@npm:1.0.4" dependencies: - define-properties: ^1.1.3 - checksum: 0db6e9af102a5254630351557ac15e6909bc7459d3e3f6b001e59fe784c96d31108818f032d9095739355a88467459e6488ff16584ee6250cd8c27dec05af4b0 + define-properties: ^1.2.1 + gopd: ^1.0.1 + checksum: 9d156f313af79d80b1566b93e19285f481c591ad6d0d319b4be5e03750d004dde40a39a0f26f7e635f9007a3600802f53ecd85a759b86f109e80a5f705e01846 languageName: node linkType: hard @@ -25064,22 +18846,6 @@ __metadata: languageName: node linkType: hard -"globby@npm:^9.2.0": - version: 9.2.0 - resolution: "globby@npm:9.2.0" - dependencies: - "@types/glob": ^7.1.1 - array-union: ^1.0.2 - dir-glob: ^2.2.2 - fast-glob: ^2.2.6 - glob: ^7.1.3 - ignore: ^4.0.3 - pify: ^4.0.1 - slash: ^2.0.0 - checksum: 2bd47ec43797b81000f3619feff96803b22591961788c06d746f6c8ba2deb14676b591ee625eb74b197c0047b2236e4a7a2ad662417661231b317c1de67aee94 - languageName: node - linkType: hard - "globrex@npm:^0.1.2": version: 0.1.2 resolution: "globrex@npm:0.1.2" @@ -25115,7 +18881,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.5, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.5, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 @@ -25136,17 +18902,10 @@ __metadata: languageName: node linkType: hard -"graphql@npm:^15.5.1": - version: 15.8.0 - resolution: "graphql@npm:15.8.0" - checksum: 30cc09b77170a9d1ed68e4c017ec8c5265f69501c96e4f34f8f6613f39a886c96dd9853eac925f212566ed651736334c8fe24ceae6c44e8d7625c95c3009a801 - languageName: node - linkType: hard - "graphql@npm:^16.6.0": - version: 16.6.0 - resolution: "graphql@npm:16.6.0" - checksum: 3a2c15ff58b69d017618d2b224fa6f3c4a7937e1f711c3a5e0948db536b4931e6e649560b53de7cc26735e027ceea6e2d0a6bb7c29fc4639b290313e3aa71618 + version: 16.8.1 + resolution: "graphql@npm:16.8.1" + checksum: 129c318156b466f440914de80dbf7bc67d17f776f2a088a40cb0da611d19a97c224b1c6d2b13cbcbc6e5776e45ed7468b8432f9c3536724e079b44f1a3d57a8a languageName: node linkType: hard @@ -25201,7 +18960,7 @@ __metadata: languageName: node linkType: hard -"handlebars@npm:4.7.7, handlebars@npm:^4.7.6, handlebars@npm:^4.7.7": +"handlebars@npm:4.7.7": version: 4.7.7 resolution: "handlebars@npm:4.7.7" dependencies: @@ -25219,6 +18978,24 @@ __metadata: languageName: node linkType: hard +"handlebars@npm:^4.7.6, handlebars@npm:^4.7.7": + version: 4.7.8 + resolution: "handlebars@npm:4.7.8" + dependencies: + minimist: ^1.2.5 + neo-async: ^2.6.2 + source-map: ^0.6.1 + uglify-js: ^3.1.4 + wordwrap: ^1.0.0 + dependenciesMeta: + uglify-js: + optional: true + bin: + handlebars: bin/handlebars + checksum: 7aff423ea38a14bb379316f3857fe0df3c5d66119270944247f155ba1f08e07a92b340c58edaa00cfe985c21508870ee5183e0634dcb53dd405f35c93ef7f10d + languageName: node + linkType: hard + "har-schema@npm:^2.0.0": version: 2.0.0 resolution: "har-schema@npm:2.0.0" @@ -25273,25 +19050,7 @@ __metadata: languageName: node linkType: hard -"has-glob@npm:^1.0.0": - version: 1.0.0 - resolution: "has-glob@npm:1.0.0" - dependencies: - is-glob: ^3.0.0 - checksum: 2546d20b7a667304d8b2e490c2d5a4e20e799a43eb6d97c0d47c0c737bbde082a73731001c791d445b904b3f408d584477df7d2d301183e13c4b3f0a3c81787b - languageName: node - linkType: hard - -"has-property-descriptors@npm:^1.0.0": - version: 1.0.0 - resolution: "has-property-descriptors@npm:1.0.0" - dependencies: - get-intrinsic: ^1.1.1 - checksum: d4ca882b6960d6257bd28baa3ddfa21f068d260411004a093b30ca357c740e11e985771c85216a6d1eef4161e862657f48c4758ec8ab515223b3895200ad164b - languageName: node - linkType: hard - -"has-property-descriptors@npm:^1.0.2": +"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.2": version: 1.0.2 resolution: "has-property-descriptors@npm:1.0.2" dependencies: @@ -25300,10 +19059,10 @@ __metadata: languageName: node linkType: hard -"has-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "has-proto@npm:1.0.1" - checksum: c8a8fe411f810b23a564bd5546a8f3f0fff6f1b692740eb7a2fdc9df716ef870040806891e2f23ff4653f1083e3895bf12088703dd1a0eac3d9202d3a4768cd0 +"has-proto@npm:^1.0.1, has-proto@npm:^1.0.3": + version: 1.0.3 + resolution: "has-proto@npm:1.0.3" + checksum: 35a6989f81e9f8022c2f4027f8b48a552de714938765d019dbea6bb547bd49ce5010a3c7c32ec6ddac6e48fc546166a3583b128f5a7add8b058a6d8b4afec205 languageName: node linkType: hard @@ -25314,19 +19073,12 @@ __metadata: languageName: node linkType: hard -"has-tostringtag@npm:^1.0.0": - version: 1.0.0 - resolution: "has-tostringtag@npm:1.0.0" +"has-tostringtag@npm:^1.0.0, has-tostringtag@npm:^1.0.2": + version: 1.0.2 + resolution: "has-tostringtag@npm:1.0.2" dependencies: - has-symbols: ^1.0.2 - checksum: 1cdba76b7d13f65198a92b8ca1560ba40edfa09e85d182bf436d928f3588a9ebd260451d569f0ed1b849c4bf54f49c862aa0d0a77f9552b1855bb6deb526c011 - languageName: node - linkType: hard - -"has-unicode@npm:^2.0.1": - version: 2.0.1 - resolution: "has-unicode@npm:2.0.1" - checksum: ebdb2f4895c26bb08a8a100b62d362e49b2190bcfd84b76bc4be1a3bd4d254ec52d0dd9f2fbcc093fc5eb878b20c52146f9dfd33e2686ed28982187be593b47c + has-symbols: ^1.0.3 + checksum: a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c languageName: node linkType: hard @@ -25369,138 +19121,12 @@ __metadata: languageName: node linkType: hard -"has@npm:^1.0.3": - version: 1.0.3 - resolution: "has@npm:1.0.3" - dependencies: - function-bind: ^1.1.1 - checksum: e1da0d2bd109f116b632f27782cf23182b42f14972ca9540e4c5aa7e52647407a0a4a76937334fddcb56befe94a3494825ec22b19b51f5e5507c3153fd1a5e1b - languageName: node - linkType: hard - -"hash-base@npm:^3.0.0": - version: 3.1.0 - resolution: "hash-base@npm:3.1.0" - dependencies: - inherits: ^2.0.4 - readable-stream: ^3.6.0 - safe-buffer: ^5.2.0 - checksum: 663eabcf4173326fbb65a1918a509045590a26cc7e0964b754eef248d281305c6ec9f6b31cb508d02ffca383ab50028180ce5aefe013e942b44a903ac8dc80d0 - languageName: node - linkType: hard - -"hash.js@npm:^1.0.0, hash.js@npm:^1.0.3": - version: 1.1.7 - resolution: "hash.js@npm:1.1.7" - dependencies: - inherits: ^2.0.3 - minimalistic-assert: ^1.0.1 - checksum: 41ada59494eac5332cfc1ce6b7ebdd7b88a3864a6d6b08a3ea8ef261332ed60f37f10877e0c825aaa4bddebf164fbffa618286aeeec5296675e2671cbfa746c4 - languageName: node - linkType: hard - -"hasown@npm:^2.0.0": - version: 2.0.0 - resolution: "hasown@npm:2.0.0" +"hasown@npm:^2.0.0, hasown@npm:^2.0.1, hasown@npm:^2.0.2": + version: 2.0.2 + resolution: "hasown@npm:2.0.2" dependencies: function-bind: ^1.1.2 - checksum: 5d415b114f410661208c95e7ab4879f1cc2765b8daceff4dc8718317d1cb7b9ffa7c5d1eafd9a4389c9aab7445d6ea88e05f3096cb1e529618b55304956b87fc - languageName: node - linkType: hard - -"hast-to-hyperscript@npm:^9.0.0": - version: 9.0.1 - resolution: "hast-to-hyperscript@npm:9.0.1" - dependencies: - "@types/unist": ^2.0.3 - comma-separated-tokens: ^1.0.0 - property-information: ^5.3.0 - space-separated-tokens: ^1.0.0 - style-to-object: ^0.3.0 - unist-util-is: ^4.0.0 - web-namespaces: ^1.0.0 - checksum: 630f0db8e1c78d8d6e4f8bd19dec4b6ff6c3048ba0b07b8e34bb812dfbbdc96f4c16abca16c3bfc64e7757921f42790a7bd4a693d6ce99375f99dead65a19a12 - languageName: node - linkType: hard - -"hast-util-from-parse5@npm:^6.0.0": - version: 6.0.1 - resolution: "hast-util-from-parse5@npm:6.0.1" - dependencies: - "@types/parse5": ^5.0.0 - hastscript: ^6.0.0 - property-information: ^5.0.0 - vfile: ^4.0.0 - vfile-location: ^3.2.0 - web-namespaces: ^1.0.0 - checksum: c5e7ee40347c3850ece717e37c3e277ca233848ebca341f68c2afbefdb912da415a2fd06940edc3ea4882ad520e1cac7bf3fcf66c31ae97e1bcf953fcb6a7db5 - languageName: node - linkType: hard - -"hast-util-parse-selector@npm:^2.0.0": - version: 2.2.5 - resolution: "hast-util-parse-selector@npm:2.2.5" - checksum: 29b7ee77960ded6a99d30c287d922243071cc07b39f2006f203bd08ee54eb8f66bdaa86ef6527477c766e2382d520b60ee4e4087f189888c35d8bcc020173648 - languageName: node - linkType: hard - -"hast-util-raw@npm:6.0.1": - version: 6.0.1 - resolution: "hast-util-raw@npm:6.0.1" - dependencies: - "@types/hast": ^2.0.0 - hast-util-from-parse5: ^6.0.0 - hast-util-to-parse5: ^6.0.0 - html-void-elements: ^1.0.0 - parse5: ^6.0.0 - unist-util-position: ^3.0.0 - vfile: ^4.0.0 - web-namespaces: ^1.0.0 - xtend: ^4.0.0 - zwitch: ^1.0.0 - checksum: 0ed0a2731251a4853710eda38e0bb79ee1ad8ccea69b391c16eb20895895818bced1c2c9eaf8853280f0aa6dc71d22b9eb6c9aab770dd1a225bb44d522eef1ef - languageName: node - linkType: hard - -"hast-util-to-parse5@npm:^6.0.0": - version: 6.0.0 - resolution: "hast-util-to-parse5@npm:6.0.0" - dependencies: - hast-to-hyperscript: ^9.0.0 - property-information: ^5.0.0 - web-namespaces: ^1.0.0 - xtend: ^4.0.0 - zwitch: ^1.0.0 - checksum: 49d6c2389fd3170741cdb0483666bccd7e9e436fe386bcbd3931b019e4c006b5bb48022e07967e1021336e744e901082d6479cfa4bc2082efa3b1e5bdab2a36f - languageName: node - linkType: hard - -"hastscript@npm:^6.0.0": - version: 6.0.0 - resolution: "hastscript@npm:6.0.0" - dependencies: - "@types/hast": ^2.0.0 - comma-separated-tokens: ^1.0.0 - hast-util-parse-selector: ^2.0.0 - property-information: ^5.0.0 - space-separated-tokens: ^1.0.0 - checksum: f76d9cf373cb075c8523c8ad52709f09f7e02b7c9d3152b8d35c65c265b9f1878bed6023f215a7d16523921036d40a7da292cb6f4399af9b5eccac2a5a5eb330 - languageName: node - linkType: hard - -"he@npm:^1.2.0": - version: 1.2.0 - resolution: "he@npm:1.2.0" - bin: - he: bin/he - checksum: a27d478befe3c8192f006cdd0639a66798979dfa6e2125c6ac582a19a5ebfec62ad83e8382e6036170d873f46e4536a7e795bf8b95bf7c247f4cc0825ccc8c17 - languageName: node - linkType: hard - -"headers-utils@npm:^3.0.2": - version: 3.0.2 - resolution: "headers-utils@npm:3.0.2" - checksum: 25020779f9ca05bdfa2b8157b3052aa4373ed8f15992c013232de56dc179ffd1c56bdfa851d185bdf708f254fee255b34054fddba8bbfe14544aec975318cdd9 + checksum: 3769d434703b8ac66b209a4cca0737519925bbdb61dd887f93a16372b14694c63ff4e797686d87c90f08168e81082248b9b028bad60d4da9e0d1148766f56eb9 languageName: node linkType: hard @@ -25518,17 +19144,6 @@ __metadata: languageName: node linkType: hard -"hmac-drbg@npm:^1.0.1": - version: 1.0.1 - resolution: "hmac-drbg@npm:1.0.1" - dependencies: - hash.js: ^1.0.3 - minimalistic-assert: ^1.0.0 - minimalistic-crypto-utils: ^1.0.1 - checksum: f3d9ba31b40257a573f162176ac5930109816036c59a09f901eb2ffd7e5e705c6832bedfff507957125f2086a0ab8f853c0df225642a88bf1fcaea945f20600d - languageName: node - linkType: hard - "homedir-polyfill@npm:^1.0.1": version: 1.0.3 resolution: "homedir-polyfill@npm:1.0.3" @@ -25581,13 +19196,6 @@ __metadata: languageName: node linkType: hard -"html-entities@npm:^2.1.0": - version: 2.4.0 - resolution: "html-entities@npm:2.4.0" - checksum: 42bbd5d91f451625d7e35aaed41c8cd110054c0d0970764cb58df467b3f27f20199e8cf7b4aebc8d4eeaf17a27c0d1fb165f2852db85de200995d0f009c9011d - languageName: node - linkType: hard - "html-escaper@npm:^2.0.0": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" @@ -25595,23 +19203,6 @@ __metadata: languageName: node linkType: hard -"html-minifier-terser@npm:^5.0.1": - version: 5.1.1 - resolution: "html-minifier-terser@npm:5.1.1" - dependencies: - camel-case: ^4.1.1 - clean-css: ^4.2.3 - commander: ^4.1.1 - he: ^1.2.0 - param-case: ^3.0.3 - relateurl: ^0.2.7 - terser: ^4.6.3 - bin: - html-minifier-terser: cli.js - checksum: b38e678aa8065358c31ab58ada6efa1563e6e8d74c198ed1a1240b9d4ffcec077e2c5ce42b87f4fdefd7dd9041f82beb5cbd804c4f4179afc6f0f6e89b63f5f6 - languageName: node - linkType: hard - "html-parse-stringify@npm:^3.0.1": version: 3.0.1 resolution: "html-parse-stringify@npm:3.0.1" @@ -25628,44 +19219,6 @@ __metadata: languageName: node linkType: hard -"html-void-elements@npm:^1.0.0": - version: 1.0.5 - resolution: "html-void-elements@npm:1.0.5" - checksum: 97b6c108d7d6b31a45deddf95a65eb074bd0f358b55a61f3a031e055812eec368076ca23f0181674c5212166168988f35312756a3b376490e31e73d9a51f5549 - languageName: node - linkType: hard - -"html-webpack-plugin@npm:^4.0.0": - version: 4.5.2 - resolution: "html-webpack-plugin@npm:4.5.2" - dependencies: - "@types/html-minifier-terser": ^5.0.0 - "@types/tapable": ^1.0.5 - "@types/webpack": ^4.41.8 - html-minifier-terser: ^5.0.1 - loader-utils: ^1.2.3 - lodash: ^4.17.20 - pretty-error: ^2.1.1 - tapable: ^1.1.3 - util.promisify: 1.0.0 - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: 405f01eb8d5554bd0330c462003e215a793518809e29df0121d20ba2a9717078df33089fda0464c62453ce3af12b6a1fee51dd24761a56f610f509e1e5d503e9 - languageName: node - linkType: hard - -"htmlparser2@npm:^6.1.0": - version: 6.1.0 - resolution: "htmlparser2@npm:6.1.0" - dependencies: - domelementtype: ^2.0.1 - domhandler: ^4.0.0 - domutils: ^2.5.2 - entities: ^2.0.0 - checksum: 3058499c95634f04dc66be8c2e0927cd86799413b2d6989d8ae542ca4dbf5fa948695d02c27d573acf44843af977aec6d9a7bdd0f6faa6b2d99e2a729b2a31b6 - languageName: node - linkType: hard - "http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" @@ -25747,6 +19300,16 @@ __metadata: languageName: node linkType: hard +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: ^7.1.0 + debug: ^4.3.4 + checksum: 4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 + languageName: node + linkType: hard + "http-signature@npm:~1.2.0": version: 1.2.0 resolution: "http-signature@npm:1.2.0" @@ -25782,13 +19345,6 @@ __metadata: languageName: node linkType: hard -"https-browserify@npm:^1.0.0": - version: 1.0.0 - resolution: "https-browserify@npm:1.0.0" - checksum: e17b6943bc24ea9b9a7da5714645d808670af75a425f29baffc3284962626efdc1eb3aa9bbffaa6e64028a6ad98af5b09fabcb454a8f918fb686abfdc9e9b8ae - languageName: node - linkType: hard - "https-proxy-agent@npm:^4.0.0": version: 4.0.0 resolution: "https-proxy-agent@npm:4.0.0" @@ -25809,13 +19365,13 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.2": - version: 7.0.2 - resolution: "https-proxy-agent@npm:7.0.2" +"https-proxy-agent@npm:^7.0.1": + version: 7.0.4 + resolution: "https-proxy-agent@npm:7.0.4" dependencies: agent-base: ^7.0.2 debug: 4 - checksum: 7735eb90073db087e7e79312e3d97c8c04baf7ea7ca7b013382b6a45abbaa61b281041a98f4e13c8c80d88f843785bcc84ba189165b4b4087b1e3496ba656d77 + checksum: bc4f7c38da32a5fc622450b6cb49a24ff596f9bd48dcedb52d2da3fa1c1a80e100fb506bd59b326c012f21c863c69b275c23de1a01d0b84db396822fdf25e52b languageName: node linkType: hard @@ -25847,12 +19403,10 @@ __metadata: languageName: node linkType: hard -"humanize-ms@npm:^1.2.1": - version: 1.2.1 - resolution: "humanize-ms@npm:1.2.1" - dependencies: - ms: ^2.0.0 - checksum: f34a2c20161d02303c2807badec2f3b49cbfbbb409abd4f95a07377ae01cfe6b59e3d15ac609cffcd8f2521f0eb37b7e1091acf65da99aa2a4f1ad63c21e7e7a +"human-signals@npm:^5.0.0": + version: 5.0.0 + resolution: "human-signals@npm:5.0.0" + checksum: 5a9359073fe17a8b58e5a085e9a39a950366d9f00217c4ff5878bd312e09d80f460536ea6a3f260b5943a01fe55c158d1cea3fc7bee3d0520aeef04f6d915c82 languageName: node linkType: hard @@ -25924,15 +19478,6 @@ __metadata: languageName: node linkType: hard -"icss-utils@npm:^4.0.0, icss-utils@npm:^4.1.1": - version: 4.1.1 - resolution: "icss-utils@npm:4.1.1" - dependencies: - postcss: ^7.0.14 - checksum: 22803c243bb097c2290b4e7c20ed14746f3e00e04856f953b751c7e6bb8c81620764bcf98d200a92d167af0884d19143c089d02e2bc609abcdeb86f465328797 - languageName: node - linkType: hard - "icss-utils@npm:^5.0.0, icss-utils@npm:^5.1.0": version: 5.1.0 resolution: "icss-utils@npm:5.1.0" @@ -25942,20 +19487,13 @@ __metadata: languageName: node linkType: hard -"ieee754@npm:^1.1.13, ieee754@npm:^1.1.4, ieee754@npm:^1.2.1": +"ieee754@npm:^1.1.13, ieee754@npm:^1.2.1": version: 1.2.1 resolution: "ieee754@npm:1.2.1" checksum: b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb languageName: node linkType: hard -"iferr@npm:^0.1.5": - version: 0.1.5 - resolution: "iferr@npm:0.1.5" - checksum: e0669b1757d0501b43a158321945d1cc1fe56f28a972df2f88a5818f05c8853c7669ba5d6cfbbf9a1a312850699de6e528626df108d559005df7e15d16ee334c - languageName: node - linkType: hard - "ignore-by-default@npm:^1.0.1": version: 1.0.1 resolution: "ignore-by-default@npm:1.0.1" @@ -25963,7 +19501,7 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^4.0.3, ignore@npm:^4.0.6": +"ignore@npm:^4.0.6": version: 4.0.6 resolution: "ignore@npm:4.0.6" checksum: 836ee7dc7fd9436096e2dba429359dbb9fa0e33d309e2b2d81692f375f6ca82024fc00567f798613d50c6b989e9cd2ad2b065acf116325cde177f02c86b7d4e0 @@ -25971,9 +19509,9 @@ __metadata: linkType: hard "ignore@npm:^5.2.0, ignore@npm:^5.2.4": - version: 5.2.4 - resolution: "ignore@npm:5.2.4" - checksum: 7c7cd90edd9fea6e037f9b9da4b01bf0a86b198ce78345f9bbd983929d68ff14830be31111edc5d70c264921f4962404d75b7262b4d9cc3bc12381eccbd03096 + version: 5.3.1 + resolution: "ignore@npm:5.3.1" + checksum: 703f7f45ffb2a27fb2c5a8db0c32e7dee66b33a225d28e8db4e1be6474795f606686a6e3bcc50e1aa12f2042db4c9d4a7d60af3250511de74620fbed052ea4cd languageName: node linkType: hard @@ -26000,7 +19538,7 @@ __metadata: languageName: node linkType: hard -"import-fresh@npm:^3.0.0, import-fresh@npm:^3.1.0, import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.0.0, import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: @@ -26019,6 +19557,13 @@ __metadata: languageName: node linkType: hard +"import-lazy@npm:~4.0.0": + version: 4.0.0 + resolution: "import-lazy@npm:4.0.0" + checksum: a3520313e2c31f25c0b06aa66d167f329832b68a4f957d7c9daf6e0fa41822b6e84948191648b9b9d8ca82f94740cdf15eecf2401a5b42cd1c33fd84f2225cca + languageName: node + linkType: hard + "import-local@npm:^3.0.2": version: 3.1.0 resolution: "import-local@npm:3.1.0" @@ -26038,15 +19583,6 @@ __metadata: languageName: node linkType: hard -"indent-string@npm:^2.1.0": - version: 2.1.0 - resolution: "indent-string@npm:2.1.0" - dependencies: - repeating: ^2.0.0 - checksum: d38e04bbd9b0e1843164d06e9ac1e106ead5a6f7b5714c94ecebc2555b2d3af075b3ddc4d6f92ac87d5319c0935df60d571d3f45f17a6f0ec707be65f26ae924 - languageName: node - linkType: hard - "indent-string@npm:^4.0.0": version: 4.0.0 resolution: "indent-string@npm:4.0.0" @@ -26054,13 +19590,6 @@ __metadata: languageName: node linkType: hard -"infer-owner@npm:^1.0.3, infer-owner@npm:^1.0.4": - version: 1.0.4 - resolution: "infer-owner@npm:1.0.4" - checksum: a7b241e3149c26e37474e3435779487f42f36883711f198c45794703c7556bc38af224088bd4d1a221a45b8208ae2c2bcf86200383621434d0c099304481c5b9 - languageName: node - linkType: hard - "inflight@npm:^1.0.4": version: 1.0.6 resolution: "inflight@npm:1.0.6" @@ -26071,20 +19600,13 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.0, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.1, inherits@npm:~2.0.3": +"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 languageName: node linkType: hard -"inherits@npm:2.0.1": - version: 2.0.1 - resolution: "inherits@npm:2.0.1" - checksum: bfc7b37c21a2cddb272adc65b053b1716612d408bb2c9a4e5c32679dc2b08032aadd67880c405be3dff060a62e45b353fc3d9fa79a3067ad7a3deb6a283cc5c6 - languageName: node - linkType: hard - "inherits@npm:2.0.3": version: 2.0.3 resolution: "inherits@npm:2.0.3" @@ -26092,16 +19614,9 @@ __metadata: languageName: node linkType: hard -"inline-style-parser@npm:0.1.1": - version: 0.1.1 - resolution: "inline-style-parser@npm:0.1.1" - checksum: 08832a533f51a1e17619f2eabf2f5ec5e956d6dcba1896351285c65df022c9420de61d73256e1dca8015a52abf96cc84ddc3b73b898b22de6589d3962b5e501b - languageName: node - linkType: hard - -"inquirer@npm:^8.0.0, inquirer@npm:^8.1.1": - version: 8.2.5 - resolution: "inquirer@npm:8.2.5" +"inquirer@npm:^8.0.0": + version: 8.2.6 + resolution: "inquirer@npm:8.2.6" dependencies: ansi-escapes: ^4.2.1 chalk: ^4.1.1 @@ -26117,8 +19632,8 @@ __metadata: string-width: ^4.1.0 strip-ansi: ^6.0.0 through: ^2.3.6 - wrap-ansi: ^7.0.0 - checksum: e3e64e10f5daeeb8f770f1310acceb4aab593c10d693e7676ecd4a5b023d5b865b484fec7ead516e5e394db70eff687ef85459f75890f11a99ceadc0f4adce18 + wrap-ansi: ^6.0.1 + checksum: eb5724de1778265323f3a68c80acfa899378cb43c24cdcb58661386500e5696b6b0b6c700e046b7aa767fe7b4823c6f04e6ddc268173e3f84116112529016296 languageName: node linkType: hard @@ -26223,73 +19738,14 @@ __metadata: languageName: unknown linkType: soft -"integration-tests-plugins@workspace:integration-tests/plugins": - version: 0.0.0-use.local - resolution: "integration-tests-plugins@workspace:integration-tests/plugins" +"internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.7": + version: 1.0.7 + resolution: "internal-slot@npm:1.0.7" dependencies: - "@babel/cli": ^7.12.10 - "@babel/core": ^7.12.10 - "@babel/node": ^7.12.10 - "@medusajs/api-key": "workspace:^" - "@medusajs/auth": "workspace:*" - "@medusajs/cache-inmemory": "workspace:*" - "@medusajs/currency": "workspace:^" - "@medusajs/customer": "workspace:^" - "@medusajs/event-bus-local": "workspace:*" - "@medusajs/inventory": latest - "@medusajs/inventory-next": "workspace:^" - "@medusajs/medusa": "workspace:*" - "@medusajs/modules-sdk": "workspace:^" - "@medusajs/pricing": "workspace:^" - "@medusajs/product": "workspace:^" - "@medusajs/promotion": "workspace:^" - "@medusajs/region": "workspace:^" - "@medusajs/stock-location": latest - "@medusajs/store": "workspace:^" - "@medusajs/tax": "workspace:^" - "@medusajs/types": "workspace:^" - "@medusajs/user": "workspace:^" - "@medusajs/utils": "workspace:^" - "@medusajs/workflow-engine-inmemory": "workspace:*" - "@swc/core": ^1.4.8 - "@swc/jest": ^0.2.36 - babel-preset-medusa-package: "*" - faker: ^5.5.3 - jest: ^26.6.3 - jest-environment-node: 26.6.2 - medusa-interfaces: "workspace:*" - pg: ^8.11.0 - typeorm: ^0.3.16 - languageName: unknown - linkType: soft - -"integration-tests-repositories@workspace:integration-tests/repositories": - version: 0.0.0-use.local - resolution: "integration-tests-repositories@workspace:integration-tests/repositories" - dependencies: - "@babel/cli": ^7.12.10 - "@babel/core": ^7.12.10 - "@babel/node": ^7.12.10 - "@medusajs/cache-inmemory": "workspace:*" - "@medusajs/event-bus-local": "workspace:*" - "@medusajs/medusa": "workspace:*" - babel-preset-medusa-package: "*" - jest: ^26.6.3 - jest-environment-node: 26.6.2 - medusa-interfaces: "workspace:*" - pg: ^8.11.0 - typeorm: ^0.3.16 - languageName: unknown - linkType: soft - -"internal-slot@npm:^1.0.3, internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.5": - version: 1.0.5 - resolution: "internal-slot@npm:1.0.5" - dependencies: - get-intrinsic: ^1.2.0 - has: ^1.0.3 + es-errors: ^1.3.0 + hasown: ^2.0.0 side-channel: ^1.0.4 - checksum: 66d8a66b4b5310c042e8ad00ce895dc55cb25165a3a7da0d7862ca18d69d3b1ba86511b4bf3baf4273d744d3f6e9154574af45189ef11135a444945309e39e4a + checksum: f8b294a4e6ea3855fc59551bbf35f2b832cf01fd5e6e2a97f5c201a071cc09b49048f856e484b67a6c721da5e55736c5b6ddafaf19e2dbeb4a3ff1821680de6c languageName: node linkType: hard @@ -26301,14 +19757,14 @@ __metadata: linkType: hard "intl-messageformat@npm:^10.1.0": - version: 10.5.0 - resolution: "intl-messageformat@npm:10.5.0" + version: 10.5.12 + resolution: "intl-messageformat@npm:10.5.12" dependencies: - "@formatjs/ecma402-abstract": 1.17.0 + "@formatjs/ecma402-abstract": 1.18.2 "@formatjs/fast-memoize": 2.2.0 - "@formatjs/icu-messageformat-parser": 2.6.0 + "@formatjs/icu-messageformat-parser": 2.7.6 tslib: ^2.4.0 - checksum: 884a9cdb680a46fc1a73b69062990346bf98f29736365ad018f83890a19dbe8845bda16d51c248d30d0ccf7f5037b7df7e2a6dc703261e3de005ac0031cebac4 + checksum: f95734e98a05ef7f51de0c27904d3a994528e3a174963bd1b3a6db9416b5fd84bbd8f7d26d84fc547d51af69ccf46dd3f73a3f4f20a2ccef5c9cd90e946ad82c languageName: node linkType: hard @@ -26337,9 +19793,9 @@ __metadata: languageName: node linkType: hard -"ioredis@npm:^5.2.5, ioredis@npm:^5.3.1, ioredis@npm:^5.3.2": - version: 5.3.2 - resolution: "ioredis@npm:5.3.2" +"ioredis@npm:^5.2.5, ioredis@npm:^5.3.1, ioredis@npm:^5.3.2, ioredis@npm:^5.4.1": + version: 5.4.1 + resolution: "ioredis@npm:5.4.1" dependencies: "@ioredis/commands": ^1.1.1 cluster-key-slot: ^1.1.0 @@ -26350,7 +19806,17 @@ __metadata: redis-errors: ^1.2.0 redis-parser: ^3.0.0 standard-as-callback: ^2.1.0 - checksum: 0dd2b5b8004e891f5b62edf18ac223194f1f5204698ec827c903e789ea05b0b36f73395491749ec63c66470485bdfb228ccdf1714fbf631a0f78f33211f2c883 + checksum: 5d28b7c89a3cab5b76d75923d7d4ce79172b3a1ca9be690133f6e8e393a7a4b4ffd55513e618bbb5504fed80d9e1395c9d9531a7c5c5c84aa4c4e765cca75456 + languageName: node + linkType: hard + +"ip-address@npm:^9.0.5": + version: 9.0.5 + resolution: "ip-address@npm:9.0.5" + dependencies: + jsbn: 1.1.0 + sprintf-js: ^1.1.3 + checksum: 331cd07fafcb3b24100613e4b53e1a2b4feab11e671e655d46dc09ee233da5011284d09ca40c4ecbdfe1d0004f462958675c224a804259f2f78d2465a87824bc languageName: node linkType: hard @@ -26361,10 +19827,10 @@ __metadata: languageName: node linkType: hard -"ip@npm:^2.0.0": - version: 2.0.0 - resolution: "ip@npm:2.0.0" - checksum: 8d186cc5585f57372847ae29b6eba258c68862055e18a75cc4933327232cb5c107f89800ce29715d542eef2c254fbb68b382e780a7414f9ee7caf60b7a473958 +"ip@npm:^2.0.1": + version: 2.0.1 + resolution: "ip@npm:2.0.1" + checksum: cab8eb3e88d0abe23e4724829621ec4c4c5cb41a7f936a2e626c947128c1be16ed543448d42af7cca95379f9892bfcacc1ccd8d09bc7e8bea0e86d492ce33616 languageName: node linkType: hard @@ -26392,38 +19858,12 @@ __metadata: languageName: node linkType: hard -"is-accessor-descriptor@npm:^0.1.6": - version: 0.1.6 - resolution: "is-accessor-descriptor@npm:0.1.6" +"is-accessor-descriptor@npm:^1.0.1": + version: 1.0.1 + resolution: "is-accessor-descriptor@npm:1.0.1" dependencies: - kind-of: ^3.0.2 - checksum: f2c314b314ec6e8a6e559351bff3c7ee9aed7a5e9c6f61dd8cb9e1382c8bfe33dca3f0e0af13daf9ded9e6e66390ff23b4acfb615d7a249009a51506a7b0f151 - languageName: node - linkType: hard - -"is-accessor-descriptor@npm:^1.0.0": - version: 1.0.0 - resolution: "is-accessor-descriptor@npm:1.0.0" - dependencies: - kind-of: ^6.0.0 - checksum: d68edafd8ef133e9003837f3c80f4e5b82b12ab5456c772d1796857671ae83e3a426ed225a28a7e35bceabbce68c1f1ffdabf47e6d53f5a4d6c4558776ad3c20 - languageName: node - linkType: hard - -"is-alphabetical@npm:1.0.4, is-alphabetical@npm:^1.0.0": - version: 1.0.4 - resolution: "is-alphabetical@npm:1.0.4" - checksum: 1505b1de5a1fd74022c05fb21b0e683a8f5229366bac8dc4d34cf6935bcfd104d1125a5e6b083fb778847629f76e5bdac538de5367bdf2b927a1356164e23985 - languageName: node - linkType: hard - -"is-alphanumerical@npm:^1.0.0": - version: 1.0.4 - resolution: "is-alphanumerical@npm:1.0.4" - dependencies: - is-alphabetical: ^1.0.0 - is-decimal: ^1.0.0 - checksum: d623abae7130a7015c6bf33d99151d4e7005572fd170b86568ff4de5ae86ac7096608b87dd4a1d4dbbd497e392b6396930ba76c9297a69455909cebb68005905 + hasown: ^2.0.0 + checksum: d034034074c5ffeb6c868e091083182279db1a956f49f8d1494cecaa0f8b99d706556ded2a9b20d9aa290549106eef8204d67d8572902e06dcb1add6db6b524d languageName: node linkType: hard @@ -26437,14 +19877,13 @@ __metadata: languageName: node linkType: hard -"is-array-buffer@npm:^3.0.1, is-array-buffer@npm:^3.0.2": - version: 3.0.2 - resolution: "is-array-buffer@npm:3.0.2" +"is-array-buffer@npm:^3.0.2, is-array-buffer@npm:^3.0.4": + version: 3.0.4 + resolution: "is-array-buffer@npm:3.0.4" dependencies: call-bind: ^1.0.2 - get-intrinsic: ^1.2.0 - is-typed-array: ^1.1.10 - checksum: 40ed13a5f5746ac3ae2f2e463687d9b5a3f5fd0086f970fb4898f0253c2a5ec2e3caea2d664dd8f54761b1c1948609702416921a22faebe160c7640a9217c80e + get-intrinsic: ^1.2.1 + checksum: 42a49d006cc6130bc5424eae113e948c146f31f9d24460fc0958f855d9d810e6fd2e4519bf19aab75179af9c298ea6092459d8cafdec523cd19e529b26eab860 languageName: node linkType: hard @@ -26462,6 +19901,15 @@ __metadata: languageName: node linkType: hard +"is-async-function@npm:^2.0.0": + version: 2.0.0 + resolution: "is-async-function@npm:2.0.0" + dependencies: + has-tostringtag: ^1.0.0 + checksum: 787bc931576aad525d751fc5ce211960fe91e49ac84a5c22d6ae0bc9541945fbc3f686dc590c3175722ce4f6d7b798a93f6f8ff4847fdb2199aea6f4baf5d668 + languageName: node + linkType: hard + "is-bigint@npm:^1.0.1": version: 1.0.4 resolution: "is-bigint@npm:1.0.4" @@ -26506,7 +19954,7 @@ __metadata: languageName: node linkType: hard -"is-buffer@npm:^2.0.0, is-buffer@npm:^2.0.5": +"is-buffer@npm:^2.0.5": version: 2.0.5 resolution: "is-buffer@npm:2.0.5" checksum: e603f6fced83cf94c53399cff3bda1a9f08e391b872b64a73793b0928be3e5f047f2bcece230edb7632eaea2acdbfcb56c23b33d8a20c820023b230f1485679a @@ -26540,26 +19988,6 @@ __metadata: languageName: node linkType: hard -"is-ci@npm:^3.0.1": - version: 3.0.1 - resolution: "is-ci@npm:3.0.1" - dependencies: - ci-info: ^3.2.0 - bin: - is-ci: bin.js - checksum: 0e81caa62f4520d4088a5bef6d6337d773828a88610346c4b1119fb50c842587ed8bef1e5d9a656835a599e7209405b5761ddf2339668f2d0f4e889a92fe6051 - languageName: node - linkType: hard - -"is-core-module@npm:^2.12.0, is-core-module@npm:^2.9.0": - version: 2.12.1 - resolution: "is-core-module@npm:2.12.1" - dependencies: - has: ^1.0.3 - checksum: ff1d0dfc0b7851310d289398e416eb92ae8a9ac7ea8b8b9737fa8c0725f5a78c5f3db6edd4dff38c9ed731f3aaa1f6410a320233fcb52a2c8f1cf58eebf10a4b - languageName: node - linkType: hard - "is-core-module@npm:^2.13.0": version: 2.13.1 resolution: "is-core-module@npm:2.13.1" @@ -26569,21 +19997,21 @@ __metadata: languageName: node linkType: hard -"is-data-descriptor@npm:^0.1.4": - version: 0.1.4 - resolution: "is-data-descriptor@npm:0.1.4" +"is-data-descriptor@npm:^1.0.1": + version: 1.0.1 + resolution: "is-data-descriptor@npm:1.0.1" dependencies: - kind-of: ^3.0.2 - checksum: 32fda7e966b2c1f093230d5ef2aad1bb86e43e7280da50961e38ec31dbd8a50570a2911fd45277d321074a0762adc98e8462bb62820462594128857225e90d21 + hasown: ^2.0.0 + checksum: ad3acc372e3227f87eb8cdba112c343ca2a67f1885aecf64f02f901cb0858a1fc9488ad42135ab102e9d9e71a62b3594740790bb103a9ba5da830a131a89e3e8 languageName: node linkType: hard -"is-data-descriptor@npm:^1.0.0": - version: 1.0.0 - resolution: "is-data-descriptor@npm:1.0.0" +"is-data-view@npm:^1.0.1": + version: 1.0.1 + resolution: "is-data-view@npm:1.0.1" dependencies: - kind-of: ^6.0.0 - checksum: bed31385d7d1a0dbb2ab3077faf2188acf42609192dca4e320ed7b3dc14a9d70c00658956cdaa2c0402be136c6b56e183973ad81b730fd90ab427fb6fd3608be + is-typed-array: ^1.1.13 + checksum: a3e6ec84efe303da859107aed9b970e018e2bee7ffcb48e2f8096921a493608134240e672a2072577e5f23a729846241d9634806e8a0e51d9129c56d5f65442d languageName: node linkType: hard @@ -26596,13 +20024,6 @@ __metadata: languageName: node linkType: hard -"is-decimal@npm:^1.0.0": - version: 1.0.4 - resolution: "is-decimal@npm:1.0.4" - checksum: a4ad53c4c5c4f5a12214e7053b10326711f6a71f0c63ba1314a77bd71df566b778e4ebd29f9fb6815f07a4dc50c3767fb19bd6fc9fa05e601410f1d64ffeac48 - languageName: node - linkType: hard - "is-deflate@npm:^1.0.0": version: 1.0.0 resolution: "is-deflate@npm:1.0.0" @@ -26611,24 +20032,22 @@ __metadata: linkType: hard "is-descriptor@npm:^0.1.0": - version: 0.1.6 - resolution: "is-descriptor@npm:0.1.6" + version: 0.1.7 + resolution: "is-descriptor@npm:0.1.7" dependencies: - is-accessor-descriptor: ^0.1.6 - is-data-descriptor: ^0.1.4 - kind-of: ^5.0.0 - checksum: 6b8f5617b764ef8c6be3d54830184357e6cdedd8e0eddf1b97d0658616ac170bfdbc7c1ad00e0aa9f5b767acdb9d6c63d4df936501784b34936bd0f9acf3b665 + is-accessor-descriptor: ^1.0.1 + is-data-descriptor: ^1.0.1 + checksum: f5960b9783f508aec570465288cb673d4b3cc4aae4e6de970c3afd9a8fc1351edcb85d78b2cce2ec5251893a423f73263cab3bb94cf365a8d71b5d510a116392 languageName: node linkType: hard "is-descriptor@npm:^1.0.0, is-descriptor@npm:^1.0.2": - version: 1.0.2 - resolution: "is-descriptor@npm:1.0.2" + version: 1.0.3 + resolution: "is-descriptor@npm:1.0.3" dependencies: - is-accessor-descriptor: ^1.0.0 - is-data-descriptor: ^1.0.0 - kind-of: ^6.0.2 - checksum: a05169c7a87feb88fc155e3ada469090cfabb5a548a3f794358b511cc47a0871b8b95e7345be4925a22ef3df585c3923b31943b3ad6255ce563a9d97f2e221e0 + is-accessor-descriptor: ^1.0.1 + is-data-descriptor: ^1.0.1 + checksum: b4ee667ea787d3a0be4e58536087fd0587de2b0b6672fbfe288f5b8d831ac4b79fd987f31d6c2d4e5543a42c97a87428bc5215ce292a1a47070147793878226f languageName: node linkType: hard @@ -26650,16 +20069,6 @@ __metadata: languageName: node linkType: hard -"is-dom@npm:^1.0.0": - version: 1.1.0 - resolution: "is-dom@npm:1.1.0" - dependencies: - is-object: ^1.0.1 - is-window: ^1.0.2 - checksum: 0645d388bed188e827b4440af7c2f4c454ad6e6fd4c395d46eae404ca8b64f1bb45e3f33f1a60fbc7f59ca10fb0e5351589b49b3d3bac1b3c5aeec70e2e5be07 - languageName: node - linkType: hard - "is-extendable@npm:^0.1.0, is-extendable@npm:^0.1.1": version: 0.1.1 resolution: "is-extendable@npm:0.1.1" @@ -26690,10 +20099,12 @@ __metadata: languageName: node linkType: hard -"is-finite@npm:^1.0.0": - version: 1.1.0 - resolution: "is-finite@npm:1.1.0" - checksum: ca6bc7a0321b339f098e657bd4cbf4bb2410f5a11f1b9adb1a1a9ab72288b64368e8251326cb1f74e985f2779299cec3e1f1e558b68ce7e1e2c9be17b7cfd626 +"is-finalizationregistry@npm:^1.0.2": + version: 1.0.2 + resolution: "is-finalizationregistry@npm:1.0.2" + dependencies: + call-bind: ^1.0.2 + checksum: 81caecc984d27b1a35c68741156fc651fb1fa5e3e6710d21410abc527eb226d400c0943a167922b2e920f6b3e58b0dede9aa795882b038b85f50b3a4b877db86 languageName: node linkType: hard @@ -26704,13 +20115,6 @@ __metadata: languageName: node linkType: hard -"is-function@npm:^1.0.2": - version: 1.0.2 - resolution: "is-function@npm:1.0.2" - checksum: c55289042a0e828a773f1245e2652e0c029efacc78ebe03e61787746fda74e2c41006cd908f20b53c36e45f9e75464475a4b2d68b17f4c7b9f8018bcaec42f9e - languageName: node - linkType: hard - "is-generator-fn@npm:^2.0.0": version: 2.1.0 resolution: "is-generator-fn@npm:2.1.0" @@ -26718,7 +20122,7 @@ __metadata: languageName: node linkType: hard -"is-generator-function@npm:^1.0.7": +"is-generator-function@npm:^1.0.10, is-generator-function@npm:^1.0.7": version: 1.0.10 resolution: "is-generator-function@npm:1.0.10" dependencies: @@ -26736,7 +20140,7 @@ __metadata: languageName: node linkType: hard -"is-glob@npm:^3.0.0, is-glob@npm:^3.1.0": +"is-glob@npm:^3.1.0": version: 3.1.0 resolution: "is-glob@npm:3.1.0" dependencies: @@ -26761,13 +20165,6 @@ __metadata: languageName: node linkType: hard -"is-hexadecimal@npm:^1.0.0": - version: 1.0.4 - resolution: "is-hexadecimal@npm:1.0.4" - checksum: ec4c64e5624c0f240922324bc697e166554f09d3ddc7633fc526084502626445d0a871fbd8cae52a9844e83bd0bb414193cc5a66806d7b2867907003fc70c5ea - languageName: node - linkType: hard - "is-inside-container@npm:^1.0.0": version: 1.0.0 resolution: "is-inside-container@npm:1.0.0" @@ -26809,10 +20206,10 @@ __metadata: languageName: node linkType: hard -"is-map@npm:^2.0.1, is-map@npm:^2.0.2": - version: 2.0.2 - resolution: "is-map@npm:2.0.2" - checksum: 119ff9137a37fd131a72fab3f4ab8c9d6a24b0a1ee26b4eff14dc625900d8675a97785eea5f4174265e2006ed076cc24e89f6e57ebd080a48338d914ec9168a5 +"is-map@npm:^2.0.2, is-map@npm:^2.0.3": + version: 2.0.3 + resolution: "is-map@npm:2.0.3" + checksum: 2c4d431b74e00fdda7162cd8e4b763d6f6f217edf97d4f8538b94b8702b150610e2c64961340015fe8df5b1fcee33ccd2e9b62619c4a8a3a155f8de6d6d355fc languageName: node linkType: hard @@ -26833,17 +20230,10 @@ __metadata: languageName: node linkType: hard -"is-negative-zero@npm:^2.0.2": - version: 2.0.2 - resolution: "is-negative-zero@npm:2.0.2" - checksum: eda024c158f70f2017f3415e471b818d314da5ef5be68f801b16314d4a4b6304a74cbed778acf9e2f955bb9c1c5f2935c1be0c7c99e1ad12286f45366217b6a3 - languageName: node - linkType: hard - -"is-node-process@npm:^1.0.1": - version: 1.2.0 - resolution: "is-node-process@npm:1.2.0" - checksum: 5b24fda6776d00e42431d7bcd86bce81cb0b6cabeb944142fe7b077a54ada2e155066ad06dbe790abdb397884bdc3151e04a9707b8cd185099efbc79780573ed +"is-negative-zero@npm:^2.0.3": + version: 2.0.3 + resolution: "is-negative-zero@npm:2.0.3" + checksum: bcdcf6b8b9714063ffcfa9929c575ac69bfdabb8f4574ff557dfc086df2836cf07e3906f5bbc4f2a5c12f8f3ba56af640c843cdfc74da8caed86c7c7d66fd08e languageName: node linkType: hard @@ -26893,13 +20283,6 @@ __metadata: languageName: node linkType: hard -"is-object@npm:^1.0.1": - version: 1.0.2 - resolution: "is-object@npm:1.0.2" - checksum: 9cfb80c3a850f453d4a77297e0556bc2040ac6bea5b6e418aee208654938b36bab768169bef3945ccfac7a9bb460edd8034e7c6d8973bcf147d7571e1b53e764 - languageName: node - linkType: hard - "is-path-cwd@npm:^2.2.0": version: 2.2.0 resolution: "is-path-cwd@npm:2.2.0" @@ -26921,13 +20304,6 @@ __metadata: languageName: node linkType: hard -"is-plain-obj@npm:^2.0.0": - version: 2.1.0 - resolution: "is-plain-obj@npm:2.1.0" - checksum: e5c9814cdaa627a9ad0a0964ded0e0491bfd9ace405c49a5d63c88b30a162f1512c069d5b80997893c4d0181eadc3fed02b4ab4b81059aba5620bfcdfdeb9c53 - languageName: node - linkType: hard - "is-plain-object@npm:5.0.0": version: 5.0.0 resolution: "is-plain-object@npm:5.0.0" @@ -26960,7 +20336,7 @@ __metadata: languageName: node linkType: hard -"is-regex@npm:^1.1.2, is-regex@npm:^1.1.4": +"is-regex@npm:^1.1.4": version: 1.1.4 resolution: "is-regex@npm:1.1.4" dependencies: @@ -26993,19 +20369,19 @@ __metadata: languageName: node linkType: hard -"is-set@npm:^2.0.1, is-set@npm:^2.0.2": - version: 2.0.2 - resolution: "is-set@npm:2.0.2" - checksum: 5f8bd1880df8c0004ce694e315e6e1e47a3452014be792880bb274a3b2cdb952fdb60789636ca6e084c7947ca8b7ae03ccaf54c93a7fcfed228af810559e5432 +"is-set@npm:^2.0.2, is-set@npm:^2.0.3": + version: 2.0.3 + resolution: "is-set@npm:2.0.3" + checksum: f73732e13f099b2dc879c2a12341cfc22ccaca8dd504e6edae26484bd5707a35d503fba5b4daad530a9b088ced1ae6c9d8200fd92e09b428fe14ea79ce8080b7 languageName: node linkType: hard -"is-shared-array-buffer@npm:^1.0.2": - version: 1.0.2 - resolution: "is-shared-array-buffer@npm:1.0.2" +"is-shared-array-buffer@npm:^1.0.2, is-shared-array-buffer@npm:^1.0.3": + version: 1.0.3 + resolution: "is-shared-array-buffer@npm:1.0.3" dependencies: - call-bind: ^1.0.2 - checksum: cfeee6f171f1b13e6cbc6f3b6cc44e192b93df39f3fcb31aa66ffb1d2df3b91e05664311659f9701baba62f5e98c83b0673c628e7adc30f55071c4874fcdccec + call-bind: ^1.0.7 + checksum: adc11ab0acbc934a7b9e5e9d6c588d4ec6682f6fea8cda5180721704fa32927582ede5b123349e32517fdadd07958973d24716c80e7ab198970c47acc09e59c7 languageName: node linkType: hard @@ -27057,16 +20433,12 @@ __metadata: languageName: node linkType: hard -"is-typed-array@npm:^1.1.10, is-typed-array@npm:^1.1.3, is-typed-array@npm:^1.1.9": - version: 1.1.10 - resolution: "is-typed-array@npm:1.1.10" +"is-typed-array@npm:^1.1.13, is-typed-array@npm:^1.1.3": + version: 1.1.13 + resolution: "is-typed-array@npm:1.1.13" dependencies: - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - for-each: ^0.3.3 - gopd: ^1.0.1 - has-tostringtag: ^1.0.0 - checksum: b71268a2e5f493f2b95af4cbfe7a65254a822f07d57f20c18f084347cd45f11810915fe37d7a6831fe4b81def24621a042fd1169ec558c50f830b591bc8c1f66 + which-typed-array: ^1.1.14 + checksum: fa5cb97d4a80e52c2cc8ed3778e39f175a1a2ae4ddf3adae3187d69586a1fd57cfa0b095db31f66aa90331e9e3da79184cea9c6abdcd1abc722dc3c3edd51cca languageName: node linkType: hard @@ -27100,13 +20472,6 @@ __metadata: languageName: node linkType: hard -"is-utf8@npm:^0.2.0": - version: 0.2.1 - resolution: "is-utf8@npm:0.2.1" - checksum: 3ed45e5b4ddfa04ed7e32c63d29c61b980ecd6df74698f45978b8c17a54034943bcbffb6ae243202e799682a66f90fef526f465dd39438745e9fe70794c1ef09 - languageName: node - linkType: hard - "is-valid-path@npm:^0.1.1": version: 0.1.1 resolution: "is-valid-path@npm:0.1.1" @@ -27116,10 +20481,10 @@ __metadata: languageName: node linkType: hard -"is-weakmap@npm:^2.0.1": - version: 2.0.1 - resolution: "is-weakmap@npm:2.0.1" - checksum: 9c9fec9efa7bf5030a4a927f33fff2a6976b93646259f92b517d3646c073cc5b98283a162ce75c412b060a46de07032444b530f0a4c9b6e012ef8f1741c3a987 +"is-weakmap@npm:^2.0.2": + version: 2.0.2 + resolution: "is-weakmap@npm:2.0.2" + checksum: 443c35bb86d5e6cc5929cd9c75a4024bb0fff9586ed50b092f94e700b89c43a33b186b76dbc6d54f3d3d09ece689ab38dcdc1af6a482cbe79c0f2da0a17f1299 languageName: node linkType: hard @@ -27132,27 +20497,13 @@ __metadata: languageName: node linkType: hard -"is-weakset@npm:^2.0.1": - version: 2.0.2 - resolution: "is-weakset@npm:2.0.2" +"is-weakset@npm:^2.0.3": + version: 2.0.3 + resolution: "is-weakset@npm:2.0.3" dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.1 - checksum: ef5136bd446ae4603229b897f73efd0720c6ab3ec6cc05c8d5c4b51aa9f95164713c4cad0a22ff1fedf04865ff86cae4648bc1d5eead4b6388e1150525af1cc1 - languageName: node - linkType: hard - -"is-whitespace-character@npm:^1.0.0": - version: 1.0.4 - resolution: "is-whitespace-character@npm:1.0.4" - checksum: 20f02cf42eafb44ff1706a04338dc45095cd691ae6984adb9a211b6b6df8d01e91722129ce55555e4c7c7b0b7d48e217553767f22eb7ec019b9f8dd3bc12cdfb - languageName: node - linkType: hard - -"is-window@npm:^1.0.2": - version: 1.0.2 - resolution: "is-window@npm:1.0.2" - checksum: f954f21c9fce64e6c72f8a908c3aaefa8fd6d1ef819acdfa1be007de70e5424bd2ac774950b38b523fd8ff4b581899efc1156cc6b0505040072e8ff25e57ec18 + call-bind: ^1.0.7 + get-intrinsic: ^1.2.4 + checksum: 8ad6141b6a400e7ce7c7442a13928c676d07b1f315ab77d9912920bf5f4170622f43126f111615788f26c3b1871158a6797c862233124507db0bcc33a9537d1a languageName: node linkType: hard @@ -27163,20 +20514,6 @@ __metadata: languageName: node linkType: hard -"is-word-character@npm:^1.0.0": - version: 1.0.4 - resolution: "is-word-character@npm:1.0.4" - checksum: 2247844064532986dc70869d961dccd1366932a147b52d4ec7f567f87edf7f9855a27b75f66b781db3b3175bbe05a76acbc6392a1a5c64c4c99fe3459dae33bd - languageName: node - linkType: hard - -"is-wsl@npm:^1.1.0": - version: 1.1.0 - resolution: "is-wsl@npm:1.1.0" - checksum: 7ad0012f21092d6f586c7faad84755a8ef0da9b9ec295e4dc82313cce4e1a93a3da3c217265016461f9b141503fe55fa6eb1fd5457d3f05e8d1bdbb48e50c13a - languageName: node - linkType: hard - "is-wsl@npm:^2.1.1, is-wsl@npm:^2.2.0": version: 2.2.0 resolution: "is-wsl@npm:2.2.0" @@ -27186,7 +20523,7 @@ __metadata: languageName: node linkType: hard -"isarray@npm:1.0.0, isarray@npm:^1.0.0, isarray@npm:~1.0.0": +"isarray@npm:1.0.0, isarray@npm:~1.0.0": version: 1.0.0 resolution: "isarray@npm:1.0.0" checksum: 18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d @@ -27201,9 +20538,9 @@ __metadata: linkType: hard "isbot@npm:^3.6.13": - version: 3.7.0 - resolution: "isbot@npm:3.7.0" - checksum: e35be3f593928679ddddbbbf45ea130f737620405ea6cc13f7ffe03be0ad218774fca874c38a69572bb1e1242f08433a8354dad78071f84dcf3cdc9fbc636679 + version: 3.8.0 + resolution: "isbot@npm:3.8.0" + checksum: 3e9daa907212db8e8e339fe0c7eacff7814de0db0aeef9ab379376b245f35058c6bdd2de0849442a791bc3d9587d749071e7d7e90aea00bf9f834f40c69ea16f languageName: node linkType: hard @@ -27214,6 +20551,13 @@ __metadata: languageName: node linkType: hard +"isexe@npm:^3.1.1": + version: 3.1.1 + resolution: "isexe@npm:3.1.1" + checksum: 9ec257654093443eb0a528a9c8cbba9c0ca7616ccb40abd6dde7202734d96bb86e4ac0d764f0f8cd965856aacbff2f4ce23e730dc19dfb41e3b0d865ca6fdcc7 + languageName: node + linkType: hard + "iso8601-duration@npm:^1.3.0": version: 1.3.0 resolution: "iso8601-duration@npm:1.3.0" @@ -27237,23 +20581,6 @@ __metadata: languageName: node linkType: hard -"isobject@npm:^4.0.0": - version: 4.0.0 - resolution: "isobject@npm:4.0.0" - checksum: 8efcda03af98cbb193737e30ffb77c71ca4e97dbf919f7aacec44b7410a166fa4e9fd71232bf5b00a919f98b5747ae359dbb5a5bc4195c93f6291423b9707df6 - languageName: node - linkType: hard - -"isomorphic-unfetch@npm:^3.1.0": - version: 3.1.0 - resolution: "isomorphic-unfetch@npm:3.1.0" - dependencies: - node-fetch: ^2.6.1 - unfetch: ^4.2.0 - checksum: d3b61fca06304db692b7f76bdfd3a00f410e42cfa7403c3b250546bf71589d18cf2f355922f57198e4cc4a9872d3647b20397a5c3edf1a347c90d57c83cf2a89 - languageName: node - linkType: hard - "isstream@npm:~0.1.2": version: 0.1.2 resolution: "isstream@npm:0.1.2" @@ -27262,9 +20589,9 @@ __metadata: linkType: hard "istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": - version: 3.2.0 - resolution: "istanbul-lib-coverage@npm:3.2.0" - checksum: 10ecb00a50cac2f506af8231ce523ffa1ac1310db0435c8ffaabb50c1d72539906583aa13c84f8835dc103998b9989edc3c1de989d2e2a96a91a9ba44e5db6b9 + version: 3.2.2 + resolution: "istanbul-lib-coverage@npm:3.2.2" + checksum: 6c7ff2106769e5f592ded1fb418f9f73b4411fd5a084387a5410538332b6567cd1763ff6b6cadca9b9eb2c443cce2f7ea7d7f1b8d315f9ce58539793b1e0922b languageName: node linkType: hard @@ -27294,26 +20621,26 @@ __metadata: linkType: hard "istanbul-lib-instrument@npm:^6.0.0": - version: 6.0.0 - resolution: "istanbul-lib-instrument@npm:6.0.0" + version: 6.0.2 + resolution: "istanbul-lib-instrument@npm:6.0.2" dependencies: - "@babel/core": ^7.12.3 - "@babel/parser": ^7.14.7 - "@istanbuljs/schema": ^0.1.2 + "@babel/core": ^7.23.9 + "@babel/parser": ^7.23.9 + "@istanbuljs/schema": ^0.1.3 istanbul-lib-coverage: ^3.2.0 semver: ^7.5.4 - checksum: ee86777f3692f95c3ae35c5cbc9aa979b551241da2de1284f75c507a2bdef948cc56ca90214c3bb47b5dc2ebe748610eb4f7c4d39b304f24a933bcd0867a05e8 + checksum: 405c6ac037bf8c7ee7495980b0cd5544b2c53078c10534d0c9ceeb92a9ea7dcf8510f58ccfce31336458a8fa6ccef27b570bbb602abaa8c1650f5496a807477c languageName: node linkType: hard "istanbul-lib-report@npm:^3.0.0": - version: 3.0.0 - resolution: "istanbul-lib-report@npm:3.0.0" + version: 3.0.1 + resolution: "istanbul-lib-report@npm:3.0.1" dependencies: istanbul-lib-coverage: ^3.0.0 - make-dir: ^3.0.0 + make-dir: ^4.0.0 supports-color: ^7.1.0 - checksum: 81b0d5187c7603ed71bdea0b701a7329f8146549ca19aa26d91b4a163aea756f9d55c1a6dc1dcd087e24dfcb99baa69e266a68644fbfd5dc98107d6f6f5948d2 + checksum: 84323afb14392de8b6a5714bd7e9af845cfbd56cfe71ed276cda2f5f1201aea673c7111901227ee33e68e4364e288d73861eb2ed48f6679d1e69a43b6d9b3ba7 languageName: node linkType: hard @@ -27328,23 +20655,13 @@ __metadata: languageName: node linkType: hard -"istanbul-reports@npm:^3.0.2, istanbul-reports@npm:^3.1.3, istanbul-reports@npm:^3.1.4": - version: 3.1.5 - resolution: "istanbul-reports@npm:3.1.5" +"istanbul-reports@npm:^3.0.2, istanbul-reports@npm:^3.1.3, istanbul-reports@npm:^3.1.5": + version: 3.1.7 + resolution: "istanbul-reports@npm:3.1.7" dependencies: html-escaper: ^2.0.0 istanbul-lib-report: ^3.0.0 - checksum: 3a147171bffdbd3034856410b6ec81637871d17d10986513328fec23df6b666f66bd08ea480f5b7a5b9f7e8abc30f3e3c2e7d1b661fc57cdc479aaaa677b1011 - languageName: node - linkType: hard - -"istanbul-reports@npm:^3.1.5": - version: 3.1.6 - resolution: "istanbul-reports@npm:3.1.6" - dependencies: - html-escaper: ^2.0.0 - istanbul-lib-report: ^3.0.0 - checksum: ec3f1bdbc51b3e0b325a5b9f4ad31a247697f31001df4e81075f7980413f14da1b5adfec574fd156efd3b0464023f61320f6718efc66ee72b32d89611cef99dd + checksum: a379fadf9cf8dc5dfe25568115721d4a7eb82fbd50b005a6672aff9c6989b20cc9312d7865814e0859cd8df58cbf664482e1d3604be0afde1f7fc3ccc1394a51 languageName: node linkType: hard @@ -27365,20 +20682,20 @@ __metadata: languageName: node linkType: hard -"jackspeak@npm:^2.0.3": - version: 2.2.1 - resolution: "jackspeak@npm:2.2.1" +"iterator.prototype@npm:^1.1.2": + version: 1.1.2 + resolution: "iterator.prototype@npm:1.1.2" dependencies: - "@isaacs/cliui": ^8.0.2 - "@pkgjs/parseargs": ^0.11.0 - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 510860a5d1eaf12cba509a09a8f7d1696090bfa7c8ae75c6d9c836890d2897409f3b3dd91039cf0020627d6eba8c024f571ae4d78bd956162b07794ddfb9dd62 + define-properties: ^1.2.1 + get-intrinsic: ^1.2.1 + has-symbols: ^1.0.3 + reflect.getprototypeof: ^1.0.4 + set-function-name: ^2.0.1 + checksum: a32151326095e916f306990d909f6bbf23e3221999a18ba686419535dcd1749b10ded505e89334b77dc4c7a58a8508978f0eb16c2c8573e6d412eb7eb894ea79 languageName: node linkType: hard -"jackspeak@npm:^2.3.5": +"jackspeak@npm:^2.3.6": version: 2.3.6 resolution: "jackspeak@npm:2.3.6" dependencies: @@ -27392,8 +20709,8 @@ __metadata: linkType: hard "jake@npm:^10.8.5": - version: 10.8.7 - resolution: "jake@npm:10.8.7" + version: 10.9.1 + resolution: "jake@npm:10.9.1" dependencies: async: ^3.2.3 chalk: ^4.0.2 @@ -27401,7 +20718,7 @@ __metadata: minimatch: ^3.1.2 bin: jake: bin/cli.js - checksum: 89326d01a8bc110d02d973729a66394c79a34b34461116f5c530a2a2dbc30265683fe6737928f75df9178e9d369ff1442f5753fb983d525e740eefdadc56a103 + checksum: dda972431a926462f08fcf583ea8997884216a43daa5cce81cb42e7e661dc244f836c0a802fde23439c6e1fc59743d1c0be340aa726d3b17d77557611a5cd541 languageName: node linkType: hard @@ -27438,27 +20755,6 @@ __metadata: languageName: node linkType: hard -"jest-changed-files@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-changed-files@npm:29.5.0" - dependencies: - execa: ^5.0.0 - p-limit: ^3.1.0 - checksum: 96334c78507a13c0f11f1360d893ade78fba7fd169825ca4acf7565156ceddd89b952be81c00378fa87ab642d3f44902c34a20f21b561e985e79f6e81fa7e9a8 - languageName: node - linkType: hard - -"jest-changed-files@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-changed-files@npm:29.6.3" - dependencies: - execa: ^5.0.0 - jest-util: ^29.6.3 - p-limit: ^3.1.0 - checksum: c73e684832ca296276853f591569f0af265ca3d9de48907e3df5821e33b5e1b85bc2add4e7a4397878ed715bcebb99cedae6c4f03499420ae30ea5853eeb2f1f - languageName: node - linkType: hard - "jest-changed-files@npm:^29.7.0": version: 29.7.0 resolution: "jest-changed-files@npm:29.7.0" @@ -27497,62 +20793,6 @@ __metadata: languageName: node linkType: hard -"jest-circus@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-circus@npm:29.5.0" - dependencies: - "@jest/environment": ^29.5.0 - "@jest/expect": ^29.5.0 - "@jest/test-result": ^29.5.0 - "@jest/types": ^29.5.0 - "@types/node": "*" - chalk: ^4.0.0 - co: ^4.6.0 - dedent: ^0.7.0 - is-generator-fn: ^2.0.0 - jest-each: ^29.5.0 - jest-matcher-utils: ^29.5.0 - jest-message-util: ^29.5.0 - jest-runtime: ^29.5.0 - jest-snapshot: ^29.5.0 - jest-util: ^29.5.0 - p-limit: ^3.1.0 - pretty-format: ^29.5.0 - pure-rand: ^6.0.0 - slash: ^3.0.0 - stack-utils: ^2.0.3 - checksum: 77f77b826941f67e9794e185072ee612cbddf53a1cfbf736de86176b7dc54e54aef151cf31b492adaef221f550924fd60dbaa01c9b939c3a4bfb46d8392c60a8 - languageName: node - linkType: hard - -"jest-circus@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-circus@npm:29.6.4" - dependencies: - "@jest/environment": ^29.6.4 - "@jest/expect": ^29.6.4 - "@jest/test-result": ^29.6.4 - "@jest/types": ^29.6.3 - "@types/node": "*" - chalk: ^4.0.0 - co: ^4.6.0 - dedent: ^1.0.0 - is-generator-fn: ^2.0.0 - jest-each: ^29.6.3 - jest-matcher-utils: ^29.6.4 - jest-message-util: ^29.6.3 - jest-runtime: ^29.6.4 - jest-snapshot: ^29.6.4 - jest-util: ^29.6.3 - p-limit: ^3.1.0 - pretty-format: ^29.6.3 - pure-rand: ^6.0.0 - slash: ^3.0.0 - stack-utils: ^2.0.3 - checksum: b770c62e43e097885a165117a261c225805f73339b38b12bcaabe819589d9fc72e6d60cb07fd1c493efbde7af979f87ca714b3f590226603cdb08d34ca6049e3 - languageName: node - linkType: hard - "jest-circus@npm:^29.7.0": version: 29.7.0 resolution: "jest-circus@npm:29.7.0" @@ -27655,60 +20895,6 @@ __metadata: languageName: node linkType: hard -"jest-cli@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-cli@npm:29.5.0" - dependencies: - "@jest/core": ^29.5.0 - "@jest/test-result": ^29.5.0 - "@jest/types": ^29.5.0 - chalk: ^4.0.0 - exit: ^0.1.2 - graceful-fs: ^4.2.9 - import-local: ^3.0.2 - jest-config: ^29.5.0 - jest-util: ^29.5.0 - jest-validate: ^29.5.0 - prompts: ^2.0.1 - yargs: ^17.3.1 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - bin: - jest: bin/jest.js - checksum: d63df7e329760bc036d11980883399de86b41a7fa93bbc2e79feef28284b096dec40afc21796504555ccbf32806bfc78cf64a63eac9093bb4f036b282b409863 - languageName: node - linkType: hard - -"jest-cli@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-cli@npm:29.6.4" - dependencies: - "@jest/core": ^29.6.4 - "@jest/test-result": ^29.6.4 - "@jest/types": ^29.6.3 - chalk: ^4.0.0 - exit: ^0.1.2 - graceful-fs: ^4.2.9 - import-local: ^3.0.2 - jest-config: ^29.6.4 - jest-util: ^29.6.3 - jest-validate: ^29.6.3 - prompts: ^2.0.1 - yargs: ^17.3.1 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - bin: - jest: bin/jest.js - checksum: c6198eb2769711b81fb71092b5a353c6d8fd97f9d1bab8cea1526769d5039dee831908d4213ac6ed7d698df215839d8cf2a1e17e518b1e141597709584c1ab2f - languageName: node - linkType: hard - "jest-cli@npm:^29.7.0": version: 29.7.0 resolution: "jest-cli@npm:29.7.0" @@ -27830,82 +21016,6 @@ __metadata: languageName: node linkType: hard -"jest-config@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-config@npm:29.5.0" - dependencies: - "@babel/core": ^7.11.6 - "@jest/test-sequencer": ^29.5.0 - "@jest/types": ^29.5.0 - babel-jest: ^29.5.0 - chalk: ^4.0.0 - ci-info: ^3.2.0 - deepmerge: ^4.2.2 - glob: ^7.1.3 - graceful-fs: ^4.2.9 - jest-circus: ^29.5.0 - jest-environment-node: ^29.5.0 - jest-get-type: ^29.4.3 - jest-regex-util: ^29.4.3 - jest-resolve: ^29.5.0 - jest-runner: ^29.5.0 - jest-util: ^29.5.0 - jest-validate: ^29.5.0 - micromatch: ^4.0.4 - parse-json: ^5.2.0 - pretty-format: ^29.5.0 - slash: ^3.0.0 - strip-json-comments: ^3.1.1 - peerDependencies: - "@types/node": "*" - ts-node: ">=9.0.0" - peerDependenciesMeta: - "@types/node": - optional: true - ts-node: - optional: true - checksum: 01780eb66815e3d31d237aab5d7611ea59e0cdf159cbab2a7c682cb08bde6d053c17a528547440fb1b0294c26ebfd5b54ad35d8c9439f6fae76960ee0bc90197 - languageName: node - linkType: hard - -"jest-config@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-config@npm:29.6.4" - dependencies: - "@babel/core": ^7.11.6 - "@jest/test-sequencer": ^29.6.4 - "@jest/types": ^29.6.3 - babel-jest: ^29.6.4 - chalk: ^4.0.0 - ci-info: ^3.2.0 - deepmerge: ^4.2.2 - glob: ^7.1.3 - graceful-fs: ^4.2.9 - jest-circus: ^29.6.4 - jest-environment-node: ^29.6.4 - jest-get-type: ^29.6.3 - jest-regex-util: ^29.6.3 - jest-resolve: ^29.6.4 - jest-runner: ^29.6.4 - jest-util: ^29.6.3 - jest-validate: ^29.6.3 - micromatch: ^4.0.4 - parse-json: ^5.2.0 - pretty-format: ^29.6.3 - slash: ^3.0.0 - strip-json-comments: ^3.1.1 - peerDependencies: - "@types/node": "*" - ts-node: ">=9.0.0" - peerDependenciesMeta: - "@types/node": - optional: true - ts-node: - optional: true - checksum: 0c2411c9f6fd98ad1a42d6b908951fc0e6d8a31eaac8c419f4ae92e7a496ed2a6a0c3494954377a0a7ad0723bb192c030e0acffe7ad34443be616f0acce13dda - languageName: node - linkType: hard - "jest-config@npm:^29.7.0": version: 29.7.0 resolution: "jest-config@npm:29.7.0" @@ -27980,30 +21090,6 @@ __metadata: languageName: node linkType: hard -"jest-diff@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-diff@npm:29.5.0" - dependencies: - chalk: ^4.0.0 - diff-sequences: ^29.4.3 - jest-get-type: ^29.4.3 - pretty-format: ^29.5.0 - checksum: 00fda597fa6ee22774453c3cd35c2210bd7f749cf48ad7a41c13b898b2943c9c047842720eb928cdb949b9de87204d8d8987bf12aefdb2f0504f5f4112cab5b0 - languageName: node - linkType: hard - -"jest-diff@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-diff@npm:29.6.4" - dependencies: - chalk: ^4.0.0 - diff-sequences: ^29.6.3 - jest-get-type: ^29.6.3 - pretty-format: ^29.6.3 - checksum: 5f96be0f15ba8e70acfa5512ca49ba67363678e7ce222889612385a8d9dd042822fdd22a514394fe726b1f462e605bc5d7fc130bd81fa2247e7d40413975d576 - languageName: node - linkType: hard - "jest-diff@npm:^29.7.0": version: 29.7.0 resolution: "jest-diff@npm:29.7.0" @@ -28043,24 +21129,6 @@ __metadata: languageName: node linkType: hard -"jest-docblock@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-docblock@npm:29.4.3" - dependencies: - detect-newline: ^3.0.0 - checksum: 25cdea8fe77ff09d958abd347e26dcd8766ca69d9935bc626a89d694c91d33be06d4c088b02e4b3f143f532f726a10dff0bfe1e2387a0972a95addf5d64ed407 - languageName: node - linkType: hard - -"jest-docblock@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-docblock@npm:29.6.3" - dependencies: - detect-newline: ^3.0.0 - checksum: e22c78dd305a3d5211d83cfa0e25e6ea571cfab935e261dc18b17db1a547ecde014c9031334fdc30626e8d157196df981f0c87ef6561978d6e2466adb6bebe09 - languageName: node - linkType: hard - "jest-docblock@npm:^29.7.0": version: 29.7.0 resolution: "jest-docblock@npm:29.7.0" @@ -28109,32 +21177,6 @@ __metadata: languageName: node linkType: hard -"jest-each@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-each@npm:29.5.0" - dependencies: - "@jest/types": ^29.5.0 - chalk: ^4.0.0 - jest-get-type: ^29.4.3 - jest-util: ^29.5.0 - pretty-format: ^29.5.0 - checksum: 214f6b5adfc0d6a3e837769018b7a7b69f41e99aac939fe4730bcca23f69e3566ed23706f95a396b20e63e6b9f90990053fc3c1662808036d4f41e4d6d32641d - languageName: node - linkType: hard - -"jest-each@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-each@npm:29.6.3" - dependencies: - "@jest/types": ^29.6.3 - chalk: ^4.0.0 - jest-get-type: ^29.6.3 - jest-util: ^29.6.3 - pretty-format: ^29.6.3 - checksum: dabbe7cfc087d9a7d679344f880c633e4f12d47bb51076473d642cc6d5d7b5c0a0f6947e0934a38781c5d7e5b8094b7e4e7164074d8b24fa4fc8dcfcbd0ce55d - languageName: node - linkType: hard - "jest-each@npm:^29.7.0": version: 29.7.0 resolution: "jest-each@npm:29.7.0" @@ -28192,24 +21234,24 @@ __metadata: languageName: node linkType: hard -"jest-environment-jsdom@npm:^29.4.1": - version: 29.5.0 - resolution: "jest-environment-jsdom@npm:29.5.0" +"jest-environment-jsdom@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-environment-jsdom@npm:29.7.0" dependencies: - "@jest/environment": ^29.5.0 - "@jest/fake-timers": ^29.5.0 - "@jest/types": ^29.5.0 + "@jest/environment": ^29.7.0 + "@jest/fake-timers": ^29.7.0 + "@jest/types": ^29.6.3 "@types/jsdom": ^20.0.0 "@types/node": "*" - jest-mock: ^29.5.0 - jest-util: ^29.5.0 + jest-mock: ^29.7.0 + jest-util: ^29.7.0 jsdom: ^20.0.0 peerDependencies: canvas: ^2.5.0 peerDependenciesMeta: canvas: optional: true - checksum: 972a1bdfb1d508a359951ec11ade5dfad7cfabea0ab9f7746737ba10e0c6381e34f2b4acb03c7e5eb623611813310dfb0775eb0607c5537b7618234d04aab2ac + checksum: 139b94e2c8ec1bb5a46ce17df5211da65ce867354b3fd4e00fa6a0d1da95902df4cf7881273fc6ea937e5c325d39d6773f0d41b6c469363334de9d489d2c321f languageName: node linkType: hard @@ -28255,34 +21297,6 @@ __metadata: languageName: node linkType: hard -"jest-environment-node@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-environment-node@npm:29.5.0" - dependencies: - "@jest/environment": ^29.5.0 - "@jest/fake-timers": ^29.5.0 - "@jest/types": ^29.5.0 - "@types/node": "*" - jest-mock: ^29.5.0 - jest-util: ^29.5.0 - checksum: 2e636a095ff9a9e0aa20fda5b4c06eebed8f3ba2411062bdf724b114eedafd49b880167998af9f77aa8aa68231621aebe3998389d73433e9553ea5735cad1e14 - languageName: node - linkType: hard - -"jest-environment-node@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-environment-node@npm:29.6.4" - dependencies: - "@jest/environment": ^29.6.4 - "@jest/fake-timers": ^29.6.4 - "@jest/types": ^29.6.3 - "@types/node": "*" - jest-mock: ^29.6.3 - jest-util: ^29.6.3 - checksum: 768d2c2a5b70b91435f1c8642377f2e92377e922d51e758e475958ff31f0b2c57c4c1f91041328c604256ba9fc284cbefa6203448b1ac67b2d53ac188807b66a - languageName: node - linkType: hard - "jest-environment-node@npm:^29.7.0": version: 29.7.0 resolution: "jest-environment-node@npm:29.7.0" @@ -28318,13 +21332,6 @@ __metadata: languageName: node linkType: hard -"jest-get-type@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-get-type@npm:29.4.3" - checksum: 874b0ced6b1cc677ff7fcf0dc86d02674617a7d0b73d47097604fb3ca460178d16104efdd3837e8b8bf0520ad5d210838c07483b058802b457b8413e60628fd0 - languageName: node - linkType: hard - "jest-get-type@npm:^29.6.3": version: 29.6.3 resolution: "jest-get-type@npm:29.6.3" @@ -28405,52 +21412,6 @@ __metadata: languageName: node linkType: hard -"jest-haste-map@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-haste-map@npm:29.5.0" - dependencies: - "@jest/types": ^29.5.0 - "@types/graceful-fs": ^4.1.3 - "@types/node": "*" - anymatch: ^3.0.3 - fb-watchman: ^2.0.0 - fsevents: ^2.3.2 - graceful-fs: ^4.2.9 - jest-regex-util: ^29.4.3 - jest-util: ^29.5.0 - jest-worker: ^29.5.0 - micromatch: ^4.0.4 - walker: ^1.0.8 - dependenciesMeta: - fsevents: - optional: true - checksum: 162edfa185478db9ebe7dff73f3475ef2c205d94fa2b0fc3b41aba4fc29bab274d4a76ca41ca20ea7d9d6ed2b0d8519e298cfffbf5cad6631412d8961c190612 - languageName: node - linkType: hard - -"jest-haste-map@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-haste-map@npm:29.6.4" - dependencies: - "@jest/types": ^29.6.3 - "@types/graceful-fs": ^4.1.3 - "@types/node": "*" - anymatch: ^3.0.3 - fb-watchman: ^2.0.0 - fsevents: ^2.3.2 - graceful-fs: ^4.2.9 - jest-regex-util: ^29.6.3 - jest-util: ^29.6.3 - jest-worker: ^29.6.4 - micromatch: ^4.0.4 - walker: ^1.0.8 - dependenciesMeta: - fsevents: - optional: true - checksum: 86dfe6c767941cb47dc201cf185b81380cfc91851b0f1e9115ded5a6f4a5aa442e0e8291ff76cb4c72a7cc568dfc9bc3b86257db79b18e6c6294a526e40acab8 - languageName: node - linkType: hard - "jest-haste-map@npm:^29.7.0": version: 29.7.0 resolution: "jest-haste-map@npm:29.7.0" @@ -28580,26 +21541,6 @@ __metadata: languageName: node linkType: hard -"jest-leak-detector@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-leak-detector@npm:29.5.0" - dependencies: - jest-get-type: ^29.4.3 - pretty-format: ^29.5.0 - checksum: d7db5d4a7cb676fc151f533d6887f3d6bbb4e35346346cbed0b5583c296b13af2d3c8434b30f62b0eb9c711718c7f4bd48496c47af3a20320ee162e33d64aaf2 - languageName: node - linkType: hard - -"jest-leak-detector@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-leak-detector@npm:29.6.3" - dependencies: - jest-get-type: ^29.6.3 - pretty-format: ^29.6.3 - checksum: 18863c20a8639398b28d72ab8dd23e4c5dbec90fa81cc8bd52c6e0891f0954e8bfdaedbf4c19b0bbcdaaff24bc71002a6dc3e7ef1eefc75b46581f651a9a47c7 - languageName: node - linkType: hard - "jest-leak-detector@npm:^29.7.0": version: 29.7.0 resolution: "jest-leak-detector@npm:29.7.0" @@ -28646,30 +21587,6 @@ __metadata: languageName: node linkType: hard -"jest-matcher-utils@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-matcher-utils@npm:29.5.0" - dependencies: - chalk: ^4.0.0 - jest-diff: ^29.5.0 - jest-get-type: ^29.4.3 - pretty-format: ^29.5.0 - checksum: 0a3ae95ef5c5c4ac2b2c503c2f57e173fa82725722e1fadcd902fd801afe17d9d36e9366820959465f553627bf1e481a0e4a540125f3b4371eec674b3557f7f3 - languageName: node - linkType: hard - -"jest-matcher-utils@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-matcher-utils@npm:29.6.4" - dependencies: - chalk: ^4.0.0 - jest-diff: ^29.6.4 - jest-get-type: ^29.6.3 - pretty-format: ^29.6.3 - checksum: aa54f7075438160bd29e8c0a02d6b7e6ed1f18bab5670d161d1555e5cfa9b61e86306a260ca0304680fb1b357a944fd1d007b6519f91fc6f67d72997b1a7fdb8 - languageName: node - linkType: hard - "jest-matcher-utils@npm:^29.7.0": version: 29.7.0 resolution: "jest-matcher-utils@npm:29.7.0" @@ -28732,40 +21649,6 @@ __metadata: languageName: node linkType: hard -"jest-message-util@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-message-util@npm:29.5.0" - dependencies: - "@babel/code-frame": ^7.12.13 - "@jest/types": ^29.5.0 - "@types/stack-utils": ^2.0.0 - chalk: ^4.0.0 - graceful-fs: ^4.2.9 - micromatch: ^4.0.4 - pretty-format: ^29.5.0 - slash: ^3.0.0 - stack-utils: ^2.0.3 - checksum: 706e89cacc89c090af584f4687c4e7f0616706481e468ec7c88270e07ae7458a829e477b7b3dff56b75d801f799d65eb2c28d6453c25dd02bea0fd98f0809dbb - languageName: node - linkType: hard - -"jest-message-util@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-message-util@npm:29.6.3" - dependencies: - "@babel/code-frame": ^7.12.13 - "@jest/types": ^29.6.3 - "@types/stack-utils": ^2.0.0 - chalk: ^4.0.0 - graceful-fs: ^4.2.9 - micromatch: ^4.0.4 - pretty-format: ^29.6.3 - slash: ^3.0.0 - stack-utils: ^2.0.3 - checksum: 5ae17c0aa8076bd0d4c68a036865cf156084cf7b4f69b4ffee0f49da61f7fe9eb38c6405c1f6967df031ffe14f8a31830baa1f04f1dbea52f239689cd4e5b326 - languageName: node - linkType: hard - "jest-message-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-message-util@npm:29.7.0" @@ -28812,28 +21695,6 @@ __metadata: languageName: node linkType: hard -"jest-mock@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-mock@npm:29.5.0" - dependencies: - "@jest/types": ^29.5.0 - "@types/node": "*" - jest-util: ^29.5.0 - checksum: c5b71d397d6acd44d99cd48dad8ca76334fc5a27e120da72d264d7527a9efc7c6fc431d79de64d0b73aa0ab26a2d0712498e323d42b9e03bee05e983b0d2035c - languageName: node - linkType: hard - -"jest-mock@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-mock@npm:29.6.3" - dependencies: - "@jest/types": ^29.6.3 - "@types/node": "*" - jest-util: ^29.6.3 - checksum: 2801f1d717de6bbebe05871fff71b245771f91fa9c6b543df58060aa4e972a8d1fd4dfea8c5c7b37ee02be5a5e3a9edb048d8a114e7186e101b52e50d61d5c07 - languageName: node - linkType: hard - "jest-mock@npm:^29.7.0": version: 29.7.0 resolution: "jest-mock@npm:29.7.0" @@ -28878,13 +21739,6 @@ __metadata: languageName: node linkType: hard -"jest-regex-util@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-regex-util@npm:29.4.3" - checksum: a7a4508bda47c5177e7337fb6fb22e9adab414ba141f224c9992c86973da1ccf5c69040e63636090ad26ef3a123d28bec950fa99496c157444b4f847e5e5a670 - languageName: node - linkType: hard - "jest-regex-util@npm:^29.6.3": version: 29.6.3 resolution: "jest-regex-util@npm:29.6.3" @@ -28925,26 +21779,6 @@ __metadata: languageName: node linkType: hard -"jest-resolve-dependencies@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-resolve-dependencies@npm:29.5.0" - dependencies: - jest-regex-util: ^29.4.3 - jest-snapshot: ^29.5.0 - checksum: fbe513b7d905c4a70be17fd1cb4bd83da1e82cceb47ed7ceababbe11c75f1d0c18eadeb3f4ebb6997ba979f35fa18dfd02e1d57eb556675e47b35675fde0aac7 - languageName: node - linkType: hard - -"jest-resolve-dependencies@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-resolve-dependencies@npm:29.6.4" - dependencies: - jest-regex-util: ^29.6.3 - jest-snapshot: ^29.6.4 - checksum: 96af4418b1bd017f658233c2f1a4deda39d8d9d85525be384c808347f57bd969f5275af8ab3be25d642b49bfee47cb1fefce02b12a729720cb75bb6b7d4426fa - languageName: node - linkType: hard - "jest-resolve-dependencies@npm:^29.7.0": version: 29.7.0 resolution: "jest-resolve-dependencies@npm:29.7.0" @@ -29006,40 +21840,6 @@ __metadata: languageName: node linkType: hard -"jest-resolve@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-resolve@npm:29.5.0" - dependencies: - chalk: ^4.0.0 - graceful-fs: ^4.2.9 - jest-haste-map: ^29.5.0 - jest-pnp-resolver: ^1.2.2 - jest-util: ^29.5.0 - jest-validate: ^29.5.0 - resolve: ^1.20.0 - resolve.exports: ^2.0.0 - slash: ^3.0.0 - checksum: e7ea3b1cf865a7e63ad297d0f43a093dde145f9ca72dc8e75b6c7eb3af60fe78e4f7d024fd92fa280419a4ca038d42a9268d4d5d512958d11347e680daca1f12 - languageName: node - linkType: hard - -"jest-resolve@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-resolve@npm:29.6.4" - dependencies: - chalk: ^4.0.0 - graceful-fs: ^4.2.9 - jest-haste-map: ^29.6.4 - jest-pnp-resolver: ^1.2.2 - jest-util: ^29.6.3 - jest-validate: ^29.6.3 - resolve: ^1.20.0 - resolve.exports: ^2.0.0 - slash: ^3.0.0 - checksum: 3924185caacc4a8f1a3ee7f580327987b8533446f8654d86713f0ba3eaf942ee3e6cef159e96cedad074df8bd7a2d2b6395d2dd2b3b7cf396d9d090943ffb897 - languageName: node - linkType: hard - "jest-resolve@npm:^29.7.0": version: 29.7.0 resolution: "jest-resolve@npm:29.7.0" @@ -29141,64 +21941,6 @@ __metadata: languageName: node linkType: hard -"jest-runner@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-runner@npm:29.5.0" - dependencies: - "@jest/console": ^29.5.0 - "@jest/environment": ^29.5.0 - "@jest/test-result": ^29.5.0 - "@jest/transform": ^29.5.0 - "@jest/types": ^29.5.0 - "@types/node": "*" - chalk: ^4.0.0 - emittery: ^0.13.1 - graceful-fs: ^4.2.9 - jest-docblock: ^29.4.3 - jest-environment-node: ^29.5.0 - jest-haste-map: ^29.5.0 - jest-leak-detector: ^29.5.0 - jest-message-util: ^29.5.0 - jest-resolve: ^29.5.0 - jest-runtime: ^29.5.0 - jest-util: ^29.5.0 - jest-watcher: ^29.5.0 - jest-worker: ^29.5.0 - p-limit: ^3.1.0 - source-map-support: 0.5.13 - checksum: 96f47976b9bcc0554455c200d02ebc1547b9a7749b05353c0d55aff535509032c0c12ea25ccc294350f62c14665dbc1e00b15e0d1c52207edfb807e4fec4a36a - languageName: node - linkType: hard - -"jest-runner@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-runner@npm:29.6.4" - dependencies: - "@jest/console": ^29.6.4 - "@jest/environment": ^29.6.4 - "@jest/test-result": ^29.6.4 - "@jest/transform": ^29.6.4 - "@jest/types": ^29.6.3 - "@types/node": "*" - chalk: ^4.0.0 - emittery: ^0.13.1 - graceful-fs: ^4.2.9 - jest-docblock: ^29.6.3 - jest-environment-node: ^29.6.4 - jest-haste-map: ^29.6.4 - jest-leak-detector: ^29.6.3 - jest-message-util: ^29.6.3 - jest-resolve: ^29.6.4 - jest-runtime: ^29.6.4 - jest-util: ^29.6.3 - jest-watcher: ^29.6.4 - jest-worker: ^29.6.4 - p-limit: ^3.1.0 - source-map-support: 0.5.13 - checksum: 5af7657c1f6db038bc5146ddb04ebc324cd82d623818607de508d926678ba494e08affef48879e7a6fca1d6ea6255d3d8dbbb80f1b9951b08844b8533f8747a5 - languageName: node - linkType: hard - "jest-runner@npm:^29.7.0": version: 29.7.0 resolution: "jest-runner@npm:29.7.0" @@ -29331,66 +22073,6 @@ __metadata: languageName: node linkType: hard -"jest-runtime@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-runtime@npm:29.5.0" - dependencies: - "@jest/environment": ^29.5.0 - "@jest/fake-timers": ^29.5.0 - "@jest/globals": ^29.5.0 - "@jest/source-map": ^29.4.3 - "@jest/test-result": ^29.5.0 - "@jest/transform": ^29.5.0 - "@jest/types": ^29.5.0 - "@types/node": "*" - chalk: ^4.0.0 - cjs-module-lexer: ^1.0.0 - collect-v8-coverage: ^1.0.0 - glob: ^7.1.3 - graceful-fs: ^4.2.9 - jest-haste-map: ^29.5.0 - jest-message-util: ^29.5.0 - jest-mock: ^29.5.0 - jest-regex-util: ^29.4.3 - jest-resolve: ^29.5.0 - jest-snapshot: ^29.5.0 - jest-util: ^29.5.0 - slash: ^3.0.0 - strip-bom: ^4.0.0 - checksum: 9b5c0a97e1f24945059695e056188041730a3f1dc5924153e323eb7429244e10e7cc877b13d057869d6621c460deae11b77a2a2e9ab56e22b56864a3e44c4448 - languageName: node - linkType: hard - -"jest-runtime@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-runtime@npm:29.6.4" - dependencies: - "@jest/environment": ^29.6.4 - "@jest/fake-timers": ^29.6.4 - "@jest/globals": ^29.6.4 - "@jest/source-map": ^29.6.3 - "@jest/test-result": ^29.6.4 - "@jest/transform": ^29.6.4 - "@jest/types": ^29.6.3 - "@types/node": "*" - chalk: ^4.0.0 - cjs-module-lexer: ^1.0.0 - collect-v8-coverage: ^1.0.0 - glob: ^7.1.3 - graceful-fs: ^4.2.9 - jest-haste-map: ^29.6.4 - jest-message-util: ^29.6.3 - jest-mock: ^29.6.3 - jest-regex-util: ^29.6.3 - jest-resolve: ^29.6.4 - jest-snapshot: ^29.6.4 - jest-util: ^29.6.3 - slash: ^3.0.0 - strip-bom: ^4.0.0 - checksum: 82c63b944ac84808480e89d6f1ad294d0bf7c1efce566493be3ff103ee706020addb430ebc0f43d44e8a1adb59a749385a30efc1619cb3511db690ad5d42a392 - languageName: node - linkType: hard - "jest-runtime@npm:^29.7.0": version: 29.7.0 resolution: "jest-runtime@npm:29.7.0" @@ -29527,65 +22209,6 @@ __metadata: languageName: node linkType: hard -"jest-snapshot@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-snapshot@npm:29.5.0" - dependencies: - "@babel/core": ^7.11.6 - "@babel/generator": ^7.7.2 - "@babel/plugin-syntax-jsx": ^7.7.2 - "@babel/plugin-syntax-typescript": ^7.7.2 - "@babel/traverse": ^7.7.2 - "@babel/types": ^7.3.3 - "@jest/expect-utils": ^29.5.0 - "@jest/transform": ^29.5.0 - "@jest/types": ^29.5.0 - "@types/babel__traverse": ^7.0.6 - "@types/prettier": ^2.1.5 - babel-preset-current-node-syntax: ^1.0.0 - chalk: ^4.0.0 - expect: ^29.5.0 - graceful-fs: ^4.2.9 - jest-diff: ^29.5.0 - jest-get-type: ^29.4.3 - jest-matcher-utils: ^29.5.0 - jest-message-util: ^29.5.0 - jest-util: ^29.5.0 - natural-compare: ^1.4.0 - pretty-format: ^29.5.0 - semver: ^7.3.5 - checksum: db9957d9c8607d75bb08302605331b5d90fa738fafeed820ab8ebcb2c90f9e62fb4fec0b4c826c04a37557cbb7a9ed26a10b0c74d46ffedce2d6ae8a9c891b00 - languageName: node - linkType: hard - -"jest-snapshot@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-snapshot@npm:29.6.4" - dependencies: - "@babel/core": ^7.11.6 - "@babel/generator": ^7.7.2 - "@babel/plugin-syntax-jsx": ^7.7.2 - "@babel/plugin-syntax-typescript": ^7.7.2 - "@babel/types": ^7.3.3 - "@jest/expect-utils": ^29.6.4 - "@jest/transform": ^29.6.4 - "@jest/types": ^29.6.3 - babel-preset-current-node-syntax: ^1.0.0 - chalk: ^4.0.0 - expect: ^29.6.4 - graceful-fs: ^4.2.9 - jest-diff: ^29.6.4 - jest-get-type: ^29.6.3 - jest-matcher-utils: ^29.6.4 - jest-message-util: ^29.6.3 - jest-util: ^29.6.3 - natural-compare: ^1.4.0 - pretty-format: ^29.6.3 - semver: ^7.5.3 - checksum: 696db4e73131d8e0df97a0bdd19c8b6e89910021b6823ce603a12a128671f42a7e7aede9d7b42ed79e4f583b7cdb46e140635c4bc6a65e072baa2ddf46fb15fc - languageName: node - linkType: hard - "jest-snapshot@npm:^29.7.0": version: 29.7.0 resolution: "jest-snapshot@npm:29.7.0" @@ -29641,7 +22264,7 @@ __metadata: languageName: node linkType: hard -"jest-util@npm:^27.0.0, jest-util@npm:^27.5.1": +"jest-util@npm:^27.5.1": version: 27.5.1 resolution: "jest-util@npm:27.5.1" dependencies: @@ -29655,35 +22278,7 @@ __metadata: languageName: node linkType: hard -"jest-util@npm:^29.0.0, jest-util@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-util@npm:29.5.0" - dependencies: - "@jest/types": ^29.5.0 - "@types/node": "*" - chalk: ^4.0.0 - ci-info: ^3.2.0 - graceful-fs: ^4.2.9 - picomatch: ^2.2.3 - checksum: c7f1dc8ae82cd9614a31e09806499560b4812beb57589b214241dd213d3cc6d24417593aef2caf2d3d9694925438849fec371ff36ca8a7f1be8438fd41e83373 - languageName: node - linkType: hard - -"jest-util@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-util@npm:29.6.3" - dependencies: - "@jest/types": ^29.6.3 - "@types/node": "*" - chalk: ^4.0.0 - ci-info: ^3.2.0 - graceful-fs: ^4.2.9 - picomatch: ^2.2.3 - checksum: 9428c07696f27aa8f230a13a35546559f9a087f3e3744f53f69a620598234c03004b808b1b4a12120cc5771a88403bf0a1e3f95a7ccd610acf03d90c36135e88 - languageName: node - linkType: hard - -"jest-util@npm:^29.7.0": +"jest-util@npm:^29.0.0, jest-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-util@npm:29.7.0" dependencies: @@ -29739,34 +22334,6 @@ __metadata: languageName: node linkType: hard -"jest-validate@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-validate@npm:29.5.0" - dependencies: - "@jest/types": ^29.5.0 - camelcase: ^6.2.0 - chalk: ^4.0.0 - jest-get-type: ^29.4.3 - leven: ^3.1.0 - pretty-format: ^29.5.0 - checksum: 7aabde27a9b736df65902a1bb4ec63af518d4c95e12a910e7658140784168f08c662d5babe67dfa70d843dd2096bc08aa7090fef83c7a9d6bb0893793c3a599a - languageName: node - linkType: hard - -"jest-validate@npm:^29.6.3": - version: 29.6.3 - resolution: "jest-validate@npm:29.6.3" - dependencies: - "@jest/types": ^29.6.3 - camelcase: ^6.2.0 - chalk: ^4.0.0 - jest-get-type: ^29.6.3 - leven: ^3.1.0 - pretty-format: ^29.6.3 - checksum: 148bacc985abf4e35cba5fd09e145ef00f3835a7625a0df18caf6c93c7a4297f492b7ae61d767f2dc37c7c2c67034ed3e8922dc1336407b4e9db235b107ddde9 - languageName: node - linkType: hard - "jest-validate@npm:^29.7.0": version: 29.7.0 resolution: "jest-validate@npm:29.7.0" @@ -29825,38 +22392,6 @@ __metadata: languageName: node linkType: hard -"jest-watcher@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-watcher@npm:29.5.0" - dependencies: - "@jest/test-result": ^29.5.0 - "@jest/types": ^29.5.0 - "@types/node": "*" - ansi-escapes: ^4.2.1 - chalk: ^4.0.0 - emittery: ^0.13.1 - jest-util: ^29.5.0 - string-length: ^4.0.1 - checksum: 6a2e71e720183303913fc34fc24a3f87fca7fcfa638bc6c9109a4808b36251a1cb7fe98b956eb0d9c9ead1ad47c3dc3745289ee89e62c6c615168e92282069ca - languageName: node - linkType: hard - -"jest-watcher@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-watcher@npm:29.6.4" - dependencies: - "@jest/test-result": ^29.6.4 - "@jest/types": ^29.6.3 - "@types/node": "*" - ansi-escapes: ^4.2.1 - chalk: ^4.0.0 - emittery: ^0.13.1 - jest-util: ^29.6.3 - string-length: ^4.0.1 - checksum: a3f4e9b16353fd3e4ee19b71308324bf113d12d538bf4894a46a6a8dcbcea6f00c60b3f02ad0865f6cea9b44938b8c8f4aa05433e50d609b8285e8ebc20400cf - languageName: node - linkType: hard - "jest-watcher@npm:^29.7.0": version: 29.7.0 resolution: "jest-watcher@npm:29.7.0" @@ -29883,7 +22418,7 @@ __metadata: languageName: node linkType: hard -"jest-worker@npm:^26.2.1, jest-worker@npm:^26.5.0, jest-worker@npm:^26.6.2": +"jest-worker@npm:^26.2.1, jest-worker@npm:^26.6.2": version: 26.6.2 resolution: "jest-worker@npm:26.6.2" dependencies: @@ -29894,7 +22429,7 @@ __metadata: languageName: node linkType: hard -"jest-worker@npm:^27.4.5, jest-worker@npm:^27.5.1": +"jest-worker@npm:^27.5.1": version: 27.5.1 resolution: "jest-worker@npm:27.5.1" dependencies: @@ -29905,30 +22440,6 @@ __metadata: languageName: node linkType: hard -"jest-worker@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-worker@npm:29.5.0" - dependencies: - "@types/node": "*" - jest-util: ^29.5.0 - merge-stream: ^2.0.0 - supports-color: ^8.0.0 - checksum: 4191ec3209cb1d838c931d47c7328fec7279eb7a5d40fa86bb3fac4d34cbad835349bc366150712259a274507fd210ddb450733032394d8e0b19640b3d3ac17d - languageName: node - linkType: hard - -"jest-worker@npm:^29.6.4": - version: 29.6.4 - resolution: "jest-worker@npm:29.6.4" - dependencies: - "@types/node": "*" - jest-util: ^29.6.3 - merge-stream: ^2.0.0 - supports-color: ^8.0.0 - checksum: cbad6f05097555c805daa105eefe73352e0d37702cd87d4265b9383e76bf20e7ab1318e7d37f44c190ba104308bcfca5b41a9fce563a0473c99c86a9ba849f46 - languageName: node - linkType: hard - "jest-worker@npm:^29.7.0": version: 29.7.0 resolution: "jest-worker@npm:29.7.0" @@ -29985,7 +22496,7 @@ __metadata: languageName: node linkType: hard -"jest@npm:^29.1.0": +"jest@npm:^29.1.0, jest@npm:^29.6.3": version: 29.7.0 resolution: "jest@npm:29.7.0" dependencies: @@ -30004,63 +22515,7 @@ __metadata: languageName: node linkType: hard -"jest@npm:^29.4.1": - version: 29.5.0 - resolution: "jest@npm:29.5.0" - dependencies: - "@jest/core": ^29.5.0 - "@jest/types": ^29.5.0 - import-local: ^3.0.2 - jest-cli: ^29.5.0 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - bin: - jest: bin/jest.js - checksum: 32e29cfa2373530ed323ea65dfb4fd5172026349be48ebb7a2dc5660adadd1c68f6b0fe2b67cc3ee723cc34e2d4552a852730ac787251b406cf58e37a90f6dac - languageName: node - linkType: hard - -"jest@npm:^29.6.3": - version: 29.6.4 - resolution: "jest@npm:29.6.4" - dependencies: - "@jest/core": ^29.6.4 - "@jest/types": ^29.6.3 - import-local: ^3.0.2 - jest-cli: ^29.6.4 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - bin: - jest: bin/jest.js - checksum: 7f4519a30b2c58d116f118cc841dbf9558fb9c47ed3b651a8feef0e98fbc96ce5bd9b574ace9bbef9d31f1f5720f121065f2d0351416449a088f1d655517bf39 - languageName: node - linkType: hard - -"jiti@npm:^1.18.2": - version: 1.18.2 - resolution: "jiti@npm:1.18.2" - bin: - jiti: bin/jiti.js - checksum: 578343e883838a5d6775350925d9e1a647e00132ade9c8cc318c163b692988612472f0af3cd9d92b8d8ca61e623092e86ab89563cbf6394900a5a39962e3c4e8 - languageName: node - linkType: hard - -"jiti@npm:^1.19.1": - version: 1.20.0 - resolution: "jiti@npm:1.20.0" - bin: - jiti: bin/jiti.js - checksum: e71999db5e436d38c32ca713c3688b5da2a686f264584d927dcca80a4eaece83af7dd32c047524e74084bb11bdfa148f5f91b7e9a0044b4803feffe3c2c30dbc - languageName: node - linkType: hard - -"jiti@npm:^1.21.0": +"jiti@npm:^1.20.0, jiti@npm:^1.21.0": version: 1.21.0 resolution: "jiti@npm:1.21.0" bin: @@ -30069,7 +22524,14 @@ __metadata: languageName: node linkType: hard -"joi@npm:^17.11.0": +"jju@npm:~1.4.0": + version: 1.4.0 + resolution: "jju@npm:1.4.0" + checksum: f3f444557e4364cfc06b1abf8331bf3778b26c0c8552ca54429bc0092652172fdea26cbffe33e1017b303d5aa506f7ede8571857400efe459cb7439180e2acad + languageName: node + linkType: hard + +"joi@npm:^17.11.0, joi@npm:^17.6.4": version: 17.13.1 resolution: "joi@npm:17.13.1" dependencies: @@ -30082,19 +22544,6 @@ __metadata: languageName: node linkType: hard -"joi@npm:^17.6.4": - version: 17.12.0 - resolution: "joi@npm:17.12.0" - dependencies: - "@hapi/hoek": ^9.3.0 - "@hapi/topo": ^5.1.0 - "@sideway/address": ^4.1.4 - "@sideway/formula": ^3.0.1 - "@sideway/pinpoint": ^2.0.0 - checksum: 2378f4ec8de2bc12674ce3e6faac509f52ff4f734c67bf68c288816b20336d4e59433ea1c1e187f1009075c81ec5fa8b5061094feb37a855d6e3ee0cfcd79dd8 - languageName: node - linkType: hard - "joycon@npm:^3.0.1, joycon@npm:^3.1.1": version: 3.1.1 resolution: "joycon@npm:3.1.1" @@ -30109,13 +22558,6 @@ __metadata: languageName: node linkType: hard -"js-string-escape@npm:^1.0.1": - version: 1.0.1 - resolution: "js-string-escape@npm:1.0.1" - checksum: 2c33b9ff1ba6b84681c51ca0997e7d5a1639813c95d5b61cb7ad47e55cc28fa4a0b1935c3d218710d8e6bcee5d0cd8c44755231e3a4e45fc604534d9595a3628 - languageName: node - linkType: hard - "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -30146,6 +22588,13 @@ __metadata: languageName: node linkType: hard +"jsbn@npm:1.1.0": + version: 1.1.0 + resolution: "jsbn@npm:1.1.0" + checksum: 4f907fb78d7b712e11dea8c165fe0921f81a657d3443dde75359ed52eb2b5d33ce6773d97985a089f09a65edd80b11cb75c767b57ba47391fee4c969f7215c96 + languageName: node + linkType: hard + "jsbn@npm:~0.1.0": version: 0.1.1 resolution: "jsbn@npm:0.1.1" @@ -30153,19 +22602,20 @@ __metadata: languageName: node linkType: hard -"jscodeshift@npm:^0.14.0": - version: 0.14.0 - resolution: "jscodeshift@npm:0.14.0" +"jscodeshift@npm:^0.15.1": + version: 0.15.2 + resolution: "jscodeshift@npm:0.15.2" dependencies: - "@babel/core": ^7.13.16 - "@babel/parser": ^7.13.16 - "@babel/plugin-proposal-class-properties": ^7.13.0 - "@babel/plugin-proposal-nullish-coalescing-operator": ^7.13.8 - "@babel/plugin-proposal-optional-chaining": ^7.13.12 - "@babel/plugin-transform-modules-commonjs": ^7.13.8 - "@babel/preset-flow": ^7.13.13 - "@babel/preset-typescript": ^7.13.0 - "@babel/register": ^7.13.16 + "@babel/core": ^7.23.0 + "@babel/parser": ^7.23.0 + "@babel/plugin-transform-class-properties": ^7.22.5 + "@babel/plugin-transform-modules-commonjs": ^7.23.0 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.22.11 + "@babel/plugin-transform-optional-chaining": ^7.23.0 + "@babel/plugin-transform-private-methods": ^7.22.5 + "@babel/preset-flow": ^7.22.15 + "@babel/preset-typescript": ^7.23.0 + "@babel/register": ^7.22.15 babel-core: ^7.0.0-bridge.0 chalk: ^4.1.2 flow-parser: 0.* @@ -30173,14 +22623,17 @@ __metadata: micromatch: ^4.0.4 neo-async: ^2.5.0 node-dir: ^0.1.17 - recast: ^0.21.0 + recast: ^0.23.3 temp: ^0.8.4 write-file-atomic: ^2.3.0 peerDependencies: "@babel/preset-env": ^7.1.6 + peerDependenciesMeta: + "@babel/preset-env": + optional: true bin: jscodeshift: bin/jscodeshift.js - checksum: dab63bdb4b7e67d79634fcd3f5dc8b227146e9f68aa88700bc49c5a45b6339d05bd934a98aa53d29abd04f81237d010e7e037799471b2aab66ec7b9a7d752786 + checksum: 79afb059b9ca92712af02bdc8d6ff144de7aaf5e2cdcc6f6534e7a86a7347b0a278d9f4884f2c78dac424162a353aafff183a60e868f71132be2c5b5304aeeb8 languageName: node linkType: hard @@ -30363,14 +22816,7 @@ __metadata: languageName: node linkType: hard -"json-parse-better-errors@npm:^1.0.2": - version: 1.0.2 - resolution: "json-parse-better-errors@npm:1.0.2" - checksum: 2f1287a7c833e397c9ddd361a78638e828fc523038bb3441fd4fc144cfd2c6cd4963ffb9e207e648cf7b692600f1e1e524e965c32df5152120910e4903a47dcb - languageName: node - linkType: hard - -"json-parse-even-better-errors@npm:^2.3.0, json-parse-even-better-errors@npm:^2.3.1": +"json-parse-even-better-errors@npm:^2.3.0": version: 2.3.1 resolution: "json-parse-even-better-errors@npm:2.3.1" checksum: 140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 @@ -30449,21 +22895,10 @@ __metadata: languageName: node linkType: hard -"json5@npm:^1.0.1": - version: 1.0.2 - resolution: "json5@npm:1.0.2" - dependencies: - minimist: ^1.2.0 - bin: - json5: lib/cli.js - checksum: 9ee316bf21f000b00752e6c2a3b79ecf5324515a5c60ee88983a1910a45426b643a4f3461657586e8aeca87aaf96f0a519b0516d2ae527a6c3e7eed80f68717f - languageName: node - linkType: hard - "jsonc-parser@npm:^3.2.0": - version: 3.2.0 - resolution: "jsonc-parser@npm:3.2.0" - checksum: 5a12d4d04dad381852476872a29dcee03a57439574e4181d91dca71904fcdcc5e8e4706c0a68a2c61ad9810e1e1c5806b5100d52d3e727b78f5cdc595401045b + version: 3.2.1 + resolution: "jsonc-parser@npm:3.2.1" + checksum: ada66dec143d7f9cb0e2d0d29c69e9ce40d20f3a4cb96b0c6efb745025ac7f9ba647d7ac0990d0adfc37a2d2ae084a12009a9c833dbdbeadf648879a99b9df89 languageName: node linkType: hard @@ -30524,19 +22959,7 @@ __metadata: languageName: node linkType: hard -"jsonwebtoken@npm:^9.0.0": - version: 9.0.0 - resolution: "jsonwebtoken@npm:9.0.0" - dependencies: - jws: ^3.2.2 - lodash: ^4.17.21 - ms: ^2.1.1 - semver: ^7.3.8 - checksum: 60c30d90d8a69b8e7148306e0c299ac120dbde9c032add48d26df928fe349e952cf4b09f12d7942257681a936e3374e4d49280ab20f8a4578688c7f08d87f9bc - languageName: node - linkType: hard - -"jsonwebtoken@npm:^9.0.2": +"jsonwebtoken@npm:^9.0.0, jsonwebtoken@npm:^9.0.2": version: 9.0.2 resolution: "jsonwebtoken@npm:9.0.2" dependencies: @@ -30567,21 +22990,14 @@ __metadata: linkType: hard "jsx-ast-utils@npm:^2.4.1 || ^3.0.0": - version: 3.3.4 - resolution: "jsx-ast-utils@npm:3.3.4" + version: 3.3.5 + resolution: "jsx-ast-utils@npm:3.3.5" dependencies: array-includes: ^3.1.6 array.prototype.flat: ^1.3.1 object.assign: ^4.1.4 object.values: ^1.1.6 - checksum: 6761ccd830deab6a4cb8ca182c7b3627f4478138b6f4e2b680afc2b5e954635feb460ff75218b67f8694a9f8a0da6f0833a013e34961a16fbe4457fb34a0a7b2 - languageName: node - linkType: hard - -"junk@npm:^3.1.0": - version: 3.1.0 - resolution: "junk@npm:3.1.0" - checksum: 820174b9fa9a3af09aeeeeb1022df2481a2b10752ce5f65ac63924a79cb9bba83ea7c288e8d5b448951109742da5ea69a230846f4bf3c17c5c6a1d0603b63db4 + checksum: a32679e9cb55469cb6d8bbc863f7d631b2c98b7fc7bf172629261751a6e7bc8da6ae374ddb74d5fbd8b06cf0eb4572287b259813d92b36e384024ed35e4c13e1 languageName: node linkType: hard @@ -30615,7 +23031,7 @@ __metadata: languageName: node linkType: hard -"keyv@npm:^4.0.0": +"keyv@npm:^4.0.0, keyv@npm:^4.5.3": version: 4.5.4 resolution: "keyv@npm:4.5.4" dependencies: @@ -30642,13 +23058,6 @@ __metadata: languageName: node linkType: hard -"kind-of@npm:^5.0.0": - version: 5.1.0 - resolution: "kind-of@npm:5.1.0" - checksum: fe85b7a2ed4b4d5a12e16e01d00d5c336e1760842fe0da38283605b9880c984288935e87b13138909e4d23d2d197a1d492f7393c6638d2c0fab8a900c4fb0392 - languageName: node - linkType: hard - "kind-of@npm:^6.0.0, kind-of@npm:^6.0.2, kind-of@npm:^6.0.3": version: 6.0.3 resolution: "kind-of@npm:6.0.3" @@ -30677,13 +23086,6 @@ __metadata: languageName: node linkType: hard -"klona@npm:^2.0.4": - version: 2.0.6 - resolution: "klona@npm:2.0.6" - checksum: 94eed2c6c2ce99f409df9186a96340558897b3e62a85afdc1ee39103954d2ebe1c1c4e9fe2b0952771771fa96d70055ede8b27962a7021406374fdb695fd4d01 - languageName: node - linkType: hard - "knex@npm:2.4.2": version: 2.4.2 resolution: "knex@npm:2.4.2" @@ -30769,19 +23171,6 @@ __metadata: languageName: node linkType: hard -"lazy-universal-dotenv@npm:^3.0.1": - version: 3.0.1 - resolution: "lazy-universal-dotenv@npm:3.0.1" - dependencies: - "@babel/runtime": ^7.5.0 - app-root-dir: ^1.0.2 - core-js: ^3.0.4 - dotenv: ^8.0.0 - dotenv-expand: ^5.1.0 - checksum: d7cf054661bcafe63c61978856f9cfacc2fc694430939681da9729016082fc9c07e4c472e7755452b518234ada38925ec5ad582b0c1f9aae7a43c24f105fdba9 - languageName: node - linkType: hard - "lazy-universal-dotenv@npm:^4.0.0": version: 4.0.0 resolution: "lazy-universal-dotenv@npm:4.0.0" @@ -30794,12 +23183,12 @@ __metadata: linkType: hard "less-loader@npm:^11.1.0": - version: 11.1.3 - resolution: "less-loader@npm:11.1.3" + version: 11.1.4 + resolution: "less-loader@npm:11.1.4" peerDependencies: less: ^3.5.0 || ^4.0.0 webpack: ^5.0.0 - checksum: 120da1cda733b543a336281eac8a5a5d74bfa22f269d18605ee629e58659a7943f961d8057b1a47cf9d4d6665a79e5f5da686c8ea5a1afa98ff277f48399a6a4 + checksum: 28fd9f91734b2b8638645489c23fc2048e3d0817d55bba742604e45e9a9240cbbdf5712ee092b7163ab0923d3a051947c743d6062fc7628980bdd89b30000679 languageName: node linkType: hard @@ -30944,10 +23333,10 @@ __metadata: languageName: node linkType: hard -"libphonenumber-js@npm:^1.10.14": - version: 1.10.37 - resolution: "libphonenumber-js@npm:1.10.37" - checksum: 2ae78f4eb8d9d5a9ea4f28c3c5d22a60c409e58b3e2fe2883f0d75c1b667451030051e3681295c8b4dbfb58991696cc864dc04e98bc7210f4810a93e0847f0b0 +"libphonenumber-js@npm:^1.10.53": + version: 1.11.0 + resolution: "libphonenumber-js@npm:1.11.0" + checksum: c9230aa2353372dbe277768a4a2b74a10d241d6013d8133ea4260fab201e7ac2fb1751460f1d8660fff7a493eeaf208d9844ebea70d997cea70bd9a3fd78041d languageName: node linkType: hard @@ -30958,6 +23347,13 @@ __metadata: languageName: node linkType: hard +"lilconfig@npm:^3.0.0": + version: 3.1.1 + resolution: "lilconfig@npm:3.1.1" + checksum: 311b559794546894e3fe176663427326026c1c644145be9e8041c58e268aa9328799b8dfe7e4dd8c6a4ae305feae95a1c9e007db3569f35b42b6e1bc8274754c + languageName: node + linkType: hard + "line-counter@npm:^1.0.3": version: 1.1.0 resolution: "line-counter@npm:1.1.0" @@ -31017,19 +23413,6 @@ __metadata: languageName: node linkType: hard -"load-json-file@npm:^1.0.0": - version: 1.1.0 - resolution: "load-json-file@npm:1.1.0" - dependencies: - graceful-fs: ^4.1.2 - parse-json: ^2.2.0 - pify: ^2.0.0 - pinkie-promise: ^2.0.0 - strip-bom: ^2.0.0 - checksum: 2a5344c2d88643735a938fdca8582c0504e1c290577faa74f56b9cc187fa443832709a15f36e5771f779ec0878215a03abc8faf97ec57bb86092ceb7e0caef22 - languageName: node - linkType: hard - "load-tsconfig@npm:^0.2.3": version: 0.2.5 resolution: "load-tsconfig@npm:0.2.5" @@ -31049,32 +23432,7 @@ __metadata: languageName: node linkType: hard -"loader-runner@npm:^2.4.0": - version: 2.4.0 - resolution: "loader-runner@npm:2.4.0" - checksum: 1f723bd8318453c2d073d7befbf891ba6d2a02f22622688bf7d22e7ba527a0f9476c7fdfedc6bfa2b55c0389d9f406f3a5239ed1b33c9088d77cfed085086a1e - languageName: node - linkType: hard - -"loader-runner@npm:^4.2.0": - version: 4.3.0 - resolution: "loader-runner@npm:4.3.0" - checksum: a44d78aae0907a72f73966fe8b82d1439c8c485238bd5a864b1b9a2a3257832effa858790241e6b37876b5446a78889adf2fcc8dd897ce54c089ecc0a0ce0bf0 - languageName: node - linkType: hard - -"loader-utils@npm:^1.2.3": - version: 1.4.2 - resolution: "loader-utils@npm:1.4.2" - dependencies: - big.js: ^5.2.2 - emojis-list: ^3.0.0 - json5: ^1.0.1 - checksum: 2b726088b5526f7605615e3e28043ae9bbd2453f4a85898e1151f3c39dbf7a2b65d09f3996bc588d92ac7e717ded529d3e1ea3ea42c433393be84a58234a2f53 - languageName: node - linkType: hard - -"loader-utils@npm:^2.0.0, loader-utils@npm:^2.0.4": +"loader-utils@npm:^2.0.0": version: 2.0.4 resolution: "loader-utils@npm:2.0.4" dependencies: @@ -31143,13 +23501,6 @@ __metadata: languageName: node linkType: hard -"lodash.curry@npm:^4.0.1": - version: 4.1.1 - resolution: "lodash.curry@npm:4.1.1" - checksum: f0431947dc9236df879fc13eb40c31a2839c958bd0eaa39170a5758c25a7d85d461716a851ab45a175371950b283480615cdd4b07fb0dd1afff7a2914a90696f - languageName: node - linkType: hard - "lodash.debounce@npm:^4.0.8": version: 4.0.8 resolution: "lodash.debounce@npm:4.0.8" @@ -31164,10 +23515,10 @@ __metadata: languageName: node linkType: hard -"lodash.flow@npm:^3.3.0": - version: 3.5.0 - resolution: "lodash.flow@npm:3.5.0" - checksum: b3202ddbb79e5aab41719806d0d5ae969f64ae6b59e6bdaaecaa96ec68d6ba429e544017fe0e71ecf5b7ee3cea7b45d43c46b7d67ca159d6cca86fca76c61a31 +"lodash.get@npm:^4.4.2": + version: 4.4.2 + resolution: "lodash.get@npm:4.4.2" + checksum: 48f40d471a1654397ed41685495acb31498d5ed696185ac8973daef424a749ca0c7871bf7b665d5c14f5cc479394479e0307e781f61d5573831769593411be6e languageName: node linkType: hard @@ -31269,14 +23620,14 @@ __metadata: languageName: node linkType: hard -"lodash.uniq@npm:4.5.0, lodash.uniq@npm:^4.5.0": +"lodash.uniq@npm:^4.5.0": version: 4.5.0 resolution: "lodash.uniq@npm:4.5.0" checksum: 262d400bb0952f112162a320cc4a75dea4f66078b9e7e3075ffbc9c6aa30b3e9df3cf20e7da7d566105e1ccf7804e4fbd7d804eee0b53de05d83f16ffbf41c5e languageName: node linkType: hard -"lodash@npm:4.17.21, lodash@npm:4.x, lodash@npm:^4.17.11, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.7.0, lodash@npm:~4.17.21": +"lodash@npm:4.17.21, lodash@npm:4.x, lodash@npm:^4.17.11, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.21, lodash@npm:^4.7.0, lodash@npm:~4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c @@ -31316,16 +23667,16 @@ __metadata: linkType: hard "logform@npm:^2.3.2, logform@npm:^2.4.0": - version: 2.5.1 - resolution: "logform@npm:2.5.1" + version: 2.6.0 + resolution: "logform@npm:2.6.0" dependencies: - "@colors/colors": 1.5.0 + "@colors/colors": 1.6.0 "@types/triple-beam": ^1.3.2 fecha: ^4.2.0 ms: ^2.1.1 safe-stable-stringify: ^2.3.1 triple-beam: ^1.3.0 - checksum: d11c36b4c42063abc816fda2fd149cff9969a9943d42afd95ddd1426804980b4e92e24f2ea6a9916fd490224b1c97578734a37d3b40ce3a9418495ce52e8ef23 + checksum: 6e02f8617a03155b2fce451bacf777a2c01da16d32c4c745b3ec85be6c3f2602f2a4953a8bd096441cb4c42c447b52318541d6b6bc335dce903cb9ad77a1749f languageName: node linkType: hard @@ -31356,16 +23707,6 @@ __metadata: languageName: node linkType: hard -"loud-rejection@npm:^1.0.0": - version: 1.6.0 - resolution: "loud-rejection@npm:1.6.0" - dependencies: - currently-unhandled: ^0.4.1 - signal-exit: ^3.0.0 - checksum: aa060b3fe55ad96b97890f1b0a24bf81a2d612e397d6cc0374ce1cf7e021cd0247f0ddb68134499882d0843c2776371d5221b80b0b3beeca5133a6e7f27a3845 - languageName: node - linkType: hard - "loupe@npm:^2.3.6": version: 2.3.7 resolution: "loupe@npm:2.3.7" @@ -31391,6 +23732,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": + version: 10.2.2 + resolution: "lru-cache@npm:10.2.2" + checksum: 402d31094335851220d0b00985084288136136992979d0e015f0f1697e15d1c86052d7d53ae86b614e5b058425606efffc6969a31a091085d7a2b80a8a1e26d6 + languageName: node + linkType: hard + "lru-cache@npm:^4.0.1": version: 4.1.5 resolution: "lru-cache@npm:4.1.5" @@ -31419,20 +23767,6 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^7.7.1": - version: 7.18.3 - resolution: "lru-cache@npm:7.18.3" - checksum: b3a452b491433db885beed95041eb104c157ef7794b9c9b4d647be503be91769d11206bb573849a16b4cc0d03cbd15ffd22df7960997788b74c1d399ac7a4fed - languageName: node - linkType: hard - -"lru-cache@npm:^9.1.1 || ^10.0.0": - version: 10.0.0 - resolution: "lru-cache@npm:10.0.0" - checksum: 347b7b391091e9f91182b6f683ce04329932a542376a2d7d300637213b99f06c222a3bb0f0db59adf246dac6cef1bb509cab352451a96621d07c41b10a20495f - languageName: node - linkType: hard - "ltgt@npm:^2.1.2": version: 2.2.1 resolution: "ltgt@npm:2.2.1" @@ -31457,9 +23791,9 @@ __metadata: linkType: hard "luxon@npm:^3.2.1": - version: 3.3.0 - resolution: "luxon@npm:3.3.0" - checksum: 47f8e1e96b25441c799b8aa833b3f007fb1854713bcffc8c3384eda8e61fc9af1f038474d137274d2d386492f341c8a8c992fc78c213adfb3143780feba2776c + version: 3.4.4 + resolution: "luxon@npm:3.4.4" + checksum: 02e26a0b039c11fd5b75e1d734c8f0332c95510f6a514a9a0991023e43fb233884da02d7f966823ffb230632a733fc86d4a4b1e63c3fbe00058b8ee0f8c728af languageName: node linkType: hard @@ -31472,7 +23806,7 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:0.30.5, magic-string@npm:^0.30.0, magic-string@npm:^0.30.2, magic-string@npm:^0.30.3, magic-string@npm:~0.30.0": +"magic-string@npm:0.30.5": version: 0.30.5 resolution: "magic-string@npm:0.30.5" dependencies: @@ -31499,6 +23833,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^0.30.0, magic-string@npm:^0.30.2, magic-string@npm:^0.30.3, magic-string@npm:~0.30.0": + version: 0.30.10 + resolution: "magic-string@npm:0.30.10" + dependencies: + "@jridgewell/sourcemap-codec": ^1.4.15 + checksum: aa9ca17eae571a19bce92c8221193b6f93ee8511abb10f085e55ffd398db8e4c089a208d9eac559deee96a08b7b24d636ea4ab92f09c6cf42a7d1af51f7fd62b + languageName: node + linkType: hard + "make-dir@npm:^2.0.0, make-dir@npm:^2.1.0": version: 2.1.0 resolution: "make-dir@npm:2.1.0" @@ -31509,7 +23852,7 @@ __metadata: languageName: node linkType: hard -"make-dir@npm:^3.0.0, make-dir@npm:^3.0.2, make-dir@npm:^3.1.0": +"make-dir@npm:^3.0.0, make-dir@npm:^3.0.2": version: 3.1.0 resolution: "make-dir@npm:3.1.0" dependencies: @@ -31518,6 +23861,15 @@ __metadata: languageName: node linkType: hard +"make-dir@npm:^4.0.0": + version: 4.0.0 + resolution: "make-dir@npm:4.0.0" + dependencies: + semver: ^7.5.3 + checksum: 69b98a6c0b8e5c4fe9acb61608a9fbcfca1756d910f51e5dbe7a9e5cfb74fca9b8a0c8a0ffdf1294a740826c1ab4871d5bf3f62f72a3049e5eac6541ddffed68 + languageName: node + linkType: hard + "make-error@npm:1.x, make-error@npm:^1.1.1": version: 1.3.6 resolution: "make-error@npm:1.3.6" @@ -31525,26 +23877,23 @@ __metadata: languageName: node linkType: hard -"make-fetch-happen@npm:^11.0.3": - version: 11.1.1 - resolution: "make-fetch-happen@npm:11.1.1" +"make-fetch-happen@npm:^13.0.0": + version: 13.0.1 + resolution: "make-fetch-happen@npm:13.0.1" dependencies: - agentkeepalive: ^4.2.1 - cacache: ^17.0.0 + "@npmcli/agent": ^2.0.0 + cacache: ^18.0.0 http-cache-semantics: ^4.1.1 - http-proxy-agent: ^5.0.0 - https-proxy-agent: ^5.0.0 is-lambda: ^1.0.1 - lru-cache: ^7.7.1 - minipass: ^5.0.0 + minipass: ^7.0.2 minipass-fetch: ^3.0.0 minipass-flush: ^1.0.5 minipass-pipeline: ^1.2.4 negotiator: ^0.6.3 + proc-log: ^4.2.0 promise-retry: ^2.0.1 - socks-proxy-agent: ^7.0.0 ssri: ^10.0.0 - checksum: c161bde51dbc03382f9fac091734526a64dd6878205db6c338f70d2133df797b5b5166bff3091cf7d4785869d4b21e99a58139c1790c2fb1b5eec00f528f5f0b + checksum: df5f4dbb6d98153b751bccf4dc4cc500de85a96a9331db9805596c46aa9f99d9555983954e6c1266d9f981ae37a9e4647f42b9a4bb5466f867f4012e582c9e7e languageName: node linkType: hard @@ -31564,7 +23913,7 @@ __metadata: languageName: node linkType: hard -"map-obj@npm:^1.0.0, map-obj@npm:^1.0.1": +"map-obj@npm:^1.0.0": version: 1.0.1 resolution: "map-obj@npm:1.0.1" checksum: ccca88395e7d38671ed9f5652ecf471ecd546924be2fb900836b9da35e068a96687d96a5f93dcdfa94d9a27d649d2f10a84595590f89a347fb4dda47629dcc52 @@ -31601,19 +23950,12 @@ __metadata: languageName: node linkType: hard -"markdown-escapes@npm:^1.0.0": - version: 1.0.4 - resolution: "markdown-escapes@npm:1.0.4" - checksum: cf3f2231191d9df61cd1d02a50a55a5c89ab9cebfe75572950f4844b93a41d561eed2d82e42732d55f2c55fa0d426b51df3a7f378b4068ae1e2923bb758a9cc8 - languageName: node - linkType: hard - "markdown-to-jsx@npm:^7.1.8": - version: 7.3.2 - resolution: "markdown-to-jsx@npm:7.3.2" + version: 7.4.7 + resolution: "markdown-to-jsx@npm:7.4.7" peerDependencies: react: ">= 0.14.0" - checksum: 191b9a9defeed02e12dd340cebf279f577266dac7b34574fa44ce4d64ee8536f9967d455b8303c853f84413feb473118290a6160d8221eeaf3b9e4961b8980e3 + checksum: 7dab3e2c8d7374c45e6ca34fd12b40453533a5b89749eff3359975b1d296c553ff7675f56be7c9d1fb3b97b7b7d143d1b3237137d5c262322e0534eea72e2800 languageName: node linkType: hard @@ -31635,7 +23977,7 @@ __metadata: languageName: node linkType: hard -"marked@npm:^4.0.15": +"marked@npm:^4.3.0": version: 4.3.0 resolution: "marked@npm:4.3.0" bin: @@ -31673,26 +24015,6 @@ __metadata: languageName: node linkType: hard -"md5.js@npm:^1.3.4": - version: 1.3.5 - resolution: "md5.js@npm:1.3.5" - dependencies: - hash-base: ^3.0.0 - inherits: ^2.0.1 - safe-buffer: ^5.1.2 - checksum: b7bd75077f419c8e013fc4d4dada48be71882e37d69a44af65a2f2804b91e253441eb43a0614423a1c91bb830b8140b0dc906bc797245e2e275759584f4efcc5 - languageName: node - linkType: hard - -"mdast-squeeze-paragraphs@npm:^4.0.0": - version: 4.0.0 - resolution: "mdast-squeeze-paragraphs@npm:4.0.0" - dependencies: - unist-util-remove: ^2.0.0 - checksum: 0b44a85d7e6d98772b1dbb28a46a35c74c2791c6cf057bfd2e590a4e011d626627e5bf82d4497706f0dae03da02a63a9279aca17c4c23a9c7173792adba8e6fc - languageName: node - linkType: hard - "mdast-util-definitions@npm:^4.0.0": version: 4.0.0 resolution: "mdast-util-definitions@npm:4.0.0" @@ -31702,22 +24024,6 @@ __metadata: languageName: node linkType: hard -"mdast-util-to-hast@npm:10.0.1": - version: 10.0.1 - resolution: "mdast-util-to-hast@npm:10.0.1" - dependencies: - "@types/mdast": ^3.0.0 - "@types/unist": ^2.0.0 - mdast-util-definitions: ^4.0.0 - mdurl: ^1.0.0 - unist-builder: ^2.0.0 - unist-util-generated: ^1.0.0 - unist-util-position: ^3.0.0 - unist-util-visit: ^2.0.0 - checksum: 08d0977c60ee951cb5e2e84bc821a842da463c37f7bbb79abf0be0894120ed5e2fc1d003d072d3bb968d8e813a916e132a094166d5562deb424acc45e1c661f4 - languageName: node - linkType: hard - "mdast-util-to-string@npm:^1.0.0": version: 1.1.0 resolution: "mdast-util-to-string@npm:1.1.0" @@ -31746,13 +24052,6 @@ __metadata: languageName: node linkType: hard -"mdurl@npm:^1.0.0": - version: 1.0.1 - resolution: "mdurl@npm:1.0.1" - checksum: ea8534341eb002aaa532a722daef6074cd8ca66202e10a2b4cda46722c1ebdb1da92197ac300bc953d3ef1bf41cd6561ef2cc69d82d5d0237dae00d4a61a4eee - languageName: node - linkType: hard - "meant@npm:^1.0.3": version: 1.0.3 resolution: "meant@npm:1.0.3" @@ -31828,44 +24127,19 @@ __metadata: languageName: unknown linkType: soft -"medusa-react@workspace:^, medusa-react@workspace:packages/medusa-react": - version: 0.0.0-use.local - resolution: "medusa-react@workspace:packages/medusa-react" +"medusa-react@npm:latest": + version: 9.0.17 + resolution: "medusa-react@npm:9.0.17" dependencies: - "@babel/core": ^7.16.0 - "@medusajs/medusa": ^1.20.5 "@medusajs/medusa-js": "*" - "@storybook/addon-essentials": ^6.3.12 - "@storybook/addon-links": ^6.3.12 - "@storybook/addons": ^6.3.12 - "@storybook/react": ^6.3.12 - "@tanstack/react-query": 4.22.0 - "@testing-library/react": ^13.4.0 - "@testing-library/react-hooks": ^8.0.1 - "@types/jest": ^27.0.3 - "@types/react": ^17.0.53 - "@types/react-dom": ^17.0.18 - axios: ^0.24.0 - babel-loader: ^8.2.3 - cross-env: ^5.2.1 - jest: ^29.4.1 - jest-environment-jsdom: ^29.4.1 - msw: ^0.35.0 - msw-storybook-addon: ^1.5.0 - react: ^17.0.2 - react-dom: ^17.0.2 - react-is: ^17.0.2 - react-json-view: ^1.21.3 - ts-jest: ^29.0.5 - tslib: ^2.3.1 - tsup: 6.7.0 peerDependencies: "@medusajs/medusa": ^1.17.2 "@tanstack/react-query": ^4.22.0 react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 - languageName: unknown - linkType: soft + checksum: 8d262e79a08b3b08092bf4394d27ece953f02de3cadf00682f53f3e07c62f01d12b4df4aecbd925d12a319c3af321eabb31a97262a6589fe51ccef20ac064a38 + languageName: node + linkType: hard "medusa-telemetry@^0.0.17, medusa-telemetry@workspace:packages/medusa-telemetry": version: 0.0.0-use.local @@ -31930,15 +24204,6 @@ __metadata: languageName: unknown linkType: soft -"memfs@npm:^3.1.2": - version: 3.5.3 - resolution: "memfs@npm:3.5.3" - dependencies: - fs-monkey: ^1.0.4 - checksum: 038fc81bce17ea92dde15aaa68fa0fdaf4960c721ce3ffc7c2cb87a259333f5159784ea48b3b72bf9e054254d9d0d0d5209d0fdc3d07d08653a09933b168fbd7 - languageName: node - linkType: hard - "memoizerific@npm:^1.11.3": version: 1.11.3 resolution: "memoizerific@npm:1.11.3" @@ -31948,44 +24213,6 @@ __metadata: languageName: node linkType: hard -"memory-fs@npm:^0.4.1": - version: 0.4.1 - resolution: "memory-fs@npm:0.4.1" - dependencies: - errno: ^0.1.3 - readable-stream: ^2.0.1 - checksum: f114c44ad8285103cb0e71420cf5bb628d3eb6cbd918197f5951590ff56ba2072f4a97924949c170320cdf180d2da4e8d16a0edd92ba0ca2d2de51dc932841e2 - languageName: node - linkType: hard - -"memory-fs@npm:^0.5.0": - version: 0.5.0 - resolution: "memory-fs@npm:0.5.0" - dependencies: - errno: ^0.1.3 - readable-stream: ^2.0.1 - checksum: 2737a27b14a9e8b8cd757be2ad99e8cc504b78a78aba9d6aa18ff1ef528e2223a433413d2df6ab5332997a5a8ccf075e6c6e90e31ab732a55455ca620e4a720b - languageName: node - linkType: hard - -"meow@npm:^3.1.0": - version: 3.7.0 - resolution: "meow@npm:3.7.0" - dependencies: - camelcase-keys: ^2.0.0 - decamelize: ^1.1.2 - loud-rejection: ^1.0.0 - map-obj: ^1.0.1 - minimist: ^1.1.3 - normalize-package-data: ^2.3.4 - object-assign: ^4.0.1 - read-pkg-up: ^1.0.1 - redent: ^1.0.0 - trim-newlines: ^1.0.0 - checksum: e5ba4632b6558006b5f4df64b5a35e777d75629ab08d84f7bbc967e7603a396e16baa8f67aae26c7833a6a117e4857afef393e0b9aee21f52320e54812d9ae09 - languageName: node - linkType: hard - "meow@npm:^6.0.0": version: 6.1.1 resolution: "meow@npm:6.1.1" @@ -32019,7 +24246,7 @@ __metadata: languageName: node linkType: hard -"merge2@npm:^1.2.3, merge2@npm:^1.3.0, merge2@npm:^1.4.1": +"merge2@npm:^1.3.0, merge2@npm:^1.4.1": version: 1.4.1 resolution: "merge2@npm:1.4.1" checksum: 254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb @@ -32083,13 +24310,6 @@ __metadata: languageName: node linkType: hard -"microevent.ts@npm:~0.1.1": - version: 0.1.1 - resolution: "microevent.ts@npm:0.1.1" - checksum: 1f18f23ebebf155d3f480b1414cec7667a477a09ced2c60705b204cfaba82cbecc76169d890b9a675f237cb1a5497ba744ca8619a65802ac6765148a05bb6bf4 - languageName: node - linkType: hard - "micromatch@npm:4.x, micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": version: 4.0.5 resolution: "micromatch@npm:4.0.5" @@ -32128,18 +24348,6 @@ __metadata: languageName: node linkType: hard -"miller-rabin@npm:^4.0.0": - version: 4.0.1 - resolution: "miller-rabin@npm:4.0.1" - dependencies: - bn.js: ^4.0.0 - brorand: ^1.0.1 - bin: - miller-rabin: bin/miller-rabin - checksum: 26b2b96f6e49dbcff7faebb78708ed2f5f9ae27ac8cbbf1d7c08f83cf39bed3d418c0c11034dce997da70d135cc0ff6f3a4c15dc452f8e114c11986388a64346 - languageName: node - linkType: hard - "mime-db@npm:1.52.0, mime-db@npm:>= 1.43.0 < 2": version: 1.52.0 resolution: "mime-db@npm:1.52.0" @@ -32147,7 +24355,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^2.1.12, mime-types@npm:^2.1.25, mime-types@npm:^2.1.27, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-types@npm:^2.1.12, mime-types@npm:^2.1.25, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -32174,7 +24382,7 @@ __metadata: languageName: node linkType: hard -"mime@npm:^2.0.3, mime@npm:^2.4.4": +"mime@npm:^2.0.3": version: 2.6.0 resolution: "mime@npm:2.6.0" bin: @@ -32236,20 +24444,6 @@ __metadata: languageName: node linkType: hard -"minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1": - version: 1.0.1 - resolution: "minimalistic-assert@npm:1.0.1" - checksum: 96730e5601cd31457f81a296f521eb56036e6f69133c0b18c13fe941109d53ad23a4204d946a0d638d7f3099482a0cec8c9bb6d642604612ce43ee536be3dddd - languageName: node - linkType: hard - -"minimalistic-crypto-utils@npm:^1.0.1": - version: 1.0.1 - resolution: "minimalistic-crypto-utils@npm:1.0.1" - checksum: 790ecec8c5c73973a4fbf2c663d911033e8494d5fb0960a4500634766ab05d6107d20af896ca2132e7031741f19888154d44b2408ada0852446705441383e9f8 - languageName: node - linkType: hard - "minimatch@npm:2 || 3, minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -32287,11 +24481,11 @@ __metadata: linkType: hard "minimatch@npm:^9.0.1": - version: 9.0.2 - resolution: "minimatch@npm:9.0.2" + version: 9.0.4 + resolution: "minimatch@npm:9.0.4" dependencies: brace-expansion: ^2.0.1 - checksum: 39157d5fd831a7981f7c0c5b22a0e0c2ae8a987ec4a4aeaacc21d3e85da24ce812808cbf7c07cde0d63ad1cf307f73be581131a7a84eeda65f00be1f51972471 + checksum: 2c16f21f50e64922864e560ff97c587d15fd491f65d92a677a344e970fe62aafdbeafe648965fa96d33c061b4d0eabfe0213466203dd793367e7f28658cf6414 languageName: node linkType: hard @@ -32306,34 +24500,34 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.1.1, minimist@npm:^1.1.3, minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.8": +"minimist@npm:^1.1.1, minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.8": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 languageName: node linkType: hard -"minipass-collect@npm:^1.0.2": - version: 1.0.2 - resolution: "minipass-collect@npm:1.0.2" +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" dependencies: - minipass: ^3.0.0 - checksum: 8f82bd1f3095b24f53a991b04b67f4c710c894e518b813f0864a31de5570441a509be1ca17e0bb92b047591a8fdbeb886f502764fefb00d2f144f4011791e898 + minipass: ^7.0.3 + checksum: 5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e languageName: node linkType: hard "minipass-fetch@npm:^3.0.0": - version: 3.0.3 - resolution: "minipass-fetch@npm:3.0.3" + version: 3.0.5 + resolution: "minipass-fetch@npm:3.0.5" dependencies: encoding: ^0.1.13 - minipass: ^5.0.0 + minipass: ^7.0.3 minipass-sized: ^1.0.3 minizlib: ^2.1.2 dependenciesMeta: encoding: optional: true - checksum: 12e0fde7e8fdb1bd923b9243b4788e7d3df305c6ddb3b79ab2da4587fa608c126157c7f6dd43746e8063ee99ec5abbb898d0426c812e9c9b68260c4fea9b279a + checksum: 9d702d57f556274286fdd97e406fc38a2f5c8d15e158b498d7393b1105974b21249289ec571fa2b51e038a4872bfc82710111cf75fae98c662f3d6f95e72152b languageName: node linkType: hard @@ -32346,7 +24540,7 @@ __metadata: languageName: node linkType: hard -"minipass-pipeline@npm:^1.2.2, minipass-pipeline@npm:^1.2.4": +"minipass-pipeline@npm:^1.2.4": version: 1.2.4 resolution: "minipass-pipeline@npm:1.2.4" dependencies: @@ -32364,7 +24558,7 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^3.0.0, minipass@npm:^3.1.1": +"minipass@npm:^3.0.0": version: 3.3.6 resolution: "minipass@npm:3.3.6" dependencies: @@ -32380,17 +24574,10 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2": - version: 6.0.2 - resolution: "minipass@npm:6.0.2" - checksum: 3878076578f44ef4078ceed10af2cfebbec1b6217bf9f7a3d8b940da8153769db29bf88498b2de0d1e0c12dfb7b634c5729b7ca03457f46435e801578add210a - languageName: node - linkType: hard - -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0": - version: 7.0.3 - resolution: "minipass@npm:7.0.3" - checksum: c85426bce6310368218aad1f20b8f242180b6c2058209c78840959d6fff8a4738076a3224c3a6b651080f95684d559be1bdb084939bc40011c653ec4552cf06e +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4": + version: 7.1.0 + resolution: "minipass@npm:7.1.0" + checksum: 6861c6ec9dc3cb99c745b287d92b2a8f409951852940205b4bb106faceb790544288622a0db7aa152f37793e2fc8f303628787883d9a679f2126605204feb97f languageName: node linkType: hard @@ -32404,24 +24591,6 @@ __metadata: languageName: node linkType: hard -"mississippi@npm:^3.0.0": - version: 3.0.0 - resolution: "mississippi@npm:3.0.0" - dependencies: - concat-stream: ^1.5.0 - duplexify: ^3.4.2 - end-of-stream: ^1.1.0 - flush-write-stream: ^1.0.0 - from2: ^2.1.0 - parallel-transform: ^1.1.0 - pump: ^3.0.0 - pumpify: ^1.3.3 - stream-each: ^1.1.0 - through2: ^2.0.0 - checksum: 97424a331ce1b9f789a0d3fa47d725dad9adfe5e0ead8bc458ba9fb51c4d2630df6b0966ca9dcbb4c90db48737d58126cbf0e3c170697bf41c265606efa91103 - languageName: node - linkType: hard - "mixin-deep@npm:^1.2.0": version: 1.3.2 resolution: "mixin-deep@npm:1.3.2" @@ -32433,9 +24602,9 @@ __metadata: linkType: hard "mixme@npm:^0.5.1": - version: 0.5.9 - resolution: "mixme@npm:0.5.9" - checksum: 7b30eb0120c1ec1cd01be496760cfad7ad0e408df674eaf87e716c3607a74f2a473c93f97eec71a01f878aaf924f351257d950521830de36e51263943c7420e4 + version: 0.5.10 + resolution: "mixme@npm:0.5.10" + checksum: 409b2124b75b5f489b1521bc470f6201d748499bf656db0aa43a07e654449f3bcc8a0277cd05ca3c3e305281a5934b6e75219866200b70a9e3e105f9cf08baf1 languageName: node linkType: hard @@ -32457,7 +24626,7 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:0.x, mkdirp@npm:^0.5.1, mkdirp@npm:^0.5.3, mkdirp@npm:^0.5.4, mkdirp@npm:~0.5.1": +"mkdirp@npm:0.x, mkdirp@npm:^0.5.4, mkdirp@npm:~0.5.1": version: 0.5.6 resolution: "mkdirp@npm:0.5.6" dependencies: @@ -32468,7 +24637,7 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:1.x, mkdirp@npm:^1.0.3, mkdirp@npm:^1.0.4": +"mkdirp@npm:1.x, mkdirp@npm:^1.0.3": version: 1.0.4 resolution: "mkdirp@npm:1.0.4" bin: @@ -32495,15 +24664,15 @@ __metadata: languageName: node linkType: hard -"mlly@npm:^1.2.0, mlly@npm:^1.4.0": - version: 1.4.2 - resolution: "mlly@npm:1.4.2" +"mlly@npm:^1.4.0, mlly@npm:^1.6.1": + version: 1.7.0 + resolution: "mlly@npm:1.7.0" dependencies: - acorn: ^8.10.0 - pathe: ^1.1.1 - pkg-types: ^1.0.3 - ufo: ^1.3.0 - checksum: 905e3a704c7d3bcaad55f31d6efe9f680eab5be053ab7f8b299b8dbc027041f741fa6a93db9a3c461be2552632f3831b6c43c50af530f5fb2e9cd6273bc9d642 + acorn: ^8.11.3 + pathe: ^1.1.2 + pkg-types: ^1.1.0 + ufo: ^1.5.3 + checksum: 0b90e5b86e35897fd830624635b30052d0dfeb01b62a021fff4c0a5f46fbc617db685acfbc8c1c7cdcf687d9ffb8d54f3c1b0087ab953232cb3c158a2fb2d770 languageName: node linkType: hard @@ -32540,26 +24709,19 @@ __metadata: linkType: hard "mobx@npm:^6.0.4": - version: 6.12.0 - resolution: "mobx@npm:6.12.0" - checksum: 18226d1120b0b21faf142c812f5e9dc670b03a3ad3fb868b9aeb9dffb72b7f0866591e50c3d07b79b01bdd4ca264b9843fb996a980b8bcb59f5a53597a8a2b90 + version: 6.12.3 + resolution: "mobx@npm:6.12.3" + checksum: 33e1d27d33adea0ceb4de32eb66b4384e81a249be5e01baa6bf556f458fd62a83d23bfa0cf8ba9e87c28f0d810ae301ee0e7322fd48a3bf47db33ffb08d5826c languageName: node linkType: hard -"moment@npm:^2.19.3": +"moment@npm:^2.19.3, moment@npm:~2.30.1": version: 2.30.1 resolution: "moment@npm:2.30.1" checksum: 865e4279418c6de666fca7786607705fd0189d8a7b7624e2e56be99290ac846f90878a6f602e34b4e0455c549b85385b1baf9966845962b313699e7cb847543a languageName: node linkType: hard -"moment@npm:~2.29.3": - version: 2.29.4 - resolution: "moment@npm:2.29.4" - checksum: 844c6f3ce42862ac9467c8ca4f5e48a00750078682cc5bda1bc0e50cc7ca88e2115a0f932d65a06e4a90e26cb78892be9b3ca3dd6546ca2c4d994cebb787fc2b - languageName: node - linkType: hard - "morgan@npm:^1.9.1": version: 1.10.0 resolution: "morgan@npm:1.10.0" @@ -32573,21 +24735,7 @@ __metadata: languageName: node linkType: hard -"move-concurrently@npm:^1.0.1": - version: 1.0.1 - resolution: "move-concurrently@npm:1.0.1" - dependencies: - aproba: ^1.1.1 - copy-concurrently: ^1.0.0 - fs-write-stream-atomic: ^1.0.8 - mkdirp: ^0.5.1 - rimraf: ^2.5.4 - run-queue: ^1.0.3 - checksum: 0fe81acf3bbbc322013c2f4ee4a48cf8d180a7d925fb9284c0f1f444e862d7eb0421ee074b68d35357a12f0d5e94a322049dc9da480672331b5b8895743eb66a - languageName: node - linkType: hard - -"mri@npm:^1.1.0, mri@npm:^1.2.0": +"mri@npm:^1.1.0": version: 1.2.0 resolution: "mri@npm:1.2.0" checksum: a3d32379c2554cf7351db6237ddc18dc9e54e4214953f3da105b97dc3babe0deb3ffe99cf409b38ea47cc29f9430561ba6b53b24ab8f9ce97a4b50409e4a50e7 @@ -32615,7 +24763,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:2.1.3, ms@npm:^2.0.0, ms@npm:^2.1.1": +"ms@npm:2.1.3, ms@npm:^2.1.1": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 @@ -32665,47 +24813,6 @@ __metadata: languageName: node linkType: hard -"msw-storybook-addon@npm:^1.5.0": - version: 1.8.0 - resolution: "msw-storybook-addon@npm:1.8.0" - dependencies: - is-node-process: ^1.0.1 - peerDependencies: - msw: ">=0.35.0 <2.0.0" - checksum: 8ccfbaa55edd857587ba07afb0eade25b7acf0b606c31d4cae6f4160251cfc3e77902bfcd3485690e8abb2dfeded5b41c63c5b71c46c1a6351ff90f99e4072e5 - languageName: node - linkType: hard - -"msw@npm:^0.35.0": - version: 0.35.0 - resolution: "msw@npm:0.35.0" - dependencies: - "@mswjs/cookies": ^0.1.6 - "@mswjs/interceptors": ^0.12.6 - "@open-draft/until": ^1.0.3 - "@types/cookie": ^0.4.1 - "@types/inquirer": ^7.3.3 - "@types/js-levenshtein": ^1.1.0 - chalk: ^4.1.1 - chokidar: ^3.4.2 - cookie: ^0.4.1 - graphql: ^15.5.1 - headers-utils: ^3.0.2 - inquirer: ^8.1.1 - is-node-process: ^1.0.1 - js-levenshtein: ^1.1.6 - node-fetch: ^2.6.1 - node-match-path: ^0.6.3 - statuses: ^2.0.0 - strict-event-emitter: ^0.2.0 - type-fest: ^1.2.2 - yargs: ^17.0.1 - bin: - msw: cli/index.js - checksum: b6cdb147ce27075f2b48eddc5bf09f5d2ce179a7db306178006adfb6cc09addac337f0ee7808db84f21c3d0a0da047c10bb93ec4590cb654d2e62737405c99fe - languageName: node - linkType: hard - "multer@npm:^1.4.5-lts.1": version: 1.4.5-lts.1 resolution: "multer@npm:1.4.5-lts.1" @@ -32776,15 +24883,6 @@ __metadata: languageName: node linkType: hard -"nan@npm:^2.12.1": - version: 2.17.0 - resolution: "nan@npm:2.17.0" - dependencies: - node-gyp: latest - checksum: 4a231a62dba025f4c4fa814c1e6ffeb450c5cd0852b780f19fe4ea22b86ba0f1f394406dfd628c67fb7f0987e982fa230da1fbd3632258f927b8defd7046c1ad - languageName: node - linkType: hard - "nan@npm:^2.14.0": version: 2.19.0 resolution: "nan@npm:2.19.0" @@ -32794,16 +24892,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.1, nanoid@npm:^3.3.6": - version: 3.3.6 - resolution: "nanoid@npm:3.3.6" - bin: - nanoid: bin/nanoid.cjs - checksum: 606b355960d0fcbe3d27924c4c52ef7d47d3b57208808ece73279420d91469b01ec1dce10fae512b6d4a8c5a5432b352b228336a8b2202a6ea68e67fa348e2ee - languageName: node - linkType: hard - -"nanoid@npm:^3.3.7": +"nanoid@npm:^3.3.6, nanoid@npm:^3.3.7": version: 3.3.7 resolution: "nanoid@npm:3.3.7" bin: @@ -32877,20 +24966,13 @@ __metadata: languageName: node linkType: hard -"neo-async@npm:^2.5.0, neo-async@npm:^2.6.0, neo-async@npm:^2.6.1, neo-async@npm:^2.6.2": +"neo-async@npm:^2.5.0, neo-async@npm:^2.6.0, neo-async@npm:^2.6.2": version: 2.6.2 resolution: "neo-async@npm:2.6.2" checksum: c2f5a604a54a8ec5438a342e1f356dff4bc33ccccdb6dc668d94fe8e5eccfc9d2c2eea6064b0967a767ba63b33763f51ccf2cd2441b461a7322656c1f06b3f5d languageName: node linkType: hard -"nested-error-stacks@npm:^2.0.0, nested-error-stacks@npm:^2.1.0": - version: 2.1.1 - resolution: "nested-error-stacks@npm:2.1.1" - checksum: feec00417e4778661cfbbe657e6add6ca9918dcc026cd697ac330b4a56a79e4882b36dde8abc138167566b1ce4c5baa17d2d4df727a96f8b96aebace1c3ffca7 - languageName: node - linkType: hard - "nice-try@npm:^1.0.4": version: 1.0.5 resolution: "nice-try@npm:1.0.5" @@ -32915,7 +24997,7 @@ __metadata: languageName: node linkType: hard -"node-dir@npm:^0.1.10, node-dir@npm:^0.1.17": +"node-dir@npm:^0.1.17": version: 0.1.17 resolution: "node-dir@npm:0.1.17" dependencies: @@ -32962,10 +25044,10 @@ __metadata: languageName: node linkType: hard -"node-fetch-native@npm:^1.4.0": - version: 1.4.0 - resolution: "node-fetch-native@npm:1.4.0" - checksum: 2ced63b4b4cef8d05e004c5489614811ae836ae17a07e548af7a29fb22c5ea2512ea24423720f1ac9b47787d701044321d4921e3da4fe8dbcc882a8f67a1d218 +"node-fetch-native@npm:^1.6.3": + version: 1.6.4 + resolution: "node-fetch-native@npm:1.6.4" + checksum: 78334dc6def5d1d95cfe87b33ac76c4833592c5eb84779ad2b0c23c689f9dd5d1cfc827035ada72d6b8b218f717798968c5a99aeff0a1a8bf06657e80592f9c3 languageName: node linkType: hard @@ -32983,7 +25065,7 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.0.0": +"node-fetch@npm:^2.0.0, node-fetch@npm:^2.5.0, node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.12": version: 2.7.0 resolution: "node-fetch@npm:2.7.0" dependencies: @@ -32997,20 +25079,6 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.5.0, node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.12, node-fetch@npm:^2.6.7": - version: 2.6.12 - resolution: "node-fetch@npm:2.6.12" - dependencies: - whatwg-url: ^5.0.0 - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - checksum: 10372e4b5ee07acadc15e6b2bc6fd8940582eea7b9b2a331f4e3665fdcd968498c1656f79f2fa572080ebb37ea80e1474a6478b3b36057ef901b63f4be8fd899 - languageName: node - linkType: hard - "node-fetch@npm:^3.3.1": version: 3.3.2 resolution: "node-fetch@npm:3.3.2" @@ -33045,23 +25113,22 @@ __metadata: linkType: hard "node-gyp@npm:latest": - version: 9.4.0 - resolution: "node-gyp@npm:9.4.0" + version: 10.1.0 + resolution: "node-gyp@npm:10.1.0" dependencies: env-paths: ^2.2.0 exponential-backoff: ^3.1.1 - glob: ^7.1.4 + glob: ^10.3.10 graceful-fs: ^4.2.6 - make-fetch-happen: ^11.0.3 - nopt: ^6.0.0 - npmlog: ^6.0.0 - rimraf: ^3.0.2 + make-fetch-happen: ^13.0.0 + nopt: ^7.0.0 + proc-log: ^3.0.0 semver: ^7.3.5 tar: ^6.1.2 - which: ^2.0.2 + which: ^4.0.0 bin: node-gyp: bin/node-gyp.js - checksum: e8dfbe2b02f23d056f69e01c409381963e92c71cafba6c9cfbf63b038f65ca19ab8183bb6891d080e59c4eb2cc425fc736f42e90afc0f0030ecd97bfc64fb7ad + checksum: 9cc821111ca244a01fb7f054db7523ab0a0cd837f665267eb962eb87695d71fb1e681f9e21464cc2fd7c05530dc4c81b810bca1a88f7d7186909b74477491a3c languageName: node linkType: hard @@ -33072,44 +25139,6 @@ __metadata: languageName: node linkType: hard -"node-libs-browser@npm:^2.2.1": - version: 2.2.1 - resolution: "node-libs-browser@npm:2.2.1" - dependencies: - assert: ^1.1.1 - browserify-zlib: ^0.2.0 - buffer: ^4.3.0 - console-browserify: ^1.1.0 - constants-browserify: ^1.0.0 - crypto-browserify: ^3.11.0 - domain-browser: ^1.1.1 - events: ^3.0.0 - https-browserify: ^1.0.0 - os-browserify: ^0.3.0 - path-browserify: 0.0.1 - process: ^0.11.10 - punycode: ^1.2.4 - querystring-es3: ^0.2.0 - readable-stream: ^2.3.3 - stream-browserify: ^2.0.1 - stream-http: ^2.7.2 - string_decoder: ^1.0.0 - timers-browserify: ^2.0.4 - tty-browserify: 0.0.0 - url: ^0.11.0 - util: ^0.11.0 - vm-browserify: ^1.0.1 - checksum: 0e05321a6396408903ed642231d2bca7dd96492d074c7af161ba06a63c95378bd3de50b4105eccbbc02d93ba3da69f0ff5e624bc2a8c92ca462ceb6a403e7986 - languageName: node - linkType: hard - -"node-match-path@npm:^0.6.3": - version: 0.6.3 - resolution: "node-match-path@npm:0.6.3" - checksum: b2e6a084f32e3cd97e600f792a46da6e68fbcf77ebad6c13ccca9eceb030f4961c358cfca26e4532e48e98779ca9a83edd2b6d7ba216c1a06961d435b1b05f9b - languageName: node - linkType: hard - "node-notifier@npm:^6.0.0": version: 6.0.0 resolution: "node-notifier@npm:6.0.0" @@ -33146,20 +25175,6 @@ __metadata: languageName: node linkType: hard -"node-releases@npm:^2.0.12": - version: 2.0.12 - resolution: "node-releases@npm:2.0.12" - checksum: 01f9a7c135be5c8bc989b6c10b9840a7aee09040d46ba4e64b5ea0174fb8891f1277514aef75033ce42031f6cb72a04d4a7e99c70ca25488ad63ad6fc5a5b6a0 - languageName: node - linkType: hard - -"node-releases@npm:^2.0.13": - version: 2.0.13 - resolution: "node-releases@npm:2.0.13" - checksum: 2fb44bf70fc949d27f3a48a7fd1a9d1d603ddad4ccd091f26b3fb8b1da976605d919330d7388ccd55ca2ade0dc8b2e12841ba19ef249c8bb29bf82532d401af7 - languageName: node - linkType: hard - "node-releases@npm:^2.0.14": version: 2.0.14 resolution: "node-releases@npm:2.0.14" @@ -33198,14 +25213,14 @@ __metadata: languageName: node linkType: hard -"nopt@npm:^6.0.0": - version: 6.0.0 - resolution: "nopt@npm:6.0.0" +"nopt@npm:^7.0.0": + version: 7.2.1 + resolution: "nopt@npm:7.2.1" dependencies: - abbrev: ^1.0.0 + abbrev: ^2.0.0 bin: nopt: bin/nopt.js - checksum: 837b52c330df16fcaad816b1f54fec6b2854ab1aa771d935c1603fbcf9b023bb073f1466b1b67f48ea4dce127ae675b85b9d9355700e9b109de39db490919786 + checksum: a069c7c736767121242037a22a788863accfa932ab285a1eb569eb8cd534b09d17206f68c37f096ae785647435e0c5a5a0a67b42ec743e481a455e5ae6a6df81 languageName: node linkType: hard @@ -33220,7 +25235,7 @@ __metadata: languageName: node linkType: hard -"normalize-package-data@npm:^2.3.2, normalize-package-data@npm:^2.3.4, normalize-package-data@npm:^2.5.0": +"normalize-package-data@npm:^2.5.0": version: 2.5.0 resolution: "normalize-package-data@npm:2.5.0" dependencies: @@ -33289,30 +25304,6 @@ __metadata: languageName: node linkType: hard -"npmlog@npm:^5.0.1": - version: 5.0.1 - resolution: "npmlog@npm:5.0.1" - dependencies: - are-we-there-yet: ^2.0.0 - console-control-strings: ^1.1.0 - gauge: ^3.0.0 - set-blocking: ^2.0.0 - checksum: 489ba519031013001135c463406f55491a17fc7da295c18a04937fe3a4d523fd65e88dd418a28b967ab743d913fdeba1e29838ce0ad8c75557057c481f7d49fa - languageName: node - linkType: hard - -"npmlog@npm:^6.0.0": - version: 6.0.2 - resolution: "npmlog@npm:6.0.2" - dependencies: - are-we-there-yet: ^3.0.0 - console-control-strings: ^1.1.0 - gauge: ^4.0.3 - set-blocking: ^2.0.0 - checksum: 0cacedfbc2f6139c746d9cd4a85f62718435ad0ca4a2d6459cd331dd33ae58206e91a0742c1558634efcde3f33f8e8e7fd3adf1bfe7978310cf00bd55cccf890 - languageName: node - linkType: hard - "nth-check@npm:^2.0.1": version: 2.1.1 resolution: "nth-check@npm:2.1.1" @@ -33322,13 +25313,6 @@ __metadata: languageName: node linkType: hard -"num2fraction@npm:^1.2.2": - version: 1.2.2 - resolution: "num2fraction@npm:1.2.2" - checksum: 3bf17b44af00508a2b0370146629710645c3e3ff3c052893680efe3f4a6ff5c953ce9e54734013b02b35744a49352d54fbc5d8b455fac979047ef17dd8ec74bd - languageName: node - linkType: hard - "number-is-nan@npm:^1.0.0": version: 1.0.1 resolution: "number-is-nan@npm:1.0.1" @@ -33336,17 +25320,25 @@ __metadata: languageName: node linkType: hard -"nwsapi@npm:^2.2.0, nwsapi@npm:^2.2.2": - version: 2.2.5 - resolution: "nwsapi@npm:2.2.5" - checksum: bc1cffd006ac9648085b89550be6083cdde7d7d4bd93139d4f1d7183c8cc6ca8878d8274c9f00456fd02701928d14df4f4ab2ff5422f172b9e9c1fa845dd49ce +"nwsapi@npm:^2.2.0, nwsapi@npm:^2.2.2, nwsapi@npm:^2.2.4": + version: 2.2.9 + resolution: "nwsapi@npm:2.2.9" + checksum: e6ebbaedf44d1c1e13f7193e5129c8da1b2e8064862b70458ab9bd9e9640b8ad035a0e48d509e787527ecdddea74d5a02798420cd971264a4e03c2b173fadac8 languageName: node linkType: hard -"nwsapi@npm:^2.2.4": - version: 2.2.7 - resolution: "nwsapi@npm:2.2.7" - checksum: 44be198adae99208487a1c886c0a3712264f7bbafa44368ad96c003512fed2753d4e22890ca1e6edb2690c3456a169f2a3c33bfacde1905cf3bf01c7722464db +"nypm@npm:^0.3.8": + version: 0.3.8 + resolution: "nypm@npm:0.3.8" + dependencies: + citty: ^0.1.6 + consola: ^3.2.3 + execa: ^8.0.1 + pathe: ^1.1.2 + ufo: ^1.4.0 + bin: + nypm: dist/cli.mjs + checksum: b910ad4f2156789e410443cb20e9e604baf9570dd54acc740bd3a7784cb6e96d4a2619c4e6ad2bea28a3f849acafbf4a8bdc9b9e52bd87379a5bd68e3b66400d languageName: node linkType: hard @@ -33440,13 +25432,6 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.12.3, object-inspect@npm:^1.9.0": - version: 1.12.3 - resolution: "object-inspect@npm:1.12.3" - checksum: 752bb5f4dc595e214157ea8f442adb77bdb850ace762b078d151d8b6486331ab12364997a89ee6509be1023b15adf2b3774437a7105f8a5043dfda11ed622411 - languageName: node - linkType: hard - "object-inspect@npm:^1.13.1": version: 1.13.1 resolution: "object-inspect@npm:1.13.1" @@ -33455,12 +25440,12 @@ __metadata: linkType: hard "object-is@npm:^1.1.5": - version: 1.1.5 - resolution: "object-is@npm:1.1.5" + version: 1.1.6 + resolution: "object-is@npm:1.1.6" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - checksum: 8c263fb03fc28f1ffb54b44b9147235c5e233dc1ca23768e7d2569740b5d860154d7cc29a30220fe28ed6d8008e2422aefdebfe987c103e1c5d190cf02d9d886 + call-bind: ^1.0.7 + define-properties: ^1.2.1 + checksum: 506af444c4dce7f8e31f34fc549e2fb8152d6b9c4a30c6e62852badd7f520b579c679af433e7a072f9d78eb7808d230dc12e1cf58da9154dfbf8813099ea0fe0 languageName: node linkType: hard @@ -33494,60 +25479,64 @@ __metadata: languageName: node linkType: hard -"object.assign@npm:^4.1.4": - version: 4.1.4 - resolution: "object.assign@npm:4.1.4" +"object.assign@npm:^4.1.4, object.assign@npm:^4.1.5": + version: 4.1.5 + resolution: "object.assign@npm:4.1.5" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 + call-bind: ^1.0.5 + define-properties: ^1.2.1 has-symbols: ^1.0.3 object-keys: ^1.1.1 - checksum: 2f286118c023e557757620e647b02e7c88d3d417e0c568fca0820de8ec9cca68928304854d5b03e99763eddad6e78a6716e2930f7e6372e4b9b843f3fd3056f3 + checksum: 60108e1fa2706f22554a4648299b0955236c62b3685c52abf4988d14fffb0e7731e00aa8c6448397e3eb63d087dcc124a9f21e1980f36d0b2667f3c18bacd469 languageName: node linkType: hard -"object.entries@npm:^1.1.0, object.entries@npm:^1.1.6": - version: 1.1.6 - resolution: "object.entries@npm:1.1.6" +"object.entries@npm:^1.1.7": + version: 1.1.8 + resolution: "object.entries@npm:1.1.8" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 8782c71db3a068ccbae9e0541e6b4ac2c25dc67c63f97b7e6ad3c88271d7820197e7398e37747f96542ed47c27f0b81148cdf14c42df15dc22f64818ae7bb5bf + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-object-atoms: ^1.0.0 + checksum: db9ea979d2956a3bc26c262da4a4d212d36f374652cc4c13efdd069c1a519c16571c137e2893d1c46e1cb0e15c88fd6419eaf410c945f329f09835487d7e65d3 languageName: node linkType: hard -"object.fromentries@npm:^2.0.0 || ^1.0.0, object.fromentries@npm:^2.0.6": - version: 2.0.6 - resolution: "object.fromentries@npm:2.0.6" +"object.fromentries@npm:^2.0.7": + version: 2.0.8 + resolution: "object.fromentries@npm:2.0.8" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: db6759ea68131cbdb70b1152f9984b49db03e81de4f6de079b39929bebd8b45501e5333ca2351991e07ee56f4651606c023396644e8f25c0806fa39a26c4c6e6 + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.2 + es-object-atoms: ^1.0.0 + checksum: cd4327e6c3369cfa805deb4cbbe919bfb7d3aeebf0bcaba291bb568ea7169f8f8cdbcabe2f00b40db0c20cd20f08e11b5f3a5a36fb7dd3fe04850c50db3bf83b languageName: node linkType: hard -"object.getownpropertydescriptors@npm:^2.0.3, object.getownpropertydescriptors@npm:^2.1.2": - version: 2.1.6 - resolution: "object.getownpropertydescriptors@npm:2.1.6" +"object.getownpropertydescriptors@npm:^2.0.3": + version: 2.1.8 + resolution: "object.getownpropertydescriptors@npm:2.1.8" dependencies: - array.prototype.reduce: ^1.0.5 - call-bind: ^1.0.2 - define-properties: ^1.2.0 - es-abstract: ^1.21.2 - safe-array-concat: ^1.0.0 - checksum: 9c401557a1cd47d873810b8df61dba350bc39848753180a2c7bdc8b9a67907b7c12e5aa9318fde7fe68d3b62c88b9cbd729b3cc8bbdf02655619b9d2a99b5c2a + array.prototype.reduce: ^1.0.6 + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.2 + es-object-atoms: ^1.0.0 + gopd: ^1.0.1 + safe-array-concat: ^1.1.2 + checksum: 553e9562fd86637c9c169df23a56f1d810d8c9b580a6d4be11552c009f32469310c9347f3d10325abf0cd9cfe4afc521a1e903fbd24148ae7ec860e1e7c75cf3 languageName: node linkType: hard -"object.hasown@npm:^1.1.2": - version: 1.1.2 - resolution: "object.hasown@npm:1.1.2" +"object.hasown@npm:^1.1.3": + version: 1.1.4 + resolution: "object.hasown@npm:1.1.4" dependencies: - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 419fc1c74a2aea7ebb4d49b79d5b1599a010b26c18eae35bd061ccdd013ccb749c499d8dd6ee21a91e6d7264ccc592573d0f13562970f76e25fc844d8c1b02ce + define-properties: ^1.2.1 + es-abstract: ^1.23.2 + es-object-atoms: ^1.0.0 + checksum: f23187b08d874ef1aea060118c8259eb7f99f93c15a50771d710569534119062b90e087b92952b2d0fb1bb8914d61fb0b43c57fb06f622aaad538fe6868ab987 languageName: node linkType: hard @@ -33560,21 +25549,14 @@ __metadata: languageName: node linkType: hard -"object.values@npm:^1.1.0, object.values@npm:^1.1.6": - version: 1.1.6 - resolution: "object.values@npm:1.1.6" +"object.values@npm:^1.1.6, object.values@npm:^1.1.7": + version: 1.2.0 + resolution: "object.values@npm:1.2.0" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 3381204390f10c9f653a4875a50d221c67b5c16cb80a6ac06c706fc82a7cad8400857d4c7a0731193b0abb56b84fe803eabcf7addcf32de76397bbf207e68c66 - languageName: node - linkType: hard - -"objectorarray@npm:^1.0.5": - version: 1.0.5 - resolution: "objectorarray@npm:1.0.5" - checksum: 3d3db66e2052df85617ac31b98f8e51a7a883ebce24123018dacf286712aa513a0a84e82b4a6bef68889d5fc39cf08e630ee78df013023fc5161e1fdf3eaaa5a + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-object-atoms: ^1.0.0 + checksum: 15809dc40fd6c5529501324fec5ff08570b7d70fb5ebbe8e2b3901afec35cf2b3dc484d1210c6c642cd3e7e0a5e18dd1d6850115337fef46bdae14ab0cb18ac3 languageName: node linkType: hard @@ -33585,6 +25567,13 @@ __metadata: languageName: node linkType: hard +"ohash@npm:^1.1.3": + version: 1.1.3 + resolution: "ohash@npm:1.1.3" + checksum: 928f5bdbd8cd73f90cf544c0533dbda8e0a42d9b8c7454ab89e64e4d11bc85f85242830b4e107426ce13dc4dd3013286f8f5e0c84abd8942a014b907d9692540 + languageName: node + linkType: hard + "on-finished@npm:2.4.1": version: 2.4.1 resolution: "on-finished@npm:2.4.1" @@ -33646,16 +25635,6 @@ __metadata: languageName: node linkType: hard -"open@npm:^7.0.3": - version: 7.4.2 - resolution: "open@npm:7.4.2" - dependencies: - is-docker: ^2.0.0 - is-wsl: ^2.1.1 - checksum: 77573a6a68f7364f3a19a4c80492712720746b63680ee304555112605ead196afe91052bd3c3d165efdf4e9d04d255e87de0d0a77acec11ef47fd5261251813f - languageName: node - linkType: hard - "open@npm:^8.0.4, open@npm:^8.0.6, open@npm:^8.4.0": version: 8.4.2 resolution: "open@npm:8.4.2" @@ -33679,13 +25658,13 @@ __metadata: languageName: node linkType: hard -"openapi-sampler@npm:^1.3.1": - version: 1.4.0 - resolution: "openapi-sampler@npm:1.4.0" +"openapi-sampler@npm:^1.5.0": + version: 1.5.1 + resolution: "openapi-sampler@npm:1.5.1" dependencies: "@types/json-schema": ^7.0.7 json-pointer: 0.6.2 - checksum: a1ad50913cfc5adad291806fe4c0cd85301ad3a4f16e1d8df7670ef0d4b8f2b6f81b459cbfdad9be1aa854282ae69cede130ea30e3156d21edbb1f62a2a05ad2 + checksum: 2be444dc56943e1b2134ab01b743d8d14613de994509c5c4554417e427c4e55360a8b47ab45cebb2cf5869b4bcc89d4cd1b10c8a6396e7e419dc3cf3ff6152ed languageName: node linkType: hard @@ -33722,16 +25701,16 @@ __metadata: linkType: hard "optionator@npm:^0.9.1, optionator@npm:^0.9.3": - version: 0.9.3 - resolution: "optionator@npm:0.9.3" + version: 0.9.4 + resolution: "optionator@npm:0.9.4" dependencies: - "@aashutoshrathi/word-wrap": ^1.2.3 deep-is: ^0.1.3 fast-levenshtein: ^2.0.6 levn: ^0.4.1 prelude-ls: ^1.2.1 type-check: ^0.4.0 - checksum: 66fba794d425b5be51353035cf3167ce6cfa049059cbb93229b819167687e0f48d2bc4603fcb21b091c99acb516aae1083624675b15c4765b2e4693a085e959c + word-wrap: ^1.2.5 + checksum: 4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675 languageName: node linkType: hard @@ -33769,20 +25748,6 @@ __metadata: languageName: node linkType: hard -"os-browserify@npm:^0.3.0": - version: 0.3.0 - resolution: "os-browserify@npm:0.3.0" - checksum: 6ff32cb1efe2bc6930ad0fd4c50e30c38010aee909eba8d65be60af55efd6cbb48f0287e3649b4e3f3a63dce5a667b23c187c4293a75e557f0d5489d735bcf52 - languageName: node - linkType: hard - -"os-homedir@npm:^1.0.0": - version: 1.0.2 - resolution: "os-homedir@npm:1.0.2" - checksum: 6be4aa67317ee247b8d46142e243fb4ef1d2d65d3067f54bfc5079257a2f4d4d76b2da78cba7af3cb3f56dbb2e4202e0c47f26171d11ca1ed4008d842c90363f - languageName: node - linkType: hard - "os-tmpdir@npm:~1.0.2": version: 1.0.2 resolution: "os-tmpdir@npm:1.0.2" @@ -33797,22 +25762,6 @@ __metadata: languageName: node linkType: hard -"outvariant@npm:^1.2.0": - version: 1.4.0 - resolution: "outvariant@npm:1.4.0" - checksum: 502d075509fe9709a376cdf9a3eccbd9599fe0c42ed8c723e8c95d4856fa80154e1e957ea0d0d6bb9e0c33352086a6a623803fb5f16775322ede4b9354635bb5 - languageName: node - linkType: hard - -"p-all@npm:^2.1.0": - version: 2.1.0 - resolution: "p-all@npm:2.1.0" - dependencies: - p-map: ^2.0.0 - checksum: 874eafa2e3f38b258f8beed34549befbc8a52a63818e0981b8beff03f592e1e1f47b8aab2483f844f2745815ffa010def58bf1edbc95614466c55411f02f3049 - languageName: node - linkType: hard - "p-cancelable@npm:^2.0.0": version: 2.1.1 resolution: "p-cancelable@npm:2.1.1" @@ -33827,15 +25776,6 @@ __metadata: languageName: node linkType: hard -"p-event@npm:^4.1.0": - version: 4.2.0 - resolution: "p-event@npm:4.2.0" - dependencies: - p-timeout: ^3.1.0 - checksum: f1b6a2fb13d47f2a8afc00150da5ece0d28940ce3d8fa562873e091d3337d298e78fee9cb18b768598ff1d11df608b2ae23868309ff6405b864a2451ccd6d25a - languageName: node - linkType: hard - "p-filter@npm:^2.1.0": version: 2.1.0 resolution: "p-filter@npm:2.1.0" @@ -33920,15 +25860,6 @@ __metadata: languageName: node linkType: hard -"p-map@npm:^3.0.0": - version: 3.0.0 - resolution: "p-map@npm:3.0.0" - dependencies: - aggregate-error: ^3.0.0 - checksum: 297930737e52412ad9f5787c52774ad6496fad9a8be5f047e75fd0a3dc61930d8f7a9b2bbe1c4d1404e54324228a4f69721da2538208dadaa4ef4c81773c9f20 - languageName: node - linkType: hard - "p-map@npm:^4.0.0": version: 4.0.0 resolution: "p-map@npm:4.0.0" @@ -33948,7 +25879,7 @@ __metadata: languageName: node linkType: hard -"p-timeout@npm:^3.1.0, p-timeout@npm:^3.2.0": +"p-timeout@npm:^3.2.0": version: 3.2.0 resolution: "p-timeout@npm:3.2.0" dependencies: @@ -33985,13 +25916,6 @@ __metadata: languageName: node linkType: hard -"pako@npm:~1.0.5": - version: 1.0.11 - resolution: "pako@npm:1.0.11" - checksum: 86dd99d8b34c3930345b8bbeb5e1cd8a05f608eeb40967b293f72fe469d0e9c88b783a8777e4cc7dc7c91ce54c5e93d88ff4b4f060e6ff18408fd21030d9ffbe - languageName: node - linkType: hard - "papaparse@npm:5.3.2": version: 5.3.2 resolution: "papaparse@npm:5.3.2" @@ -33999,27 +25923,6 @@ __metadata: languageName: node linkType: hard -"parallel-transform@npm:^1.1.0": - version: 1.2.0 - resolution: "parallel-transform@npm:1.2.0" - dependencies: - cyclist: ^1.0.1 - inherits: ^2.0.3 - readable-stream: ^2.1.5 - checksum: ab0e58569e73681ca4b9c9228189bdb6cbea535295fae344cf0d8342fd33a950961914f3c414f81894c1498fb9ad1c079b4625d2b7ceae9e6ab812f22e3bea3f - languageName: node - linkType: hard - -"param-case@npm:^3.0.3": - version: 3.0.4 - resolution: "param-case@npm:3.0.4" - dependencies: - dot-case: ^3.0.4 - tslib: ^2.0.3 - checksum: ccc053f3019f878eca10e70ec546d92f51a592f762917dafab11c8b532715dcff58356118a6f350976e4ab109e321756f05739643ed0ca94298e82291e6f9e76 - languageName: node - linkType: hard - "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -34036,42 +25939,6 @@ __metadata: languageName: node linkType: hard -"parse-asn1@npm:^5.0.0, parse-asn1@npm:^5.1.5": - version: 5.1.6 - resolution: "parse-asn1@npm:5.1.6" - dependencies: - asn1.js: ^5.2.0 - browserify-aes: ^1.0.0 - evp_bytestokey: ^1.0.0 - pbkdf2: ^3.0.3 - safe-buffer: ^5.1.1 - checksum: 4ed1d9b9e120c5484d29d67bb90171aac0b73422bc016d6294160aea983275c28a27ab85d862059a36a86a97dd31b7ddd97486802ca9fac67115fe3409e9dcbd - languageName: node - linkType: hard - -"parse-entities@npm:^2.0.0": - version: 2.0.0 - resolution: "parse-entities@npm:2.0.0" - dependencies: - character-entities: ^1.0.0 - character-entities-legacy: ^1.0.0 - character-reference-invalid: ^1.0.0 - is-alphanumerical: ^1.0.0 - is-decimal: ^1.0.0 - is-hexadecimal: ^1.0.0 - checksum: f85a22c0ea406ff26b53fdc28641f01cc36fa49eb2e3135f02693286c89ef0bcefc2262d99b3688e20aac2a14fd10b75c518583e875c1b9fe3d1f937795e0854 - languageName: node - linkType: hard - -"parse-json@npm:^2.2.0": - version: 2.2.0 - resolution: "parse-json@npm:2.2.0" - dependencies: - error-ex: ^1.2.0 - checksum: 7a90132aa76016f518a3d5d746a21b3f1ad0f97a68436ed71b6f995b67c7151141f5464eea0c16c59aec9b7756519a0e3007a8f98cf3714632d509ec07736df6 - languageName: node - linkType: hard - "parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" @@ -34107,7 +25974,7 @@ __metadata: languageName: node linkType: hard -"parse5@npm:6.0.1, parse5@npm:^6.0.0, parse5@npm:^6.0.1": +"parse5@npm:6.0.1, parse5@npm:^6.0.1": version: 6.0.1 resolution: "parse5@npm:6.0.1" checksum: 595821edc094ecbcfb9ddcb46a3e1fe3a718540f8320eff08b8cf6742a5114cce2d46d45f95c26191c11b184dcaf4e2960abcd9c5ed9eb9393ac9a37efcfdecb @@ -34130,7 +25997,7 @@ __metadata: languageName: node linkType: hard -"parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": +"parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" checksum: 90dd4760d6f6174adb9f20cf0965ae12e23879b5f5464f38e92fce8073354341e4b3b76fa3d878351efe7d01e617121955284cfd002ab087fba1a0726ec0b4f5 @@ -34210,19 +26077,12 @@ __metadata: linkType: hard "password-prompt@npm:^1.1.2": - version: 1.1.2 - resolution: "password-prompt@npm:1.1.2" + version: 1.1.3 + resolution: "password-prompt@npm:1.1.3" dependencies: - ansi-escapes: ^3.1.0 - cross-spawn: ^6.0.5 - checksum: 123a660f97e1f722901fd5d3f6b63be1eac7f19370e44b9ecffeec46c00d5f9b2458b508cc4ce0e823964b6f0f6d602395540140ae5edecbf17f1ea5ca08cd39 - languageName: node - linkType: hard - -"path-browserify@npm:0.0.1": - version: 0.0.1 - resolution: "path-browserify@npm:0.0.1" - checksum: 3d59710cddeea06509d91935196185900f3d9d29376dff68ff0e146fbd41d0fb304e983d0158f30cabe4dd2ffcc6a7d3d977631994ee984c88e66aed50a1ccd3 + ansi-escapes: ^4.3.2 + cross-spawn: ^7.0.3 + checksum: f6c2ec49e8bb91a421ed42809c00f8c1d09ee7ea8454c05a40150ec3c47e67b1f16eea7bceace13451accb7bb85859ee3e8d67e8fa3a85f622ba36ebe681ee51 languageName: node linkType: hard @@ -34240,15 +26100,6 @@ __metadata: languageName: node linkType: hard -"path-exists@npm:^2.0.0": - version: 2.1.0 - resolution: "path-exists@npm:2.1.0" - dependencies: - pinkie-promise: ^2.0.0 - checksum: 87352f1601c085d5a6eb202f60e5c016c1b790bd0bc09398af446ed3f5c4510b4531ff99cf8acac2d91868886e792927b4292f768b35a83dce12588fb7cbb46e - languageName: node - linkType: hard - "path-exists@npm:^3.0.0": version: 3.0.0 resolution: "path-exists@npm:3.0.0" @@ -34298,23 +26149,13 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^1.10.0": - version: 1.10.0 - resolution: "path-scurry@npm:1.10.0" +"path-scurry@npm:^1.10.2": + version: 1.10.2 + resolution: "path-scurry@npm:1.10.2" dependencies: - lru-cache: ^9.1.1 || ^10.0.0 - minipass: ^5.0.0 || ^6.0.2 - checksum: dcc4109928c9a0991f0e1719c73b0a184eb7f313fe3eb2242f25274b1e761f53041989fb6b069541b88f58ee6dfbbecf94922225e0c5a3fba8112c9c60abb391 - languageName: node - linkType: hard - -"path-scurry@npm:^1.10.1": - version: 1.10.1 - resolution: "path-scurry@npm:1.10.1" - dependencies: - lru-cache: ^9.1.1 || ^10.0.0 + lru-cache: ^10.2.0 minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 - checksum: e5dc78a7348d25eec61ab166317e9e9c7b46818aa2c2b9006c507a6ff48c672d011292d9662527213e558f5652ce0afcc788663a061d8b59ab495681840c0c1e + checksum: d723777fbf9627f201e64656680f66ebd940957eebacf780e6cce1c2919c29c116678b2d7dbf8821b3a2caa758d125f4444005ccec886a25c8f324504e48e601 languageName: node linkType: hard @@ -34325,26 +26166,6 @@ __metadata: languageName: node linkType: hard -"path-type@npm:^1.0.0": - version: 1.1.0 - resolution: "path-type@npm:1.1.0" - dependencies: - graceful-fs: ^4.1.2 - pify: ^2.0.0 - pinkie-promise: ^2.0.0 - checksum: 2b8c348cb52bbc0c0568afa10a0a5d8f6233adfe5ae75feb56064f6aed6324ab74185c61c2545f4e52ca08acdc76005f615da4e127ed6eecb866002cf491f350 - languageName: node - linkType: hard - -"path-type@npm:^3.0.0": - version: 3.0.0 - resolution: "path-type@npm:3.0.0" - dependencies: - pify: ^3.0.0 - checksum: 1332c632f1cac15790ebab8dd729b67ba04fc96f81647496feb1c2975d862d046f41e4b975dbd893048999b2cc90721f72924ad820acc58c78507ba7141a8e56 - languageName: node - linkType: hard - "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" @@ -34352,10 +26173,10 @@ __metadata: languageName: node linkType: hard -"pathe@npm:^1.1.0, pathe@npm:^1.1.1": - version: 1.1.1 - resolution: "pathe@npm:1.1.1" - checksum: 3ae5a0529c3415d91c3ac9133f52cffea54a0dd46892fe059f4b80faf36fd207957d4594bdc87043b65d0761b1e5728f81f46bafff3b5302da4e2e48889b8c0e +"pathe@npm:^1.1.1, pathe@npm:^1.1.2": + version: 1.1.2 + resolution: "pathe@npm:1.1.2" + checksum: 64ee0a4e587fb0f208d9777a6c56e4f9050039268faaaaecd50e959ef01bf847b7872785c36483fa5cdcdbdfdb31fef2ff222684d4fc21c330ab60395c681897 languageName: node linkType: hard @@ -34373,19 +26194,6 @@ __metadata: languageName: node linkType: hard -"pbkdf2@npm:^3.0.3": - version: 3.1.2 - resolution: "pbkdf2@npm:3.1.2" - dependencies: - create-hash: ^1.1.2 - create-hmac: ^1.1.4 - ripemd160: ^2.0.1 - safe-buffer: ^5.0.1 - sha.js: ^2.4.8 - checksum: 5a30374e87d33fa080a92734d778cf172542cc7e41b96198c4c88763997b62d7850de3fbda5c3111ddf79805ee7c1da7046881c90ac4920b5e324204518b05fd - languageName: node - linkType: hard - "peek-stream@npm:^1.1.0": version: 1.1.3 resolution: "peek-stream@npm:1.1.3" @@ -34425,13 +26233,20 @@ __metadata: languageName: node linkType: hard -"pg-connection-string@npm:2.6.1, pg-connection-string@npm:^2.5.0": +"pg-connection-string@npm:2.6.1": version: 2.6.1 resolution: "pg-connection-string@npm:2.6.1" checksum: e5a71a2da143b8dc17143a9db7737679b210643771aa678d3bc60c7bc70da11bbb8e2d531be91c8c4eddd6ac6046307811e793f5850b9ba595a11785c948a417 languageName: node linkType: hard +"pg-connection-string@npm:^2.5.0": + version: 2.6.4 + resolution: "pg-connection-string@npm:2.6.4" + checksum: 0d0b617df0fc6507bf6a94bdcd56c7a305788a1402d69bff9773350947c8f525d6d8136128065370749a3325e99658ae40fbdcce620fb8e60126181f0591a6a6 + languageName: node + linkType: hard + "pg-god@npm:^1.0.12": version: 1.0.12 resolution: "pg-god@npm:1.0.12" @@ -34463,28 +26278,21 @@ __metadata: linkType: hard "pg-pool@npm:^3.6.0": - version: 3.6.1 - resolution: "pg-pool@npm:3.6.1" + version: 3.6.2 + resolution: "pg-pool@npm:3.6.2" peerDependencies: pg: ">=8.0" - checksum: 47837c4e4c2b9e195cec01bd58b6e276acc915537191707ad4d6ed975fd9bc03c73f63cb7fde4cb0e08ed059e35faf60fbd03744dee3af71d4b4631ab40eeb7f + checksum: 14c524549490954b5e48457a4b808df8f619f6deeb3b395b0cd184a8f4ed65a9273fe0697ba0341a41d6745af197f1437eb1cf51fff0cbbf5b0fb3852ebe5392 languageName: node linkType: hard -"pg-protocol@npm:*": +"pg-protocol@npm:*, pg-protocol@npm:^1.6.0": version: 1.6.1 resolution: "pg-protocol@npm:1.6.1" checksum: 7eadef4010ac0a3925c460be7332ca4098a5c6d5181725a62193fcfa800000ae6632d98d814f3989b42cf5fdc3b45e34c714a1959d29174e81e30730e140ae5f languageName: node linkType: hard -"pg-protocol@npm:^1.6.0": - version: 1.6.0 - resolution: "pg-protocol@npm:1.6.0" - checksum: 318a4d1e9cebd3927b10a8bc412f5017117a1f9a5fafb628d75847da7d1ab81c33250de58596bd0990029e14e92a995a851286d60fc236692299faf509572213 - languageName: node - linkType: hard - "pg-types@npm:^2.1.0": version: 2.2.0 resolution: "pg-types@npm:2.2.0" @@ -34542,13 +26350,6 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^0.2.1": - version: 0.2.1 - resolution: "picocolors@npm:0.2.1" - checksum: 98a83c77912c80aea0fc518aec184768501bfceafa490714b0f43eda9c52e372b844ce0a591e822bbfe5df16dcf366be7cbdb9534d39cf54a80796340371ee17 - languageName: node - linkType: hard - "picocolors@npm:^1.0.0": version: 1.0.0 resolution: "picocolors@npm:1.0.0" @@ -34563,20 +26364,13 @@ __metadata: languageName: node linkType: hard -"pify@npm:^2.0.0, pify@npm:^2.3.0": +"pify@npm:^2.3.0": version: 2.3.0 resolution: "pify@npm:2.3.0" checksum: 551ff8ab830b1052633f59cb8adc9ae8407a436e06b4a9718bcb27dc5844b83d535c3a8512b388b6062af65a98c49bdc0dd523d8b2617b188f7c8fee457158dc languageName: node linkType: hard -"pify@npm:^3.0.0": - version: 3.0.0 - resolution: "pify@npm:3.0.0" - checksum: fead19ed9d801f1b1fcd0638a1ac53eabbb0945bf615f2f8806a8b646565a04a1b0e7ef115c951d225f042cca388fdc1cd3add46d10d1ed6951c20bd2998af10 - languageName: node - linkType: hard - "pify@npm:^4.0.1": version: 4.0.1 resolution: "pify@npm:4.0.1" @@ -34591,23 +26385,7 @@ __metadata: languageName: node linkType: hard -"pinkie-promise@npm:^2.0.0": - version: 2.0.1 - resolution: "pinkie-promise@npm:2.0.1" - dependencies: - pinkie: ^2.0.0 - checksum: 11b5e5ce2b090c573f8fad7b517cbca1bb9a247587306f05ae71aef6f9b2cd2b923c304aa9663c2409cfde27b367286179f1379bc4ec18a3fbf2bb0d473b160a - languageName: node - linkType: hard - -"pinkie@npm:^2.0.0": - version: 2.0.4 - resolution: "pinkie@npm:2.0.4" - checksum: 25228b08b5597da42dc384221aa0ce56ee0fbf32965db12ba838e2a9ca0193c2f0609c45551ee077ccd2060bf109137fdb185b00c6d7e0ed7e35006d20fdcbc6 - languageName: node - linkType: hard - -"pirates@npm:^4.0.1, pirates@npm:^4.0.4, pirates@npm:^4.0.5": +"pirates@npm:^4.0.1, pirates@npm:^4.0.4, pirates@npm:^4.0.6": version: 4.0.6 resolution: "pirates@npm:4.0.6" checksum: 00d5fa51f8dded94d7429700fb91a0c1ead00ae2c7fd27089f0c5b63e6eca36197fe46384631872690a66f390c5e27198e99006ab77ae472692ab9c2ca903f36 @@ -34641,14 +26419,14 @@ __metadata: languageName: node linkType: hard -"pkg-types@npm:^1.0.3": - version: 1.0.3 - resolution: "pkg-types@npm:1.0.3" +"pkg-types@npm:^1.1.0": + version: 1.1.0 + resolution: "pkg-types@npm:1.1.0" dependencies: - jsonc-parser: ^3.2.0 - mlly: ^1.2.0 - pathe: ^1.1.0 - checksum: 7f692ff2005f51b8721381caf9bdbc7f5461506ba19c34f8631660a215c8de5e6dca268f23a319dd180b8f7c47a0dc6efea14b376c485ff99e98d810b8f786c4 + confbox: ^0.1.7 + mlly: ^1.6.1 + pathe: ^1.1.2 + checksum: b350da13d2dab7dc2fa9d65a08a2038d841d8d8c94bf3878dd911a522e20da50d6662bab510fa329e363e403892374b3b847ebf7b3e10011805cdefb00f228fd languageName: node linkType: hard @@ -34669,11 +26447,11 @@ __metadata: linkType: hard "plimit-lit@npm:^1.2.6": - version: 1.5.0 - resolution: "plimit-lit@npm:1.5.0" + version: 1.6.1 + resolution: "plimit-lit@npm:1.6.1" dependencies: - queue-lit: ^1.5.0 - checksum: fe2d31ecab11185e24c874e6b2b741e19515dcb943e571a703a9a1621813b94299a486718ea8efa68fd70f239294fa909669eeb8685ff74e29bf1a6d2b6bff12 + queue-lit: ^1.5.1 + checksum: af5d351bb55afe1eaa84b27c2b329699e150e4cf70464f3d474f5eabe9bdb9f48ed378ada1498d3b893f68ee7da2423ba6d9a4d88b1429d3b0aea22afcf5292b languageName: node linkType: hard @@ -34691,28 +26469,19 @@ __metadata: languageName: node linkType: hard -"pnp-webpack-plugin@npm:1.6.4": - version: 1.6.4 - resolution: "pnp-webpack-plugin@npm:1.6.4" - dependencies: - ts-pnp: ^1.1.6 - checksum: 6cedab8a9cd129b9f58408023f80cad528e361685f50c2149da7ad8fb79bd2043d3250c68b8723aa43ecdb913931edf04ecaa4d7afe719d0e151055d41779599 - languageName: node - linkType: hard - -"polished@npm:^4.1.3, polished@npm:^4.2.2": - version: 4.2.2 - resolution: "polished@npm:4.2.2" +"polished@npm:^4.2.2": + version: 4.3.1 + resolution: "polished@npm:4.3.1" dependencies: "@babel/runtime": ^7.17.8 - checksum: 1d054d1fea18ac7d921ca91504ffcf1ef0f505eda6acbfec6e205a98ebfea80b658664995deb35907dabc5f75f287dc2894812503a8aed28285bb91f25cf7400 + checksum: 45480d4c7281a134281cef092f6ecc202a868475ff66a390fee6e9261386e16f3047b4de46a2f2e1cf7fb7aa8f52d30b4ed631a1e3bcd6f303ca31161d4f07fe languageName: node linkType: hard "pony-cause@npm:^2.1.4": - version: 2.1.10 - resolution: "pony-cause@npm:2.1.10" - checksum: 55ad0ca52039895f273c69e55fc9fe882deff38689dc5962558bfa16cce0ea7cb5bb7b67d0c43ec9c3e7edeb81f81ee8c1113014930d77b2cbac5adc4ac7fb64 + version: 2.1.11 + resolution: "pony-cause@npm:2.1.11" + checksum: d5db6489ec42f8fcce0fd9ad2052be98cd8f63814bf32819694ec1f4c6a01bc3be6181050d83bc79e95272174a5b9776d1c2af1fa79ef51e0ccc0f97c22b1420 languageName: node linkType: hard @@ -34723,6 +26492,13 @@ __metadata: languageName: node linkType: hard +"possible-typed-array-names@npm:^1.0.0": + version: 1.0.0 + resolution: "possible-typed-array-names@npm:1.0.0" + checksum: d9aa22d31f4f7680e20269db76791b41c3a32c01a373e25f8a4813b4d45f7456bfc2b6d68f752dc4aab0e0bb0721cb3d76fb678c9101cb7a16316664bc2c73fd + languageName: node + linkType: hard + "postcss-calc@npm:^8.2.3": version: 8.2.4 resolution: "postcss-calc@npm:8.2.4" @@ -34797,15 +26573,6 @@ __metadata: languageName: node linkType: hard -"postcss-flexbugs-fixes@npm:^4.2.1": - version: 4.2.1 - resolution: "postcss-flexbugs-fixes@npm:4.2.1" - dependencies: - postcss: ^7.0.26 - checksum: 57d2894dadd5762ae243792ca45806281ca9c32a9270519f2fd5d95cf1445590df260997b3d9ff937b9e1a551644799881c7f337352dde4e453805687c1ebee8 - languageName: node - linkType: hard - "postcss-import@npm:^15.1.0": version: 15.1.0 resolution: "postcss-import@npm:15.1.0" @@ -34830,7 +26597,7 @@ __metadata: languageName: node linkType: hard -"postcss-load-config@npm:^3.0.0, postcss-load-config@npm:^3.0.1": +"postcss-load-config@npm:^3.0.0": version: 3.1.4 resolution: "postcss-load-config@npm:3.1.4" dependencies: @@ -34849,11 +26616,11 @@ __metadata: linkType: hard "postcss-load-config@npm:^4.0.1": - version: 4.0.1 - resolution: "postcss-load-config@npm:4.0.1" + version: 4.0.2 + resolution: "postcss-load-config@npm:4.0.2" dependencies: - lilconfig: ^2.0.5 - yaml: ^2.1.1 + lilconfig: ^3.0.0 + yaml: ^2.3.4 peerDependencies: postcss: ">=8.0.9" ts-node: ">=9.0.0" @@ -34862,37 +26629,21 @@ __metadata: optional: true ts-node: optional: true - checksum: 5f568420c4d758d77d661f26914c08fe8dfb0666c7b779dc4f48d7fd880d131e8aa232a45cc1a8ba3f47f9c5fca572b661ca0103c2212979e9dc00918cff3d5f - languageName: node - linkType: hard - -"postcss-loader@npm:^4.2.0": - version: 4.3.0 - resolution: "postcss-loader@npm:4.3.0" - dependencies: - cosmiconfig: ^7.0.0 - klona: ^2.0.4 - loader-utils: ^2.0.0 - schema-utils: ^3.0.0 - semver: ^7.3.4 - peerDependencies: - postcss: ^7.0.0 || ^8.0.1 - webpack: ^4.0.0 || ^5.0.0 - checksum: 3405584e571ec4d66d7c2b665a2a4823eaa7208433fd40eb6b669ac441f23398bc81fc18fe631c7d7805a303ad31f284a5066c4097dd082c1faba7edf13db8aa + checksum: 3d7939acb3570b0e4b4740e483d6e555a3e2de815219cb8a3c8fc03f575a6bde667443aa93369c0be390af845cb84471bf623e24af833260de3a105b78d42519 languageName: node linkType: hard "postcss-loader@npm:^7.2.4": - version: 7.3.3 - resolution: "postcss-loader@npm:7.3.3" + version: 7.3.4 + resolution: "postcss-loader@npm:7.3.4" dependencies: - cosmiconfig: ^8.2.0 - jiti: ^1.18.2 - semver: ^7.3.8 + cosmiconfig: ^8.3.5 + jiti: ^1.20.0 + semver: ^7.5.4 peerDependencies: postcss: ^7.0.0 || ^8.0.1 webpack: ^5.0.0 - checksum: d039654273f858be1f75dfdf8b550869d88905b73a7684b3e48a2937a6087619e84fd1a3551cdef78685a965a2573e985b29a532c3878d834071ecd2da0eb304 + checksum: 1bf7614aeea9ad1f8ee6be3a5451576c059391688ea67f825aedc2674056369597faeae4e4a81fe10843884c9904a71403d9a54197e1f560e8fbb9e61f2a2680 languageName: node linkType: hard @@ -34970,77 +26721,36 @@ __metadata: languageName: node linkType: hard -"postcss-modules-extract-imports@npm:^2.0.0": - version: 2.0.0 - resolution: "postcss-modules-extract-imports@npm:2.0.0" - dependencies: - postcss: ^7.0.5 - checksum: 170e8d680c267c536563e76979f04dc80e6dfa026d49f1e9ead2d0981a74b0c64d2894a8fd691e50568f12144553cf0b948ab43263872b3f696dcb34b683e238 - languageName: node - linkType: hard - -"postcss-modules-extract-imports@npm:^3.0.0": - version: 3.0.0 - resolution: "postcss-modules-extract-imports@npm:3.0.0" +"postcss-modules-extract-imports@npm:^3.0.0, postcss-modules-extract-imports@npm:^3.1.0": + version: 3.1.0 + resolution: "postcss-modules-extract-imports@npm:3.1.0" peerDependencies: postcss: ^8.1.0 - checksum: f8879d66d8162fb7a3fcd916d37574006c584ea509107b1cfb798a5e090175ef9470f601e46f0a305070d8ff2500e07489a5c1ac381c29a1dc1120e827ca7943 + checksum: 402084bcab376083c4b1b5111b48ec92974ef86066f366f0b2d5b2ac2b647d561066705ade4db89875a13cb175b33dd6af40d16d32b2ea5eaf8bac63bd2bf219 languageName: node linkType: hard -"postcss-modules-local-by-default@npm:^3.0.2": - version: 3.0.3 - resolution: "postcss-modules-local-by-default@npm:3.0.3" - dependencies: - icss-utils: ^4.1.1 - postcss: ^7.0.32 - postcss-selector-parser: ^6.0.2 - postcss-value-parser: ^4.1.0 - checksum: 007fd7286b4e120edfdf1a41f2006e9c8cb49e1613a4e3f0fdc184ad14273a1bbfc39ced3bc7cbad9af64bf67056e8ea0dcfda16d3057562343a48ee9ec2ccac - languageName: node - linkType: hard - -"postcss-modules-local-by-default@npm:^4.0.0, postcss-modules-local-by-default@npm:^4.0.3": - version: 4.0.3 - resolution: "postcss-modules-local-by-default@npm:4.0.3" +"postcss-modules-local-by-default@npm:^4.0.0, postcss-modules-local-by-default@npm:^4.0.5": + version: 4.0.5 + resolution: "postcss-modules-local-by-default@npm:4.0.5" dependencies: icss-utils: ^5.0.0 postcss-selector-parser: ^6.0.2 postcss-value-parser: ^4.1.0 peerDependencies: postcss: ^8.1.0 - checksum: be49b86efbfb921f42287e227584aac91af9826fc1083db04958ae283dfe215ca539421bfba71f9da0f0b10651f28e95a64b5faca7166f578a1933b8646051f7 + checksum: f4ad35abeb685ecb25f80c93d9fe23c8b89ee45ac4185f3560e701b4d7372f9b798577e79c5ed03b6d9c80bc923b001210c127c04ced781f43cda9e32b202a5b languageName: node linkType: hard -"postcss-modules-scope@npm:^2.2.0": - version: 2.2.0 - resolution: "postcss-modules-scope@npm:2.2.0" - dependencies: - postcss: ^7.0.6 - postcss-selector-parser: ^6.0.0 - checksum: 60b4438d43e6629d72b31a5122037e5574f8a6a4629038cd74afc4e5197cebc55b76c765b6bfcc2421bc740d19c3c97e68918e560a0fe88047c2131d0966df3c - languageName: node - linkType: hard - -"postcss-modules-scope@npm:^3.0.0": - version: 3.0.0 - resolution: "postcss-modules-scope@npm:3.0.0" +"postcss-modules-scope@npm:^3.0.0, postcss-modules-scope@npm:^3.2.0": + version: 3.2.0 + resolution: "postcss-modules-scope@npm:3.2.0" dependencies: postcss-selector-parser: ^6.0.4 peerDependencies: postcss: ^8.1.0 - checksum: 60af503910363689568c2c3701cb019a61b58b3d739391145185eec211bea5d50ccb6ecbe6955b39d856088072fd50ea002e40a52b50e33b181ff5c41da0308a - languageName: node - linkType: hard - -"postcss-modules-values@npm:^3.0.0": - version: 3.0.0 - resolution: "postcss-modules-values@npm:3.0.0" - dependencies: - icss-utils: ^4.0.0 - postcss: ^7.0.6 - checksum: f97b4669446810aa9c4c22538e24faee203e8462f1c7d38923c57140903bc170451dfec5974e480c2c367690735042cbfec187d209d0044d99f829f29ad0e610 + checksum: a2f5ffe372169b3feb8628cd785eb748bf12e344cfa57bce9e5cdc4fa5adcdb40d36daa86bb35dad53427703b185772aad08825b5783f745fcb1b6039454a84b languageName: node linkType: hard @@ -35218,13 +26928,13 @@ __metadata: languageName: node linkType: hard -"postcss-selector-parser@npm:^6.0.0, postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9": - version: 6.0.13 - resolution: "postcss-selector-parser@npm:6.0.13" +"postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9": + version: 6.0.16 + resolution: "postcss-selector-parser@npm:6.0.16" dependencies: cssesc: ^3.0.0 util-deprecate: ^1.0.2 - checksum: 51f099b27f7c7198ea1826470ef0adfa58b3bd3f59b390fda123baa0134880a5fa9720137b6009c4c1373357b144f700b0edac73335d0067422063129371444e + checksum: 0e11657cb3181aaf9ff67c2e59427c4df496b4a1b6a17063fae579813f80af79d444bf38f82eeb8b15b4679653fd3089e66ef0283f9aab01874d885e6cf1d2cf languageName: node linkType: hard @@ -35258,7 +26968,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:8.4.31, postcss@npm:^8.2.14, postcss@npm:^8.4.23, postcss@npm:^8.4.27": +"postcss@npm:8.4.31": version: 8.4.31 resolution: "postcss@npm:8.4.31" dependencies: @@ -35269,50 +26979,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^7.0.14, postcss@npm:^7.0.26, postcss@npm:^7.0.32, postcss@npm:^7.0.36, postcss@npm:^7.0.5, postcss@npm:^7.0.6": - version: 7.0.39 - resolution: "postcss@npm:7.0.39" - dependencies: - picocolors: ^0.2.1 - source-map: ^0.6.1 - checksum: fd27ee808c0d02407582cccfad4729033e2b439d56cd45534fb39aaad308bb35a290f3b7db5f2394980e8756f9381b458a625618550808c5ff01a125f51efc53 - languageName: node - linkType: hard - -"postcss@npm:^8.2.1, postcss@npm:^8.4.21": - version: 8.4.24 - resolution: "postcss@npm:8.4.24" - dependencies: - nanoid: ^3.3.6 - picocolors: ^1.0.0 - source-map-js: ^1.0.2 - checksum: 37704ee03a2cbdebf2c99a76d399d6e0250742b5f6c699a12d475c84cedfcbeb26e180d9c780e0219dd2ad70cac963ceaf1d6763a1aec3e63d0c19fceb0eab23 - languageName: node - linkType: hard - -"postcss@npm:^8.4.32": - version: 8.4.32 - resolution: "postcss@npm:8.4.32" - dependencies: - nanoid: ^3.3.7 - picocolors: ^1.0.0 - source-map-js: ^1.0.2 - checksum: 39308a9195fa34d4dbdd7b58a896cff0c7809f84f7a4ac1b95b68ca86c9138a395addff33075668ed3983d41b90aac05754c445237a9365eb1c3a5602ebd03ad - languageName: node - linkType: hard - -"postcss@npm:^8.4.33": - version: 8.4.33 - resolution: "postcss@npm:8.4.33" - dependencies: - nanoid: ^3.3.7 - picocolors: ^1.0.0 - source-map-js: ^1.0.2 - checksum: 16eda83458fcd8a91bece287b5920c7f57164c3ea293e6c80d0ea71ce7843007bcd8592260a5160b9a7f02693e6ac93e2495b02d8c7596d3f3f72c1447e3ba79 - languageName: node - linkType: hard - -"postcss@npm:^8.4.38": +"postcss@npm:^8.2.1, postcss@npm:^8.2.14, postcss@npm:^8.4.23, postcss@npm:^8.4.27, postcss@npm:^8.4.32, postcss@npm:^8.4.33, postcss@npm:^8.4.38": version: 8.4.38 resolution: "postcss@npm:8.4.38" dependencies: @@ -35391,14 +27058,14 @@ __metadata: linkType: hard "preferred-pm@npm:^3.0.0": - version: 3.0.3 - resolution: "preferred-pm@npm:3.0.3" + version: 3.1.3 + resolution: "preferred-pm@npm:3.1.3" dependencies: find-up: ^5.0.0 find-yarn-workspace-root2: 1.2.16 path-exists: ^4.0.0 which-pm: 2.0.0 - checksum: 5ab144a14094202b99d7ca92e37c1649675f2fe3ec530bd2a8bba4af84161a53dff2266315dfd18fad1566a657cabc6c7a208937f0baf671358f25a1f4c0e3eb + checksum: 8eb9c35e4818d8e20b5b61a2117f5c77678649e1d20492fe4fdae054a9c4b930d04582b17e8a59b2dc923f2f788c7ded7fc99fd22c04631d836f7f52aeb79bde languageName: node linkType: hard @@ -35477,15 +27144,6 @@ __metadata: languageName: node linkType: hard -"prettier@npm:>=2.2.1 <=2.3.0": - version: 2.3.0 - resolution: "prettier@npm:2.3.0" - bin: - prettier: bin-prettier.js - checksum: b9f434af2f25a37aad0b133894827e980885eb8bf317444c9dde0401ed2c7f463f9996d691f5ee5a0a4450ab46a894cd6557516b561e2522821522ce1f4c6668 - languageName: node - linkType: hard - "prettier@npm:^2.7.1, prettier@npm:^2.8.0, prettier@npm:^2.8.7, prettier@npm:^2.8.8": version: 2.8.8 resolution: "prettier@npm:2.8.8" @@ -35496,11 +27154,11 @@ __metadata: linkType: hard "prettier@npm:^3.1.1": - version: 3.1.1 - resolution: "prettier@npm:3.1.1" + version: 3.2.5 + resolution: "prettier@npm:3.2.5" bin: prettier: bin/prettier.cjs - checksum: facc944ba20e194ff4db765e830ffbcb642803381f0d2033ed397e79904fa4ccc877dc25ad68f42d36985c01d051c990ca1b905fb83d2d7d65fe69e4386fa1a3 + checksum: ea327f37a7d46f2324a34ad35292af2ad4c4c3c3355da07313339d7e554320f66f65f91e856add8530157a733c6c4a897dc41b577056be5c24c40f739f5ee8c6 languageName: node linkType: hard @@ -35520,16 +27178,6 @@ __metadata: languageName: node linkType: hard -"pretty-error@npm:^2.1.1": - version: 2.1.2 - resolution: "pretty-error@npm:2.1.2" - dependencies: - lodash: ^4.17.20 - renderkid: ^2.0.4 - checksum: 779743faf707308e5d07c53c3ec94596c0cb631c92104a2721dd5d021ade39505a9151c5a5f838dfd26b02a06752c410eb6de1769c4fe327c90bd083f61a1fa1 - languageName: node - linkType: hard - "pretty-format@npm:^25.5.0": version: 25.5.0 resolution: "pretty-format@npm:25.5.0" @@ -35565,7 +27213,7 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": +"pretty-format@npm:^29.0.0, pretty-format@npm:^29.5.0, pretty-format@npm:^29.7.0": version: 29.7.0 resolution: "pretty-format@npm:29.7.0" dependencies: @@ -35576,28 +27224,6 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^29.5.0": - version: 29.5.0 - resolution: "pretty-format@npm:29.5.0" - dependencies: - "@jest/schemas": ^29.4.3 - ansi-styles: ^5.0.0 - react-is: ^18.0.0 - checksum: bcc0190d050196b64e501e5c2b44beb802d79a2b70b6fe6b24ae2d5e0f31237dfcb1f0ab2ada4678829b6ee38507ba292396301aff0a8122e575ffd45d5d037c - languageName: node - linkType: hard - -"pretty-format@npm:^29.6.3": - version: 29.6.3 - resolution: "pretty-format@npm:29.6.3" - dependencies: - "@jest/schemas": ^29.6.3 - ansi-styles: ^5.0.0 - react-is: ^18.0.0 - checksum: 73c6a46acdad4cb9337add02c850769fb831d7154cdb50b1152f3970a8fbf8292188dcccd1ba597f3e34c360af71fc0b63f1db4cf155a0098ffe2812eb7a6b22 - languageName: node - linkType: hard - "pretty-hrtime@npm:^1.0.3": version: 1.0.3 resolution: "pretty-hrtime@npm:1.0.3" @@ -35606,24 +27232,38 @@ __metadata: linkType: hard "prism-react-renderer@npm:^2.0.6": - version: 2.0.6 - resolution: "prism-react-renderer@npm:2.0.6" + version: 2.3.1 + resolution: "prism-react-renderer@npm:2.3.1" dependencies: "@types/prismjs": ^1.26.0 - clsx: ^1.2.1 + clsx: ^2.0.0 peerDependencies: react: ">=16.0.0" - checksum: f98b67ebe64c2c83449c7cedd285b55ad1ab48fafb189fba7b7bc653f68717172699934c9403906ccbc0da414329d00e15fa673cc38265fd003f010d8efb3331 + checksum: 566932127ca18049a651aa038a8f8c7c1ca15950d21b659c2ce71fd95bd03bef2b5d40c489e7aa3453eaf15d984deef542a609d7842e423e6a13427dd90bd371 languageName: node linkType: hard -"prismjs@npm:^1.27.0, prismjs@npm:^1.29.0": +"prismjs@npm:^1.29.0": version: 1.29.0 resolution: "prismjs@npm:1.29.0" checksum: d906c4c4d01b446db549b4f57f72d5d7e6ccaca04ecc670fb85cea4d4b1acc1283e945a9cbc3d81819084a699b382f970e02f9d1378e14af9808d366d9ed7ec6 languageName: node linkType: hard +"proc-log@npm:^3.0.0": + version: 3.0.0 + resolution: "proc-log@npm:3.0.0" + checksum: f66430e4ff947dbb996058f6fd22de2c66612ae1a89b097744e17fb18a4e8e7a86db99eda52ccf15e53f00b63f4ec0b0911581ff2aac0355b625c8eac509b0dc + languageName: node + linkType: hard + +"proc-log@npm:^4.2.0": + version: 4.2.0 + resolution: "proc-log@npm:4.2.0" + checksum: 17db4757c2a5c44c1e545170e6c70a26f7de58feb985091fb1763f5081cab3d01b181fb2dd240c9f4a4255a1d9227d163d5771b7e69c9e49a561692db865efb9 + languageName: node + linkType: hard + "process-nextick-args@npm:~2.0.0": version: 2.0.1 resolution: "process-nextick-args@npm:2.0.1" @@ -35645,13 +27285,6 @@ __metadata: languageName: node linkType: hard -"promise-inflight@npm:^1.0.1": - version: 1.0.1 - resolution: "promise-inflight@npm:1.0.1" - checksum: d179d148d98fbff3d815752fa9a08a87d3190551d1420f17c4467f628214db12235ae068d98cd001f024453676d8985af8f28f002345646c4ece4600a79620bc - languageName: node - linkType: hard - "promise-retry@npm:^2.0.1": version: 2.0.1 resolution: "promise-retry@npm:2.0.1" @@ -35662,43 +27295,18 @@ __metadata: languageName: node linkType: hard -"promise.allsettled@npm:^1.0.0": - version: 1.0.6 - resolution: "promise.allsettled@npm:1.0.6" - dependencies: - array.prototype.map: ^1.0.5 - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - get-intrinsic: ^1.1.3 - iterate-value: ^1.0.2 - checksum: 34f82313be2e9384282935d91bd6c13bb444351f86b75f218f4a388eed59be9e0db87daeafe909997d4afd8f75049b78adcc51ecfe399cc6b60f23b77f235ad9 - languageName: node - linkType: hard - "promise.any@npm:^2.0.2": - version: 2.0.5 - resolution: "promise.any@npm:2.0.5" + version: 2.0.6 + resolution: "promise.any@npm:2.0.6" dependencies: array.prototype.map: ^1.0.5 call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - es-aggregate-error: ^1.0.9 - get-intrinsic: ^1.1.3 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + es-aggregate-error: ^1.0.10 + get-intrinsic: ^1.2.1 iterate-value: ^1.0.2 - checksum: fc573c2f3f13719284d577c0b1fbecdcd84552de1bbf2d59133e140931fd90a284ebba7d51d1e288ed15550b0f340f96805126547a9a0b30cb10da02a34b1c70 - languageName: node - linkType: hard - -"promise.prototype.finally@npm:^3.1.0": - version: 3.1.4 - resolution: "promise.prototype.finally@npm:3.1.4" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 7efbf88b4cc2b38452ef1d3ee934c61f3ed7034b0f4e9a072f6eded123701e409e8f2aadba870f93a5012e766d1cc9b4fd076e665a9e4adace817c7e7ea88d28 + checksum: 3f6fd5b22ce8b72aebebd2643bd5bbb55a6740d24f8e02cc1dd6e2e625bb0edee71f621ceae1285cf45f2bed6f7a02bb59506a4f99809ce741e7d5e8c9dae203 languageName: node linkType: hard @@ -35709,15 +27317,6 @@ __metadata: languageName: node linkType: hard -"promise@npm:^7.1.1": - version: 7.3.1 - resolution: "promise@npm:7.3.1" - dependencies: - asap: ~2.0.3 - checksum: 742e5c0cc646af1f0746963b8776299701ad561ce2c70b49365d62c8db8ea3681b0a1bf0d4e2fe07910bf72f02d39e51e8e73dc8d7503c3501206ac908be107f - languageName: node - linkType: hard - "prompts@npm:^2.0.1, prompts@npm:^2.4.0, prompts@npm:^2.4.2": version: 2.4.2 resolution: "prompts@npm:2.4.2" @@ -35728,7 +27327,7 @@ __metadata: languageName: node linkType: hard -"prop-types@npm:^15.0.0, prop-types@npm:^15.5.0, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": +"prop-types@npm:^15.5.0, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": version: 15.8.1 resolution: "prop-types@npm:15.8.1" dependencies: @@ -35739,15 +27338,6 @@ __metadata: languageName: node linkType: hard -"property-information@npm:^5.0.0, property-information@npm:^5.3.0": - version: 5.6.0 - resolution: "property-information@npm:5.6.0" - dependencies: - xtend: ^4.0.0 - checksum: d54b77c31dc13bb6819559080b2c67d37d94be7dc271f404f139a16a57aa96fcc0b3ad806d4a5baef9e031744853e4afe3df2e37275aacb1f78079bbb652c5af - languageName: node - linkType: hard - "proxy-addr@npm:~2.0.5, proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" @@ -35793,20 +27383,6 @@ __metadata: languageName: node linkType: hard -"public-encrypt@npm:^4.0.0": - version: 4.0.3 - resolution: "public-encrypt@npm:4.0.3" - dependencies: - bn.js: ^4.1.0 - browserify-rsa: ^4.0.0 - create-hash: ^1.1.0 - parse-asn1: ^5.0.0 - randombytes: ^2.0.1 - safe-buffer: ^5.1.2 - checksum: 6c2cc19fbb554449e47f2175065d6b32f828f9b3badbee4c76585ac28ae8641aafb9bb107afc430c33c5edd6b05dbe318df4f7d6d7712b1093407b11c4280700 - languageName: node - linkType: hard - "pump@npm:^2.0.0": version: 2.0.1 resolution: "pump@npm:2.0.1" @@ -35838,7 +27414,7 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^1.2.4, punycode@npm:^1.4.1": +"punycode@npm:^1.4.1": version: 1.4.1 resolution: "punycode@npm:1.4.1" checksum: 354b743320518aef36f77013be6e15da4db24c2b4f62c5f1eb0529a6ed02fbaf1cb52925785f6ab85a962f2b590d9cd5ad730b70da72b5f180e2556b8bd3ca08 @@ -35846,9 +27422,9 @@ __metadata: linkType: hard "punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.0": - version: 2.3.0 - resolution: "punycode@npm:2.3.0" - checksum: 8e6f7abdd3a6635820049e3731c623bbef3fedbf63bbc696b0d7237fdba4cefa069bc1fa62f2938b0fbae057550df7b5318f4a6bcece27f1907fc75c54160bee + version: 2.3.1 + resolution: "punycode@npm:2.3.1" + checksum: 14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 languageName: node linkType: hard @@ -35870,17 +27446,10 @@ __metadata: languageName: node linkType: hard -"pure-color@npm:^1.2.0": - version: 1.3.0 - resolution: "pure-color@npm:1.3.0" - checksum: 50d0e088ad0349bdd508cddf7c7afbb2d14ba3c047628dbfcfddf467a98f10462caf91f3227172ada88f64afaf761c499ecba0d4053b06926f0f914769be24b9 - languageName: node - linkType: hard - "pure-rand@npm:^6.0.0": - version: 6.0.2 - resolution: "pure-rand@npm:6.0.2" - checksum: 0556bee2e16a8d081a2b7630d9cb4e5dafd4e6bd6e4c61de1cf1ef5974f127847523e3d0e62884f6f5d64b66a5e93b05bd8f37ed009f3a4fe5089899e05914aa + version: 6.1.0 + resolution: "pure-rand@npm:6.1.0" + checksum: 1abe217897bf74dcb3a0c9aba3555fe975023147b48db540aa2faf507aee91c03bf54f6aef0eb2bf59cc259a16d06b28eca37f0dc426d94f4692aeff02fb0e65 languageName: node linkType: hard @@ -35909,21 +27478,12 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.10.0, qs@npm:^6.10.3, qs@npm:^6.11.0, qs@npm:^6.11.2, qs@npm:^6.5.1": - version: 6.11.2 - resolution: "qs@npm:6.11.2" - dependencies: - side-channel: ^1.0.4 - checksum: 4f95d4ff18ed480befcafa3390022817ffd3087fc65f146cceb40fc5edb9fa96cb31f648cae2fa96ca23818f0798bd63ad4ca369a0e22702fcd41379b3ab6571 - languageName: node - linkType: hard - -"qs@npm:^6.12.0": - version: 6.12.0 - resolution: "qs@npm:6.12.0" +"qs@npm:^6.10.0, qs@npm:^6.10.3, qs@npm:^6.11.0, qs@npm:^6.11.2, qs@npm:^6.12.0, qs@npm:^6.5.1": + version: 6.12.1 + resolution: "qs@npm:6.12.1" dependencies: side-channel: ^1.0.6 - checksum: e165a77ac5f3ca60c15c5f3d51b321ddec7aa438804436b29d160117bc6fb7bf7dab94abd0c7d7c0785890d3a75ae41e1d6346e158aaf1540c6fe53a31f11675 + checksum: 439e6d7c6583e7c69f2cab2c39c55b97db7ce576e4c7c469082b938b7fc8746e8d547baacb69b4cd2b6666484776c3f4840ad7163a4c5326300b0afa0acdd84b languageName: node linkType: hard @@ -35934,13 +27494,6 @@ __metadata: languageName: node linkType: hard -"querystring-es3@npm:^0.2.0": - version: 0.2.1 - resolution: "querystring-es3@npm:0.2.1" - checksum: 476938c1adb45c141f024fccd2ffd919a3746e79ed444d00e670aad68532977b793889648980e7ca7ff5ffc7bfece623118d0fbadcaf217495eeb7059ae51580 - languageName: node - linkType: hard - "querystringify@npm:^2.1.1": version: 2.2.0 resolution: "querystringify@npm:2.2.0" @@ -35948,10 +27501,10 @@ __metadata: languageName: node linkType: hard -"queue-lit@npm:^1.5.0": - version: 1.5.0 - resolution: "queue-lit@npm:1.5.0" - checksum: e6b8ba9cdfca2c775e3f93bbd13870e77c9214f8590fa1ca203f3a2b8357d8d1eb44cdf707eca7fbfd60cef0faa74352778bf57b710b27869713b18acdc0d281 +"queue-lit@npm:^1.5.1": + version: 1.5.2 + resolution: "queue-lit@npm:1.5.2" + checksum: 8aa838b2c939aeaa6cd272b5b6b172379a3fa1d9193b2a3e687643c68c0efee3cd3493af4f1f8a11ff79b8207e4d00cc5d0b072f6e4bbeaaa27ee01f567ec4ac languageName: node linkType: hard @@ -35990,13 +27543,6 @@ __metadata: languageName: node linkType: hard -"ramda@npm:^0.28.0": - version: 0.28.0 - resolution: "ramda@npm:0.28.0" - checksum: 0f9dc0cc3b0432ff047f1e2a5e58860c531a84574674c0f52fef535efc6e1e07fa3851102fff3da7dd551a592c743f6f6fa521379a6aa5fe50266f8af8f0b570 - languageName: node - linkType: hard - "random-bytes@npm:~1.0.0": version: 1.0.0 resolution: "random-bytes@npm:1.0.0" @@ -36015,7 +27561,7 @@ __metadata: languageName: node linkType: hard -"randombytes@npm:^2.0.0, randombytes@npm:^2.0.1, randombytes@npm:^2.0.5, randombytes@npm:^2.1.0": +"randombytes@npm:^2.1.0": version: 2.1.0 resolution: "randombytes@npm:2.1.0" dependencies: @@ -36024,17 +27570,7 @@ __metadata: languageName: node linkType: hard -"randomfill@npm:^1.0.3": - version: 1.0.4 - resolution: "randomfill@npm:1.0.4" - dependencies: - randombytes: ^2.0.5 - safe-buffer: ^5.1.0 - checksum: 11aeed35515872e8f8a2edec306734e6b74c39c46653607f03c68385ab8030e2adcc4215f76b5e4598e028c4750d820afd5c65202527d831d2a5f207fe2bc87c - languageName: node - linkType: hard - -"range-parser@npm:^1.2.1, range-parser@npm:~1.2.1": +"range-parser@npm:~1.2.1": version: 1.2.1 resolution: "range-parser@npm:1.2.1" checksum: 96c032ac2475c8027b7a4e9fe22dc0dfe0f6d90b85e496e0f016fbdb99d6d066de0112e680805075bd989905e2123b3b3d002765149294dce0c1f7f01fcc2ea0 @@ -36053,18 +27589,6 @@ __metadata: languageName: node linkType: hard -"raw-body@npm:2.5.1": - version: 2.5.1 - resolution: "raw-body@npm:2.5.1" - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - checksum: 5dad5a3a64a023b894ad7ab4e5c7c1ce34d3497fc7138d02f8c88a3781e68d8a55aa7d4fd3a458616fa8647cc228be314a1c03fb430a07521de78b32c4dd09d2 - languageName: node - linkType: hard - "raw-body@npm:2.5.2": version: 2.5.2 resolution: "raw-body@npm:2.5.2" @@ -36077,30 +27601,6 @@ __metadata: languageName: node linkType: hard -"raw-loader@npm:^4.0.2": - version: 4.0.2 - resolution: "raw-loader@npm:4.0.2" - dependencies: - loader-utils: ^2.0.0 - schema-utils: ^3.0.0 - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: 981ebe65e1cee7230300d21ba6dcd8bd23ea81ef4ad2b167c0f62d93deba347f27921d330be848634baab3831cf9f38900af6082d6416c2e937fe612fa6a74ff - languageName: node - linkType: hard - -"react-base16-styling@npm:^0.6.0": - version: 0.6.0 - resolution: "react-base16-styling@npm:0.6.0" - dependencies: - base16: ^1.0.0 - lodash.curry: ^4.0.1 - lodash.flow: ^3.3.0 - pure-color: ^1.2.0 - checksum: 4887ac57b36fedc7e1ebc99ae431c5feb07d60a9150770d0ca3a59f4ae7059434ea8813ca4f915e7434d4d8d8529b9ba072ceb85041fd52ca1cd6289c57c9621 - languageName: node - linkType: hard - "react-colorful@npm:^5.1.2": version: 5.6.1 resolution: "react-colorful@npm:5.6.1" @@ -36121,25 +27621,25 @@ __metadata: linkType: hard "react-currency-input-field@npm:^3.6.11": - version: 3.6.11 - resolution: "react-currency-input-field@npm:3.6.11" + version: 3.8.0 + resolution: "react-currency-input-field@npm:3.8.0" peerDependencies: react: ^16.9.0 || ^17.0.0 || ^18.0.0 - checksum: d1a15dc14f572806917e452c77a2b69d00647676be578304624c98fe66e557a9f397a3ece72b997b2a8db827db236a5801f26b86605ef334398175c856e46d50 + checksum: d82d367933925c046d5434b29701874b5fd2298943b677747172a76e80c365c6cf86e79abe69b8b89e21bc2c85a7d36262092d4f9f3efee2d3bf9774ea7c7276 languageName: node linkType: hard "react-day-picker@npm:^8.8.0": - version: 8.8.0 - resolution: "react-day-picker@npm:8.8.0" + version: 8.10.1 + resolution: "react-day-picker@npm:8.10.1" peerDependencies: - date-fns: ^2.28.0 + date-fns: ^2.28.0 || ^3.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 635537efab411e4bd62d1965a970d2bcad543f2ecfe8789f96ee5580d9df61dba84528cace9861fba3a9e08b858a6f286a991ed830d7053f8af1acae8034a2ca + checksum: a0ff28c4b61b3882e6a825b19e5679e2fdf3256cf1be8eb0a0c028949815c1ae5a6561474c2c19d231c010c8e0e0b654d3a322610881e0655abca05a2e03d9df languageName: node linkType: hard -"react-docgen-typescript@npm:^2.1.1, react-docgen-typescript@npm:^2.2.2": +"react-docgen-typescript@npm:^2.2.2": version: 2.2.2 resolution: "react-docgen-typescript@npm:2.2.2" peerDependencies: @@ -36148,45 +27648,25 @@ __metadata: languageName: node linkType: hard -"react-docgen@npm:^5.0.0": - version: 5.4.3 - resolution: "react-docgen@npm:5.4.3" - dependencies: - "@babel/core": ^7.7.5 - "@babel/generator": ^7.12.11 - "@babel/runtime": ^7.7.6 - ast-types: ^0.14.2 - commander: ^2.19.0 - doctrine: ^3.0.0 - estree-to-babel: ^3.1.0 - neo-async: ^2.6.1 - node-dir: ^0.1.10 - strip-indent: ^3.0.0 - bin: - react-docgen: bin/react-docgen.js - checksum: c920e9611e08317f8fdae707114cf02baaa18e2f1bd23ed18f57e66b9e1042e51dc98cc9de828b03d018ccc4e26300c9a6c4f74e862fc94dc64029267c801a01 - languageName: node - linkType: hard - -"react-docgen@npm:^6.0.2": - version: 6.0.4 - resolution: "react-docgen@npm:6.0.4" +"react-docgen@npm:^7.0.0": + version: 7.0.3 + resolution: "react-docgen@npm:7.0.3" dependencies: "@babel/core": ^7.18.9 "@babel/traverse": ^7.18.9 "@babel/types": ^7.18.9 "@types/babel__core": ^7.18.0 "@types/babel__traverse": ^7.18.0 - "@types/doctrine": ^0.0.6 + "@types/doctrine": ^0.0.9 "@types/resolve": ^1.20.2 doctrine: ^3.0.0 resolve: ^1.22.1 strip-indent: ^4.0.0 - checksum: 6e372de705b0ce576c8a46c8aedaea3f584441b18d68c02128f14e20657597fe088c80bb67374d5057001f71505924e07d6e366ec8d768e2456d47395bd32066 + checksum: 74622750e60b287d2897a6887a2bd88303fadd84540247e162e9e970430864ae7b49152de043233d873a0aa7cffa406e5cd8fc1e8e2c277b8da73198b570f16b languageName: node linkType: hard -"react-dom@npm:^17.0.1, react-dom@npm:^17.0.2": +"react-dom@npm:^17.0.1": version: 17.0.2 resolution: "react-dom@npm:17.0.2" dependencies: @@ -36200,28 +27680,14 @@ __metadata: linkType: hard "react-dom@npm:^18.2.0": - version: 18.2.0 - resolution: "react-dom@npm:18.2.0" + version: 18.3.1 + resolution: "react-dom@npm:18.3.1" dependencies: loose-envify: ^1.1.0 - scheduler: ^0.23.0 + scheduler: ^0.23.2 peerDependencies: - react: ^18.2.0 - checksum: 66dfc5f93e13d0674e78ef41f92ed21dfb80f9c4ac4ac25a4b51046d41d4d2186abc915b897f69d3d0ebbffe6184e7c5876f2af26bfa956f179225d921be713a - languageName: node - linkType: hard - -"react-element-to-jsx-string@npm:^14.3.4": - version: 14.3.4 - resolution: "react-element-to-jsx-string@npm:14.3.4" - dependencies: - "@base2/pretty-print-object": 1.0.1 - is-plain-object: 5.0.0 - react-is: 17.0.2 - peerDependencies: - react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 - react-dom: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 - checksum: 4ead664b2e26e76af57c9ce2f2a46e79fda1d3a408afb5f34d03357d195b7f41a1a86bb9286b6d6ba76c9c2611fe56bc038665cf27fdb56f571d235ddfce9ffb + react: ^18.3.1 + checksum: a752496c1941f958f2e8ac56239172296fcddce1365ce45222d04a1947e0cc5547df3e8447f855a81d6d39f008d7c32eab43db3712077f09e3f67c4874973e85 languageName: node linkType: hard @@ -36239,17 +27705,6 @@ __metadata: languageName: node linkType: hard -"react-error-boundary@npm:^3.1.0": - version: 3.1.4 - resolution: "react-error-boundary@npm:3.1.4" - dependencies: - "@babel/runtime": ^7.12.5 - peerDependencies: - react: ">=16.13.1" - checksum: f977ca61823e43de2381d53dd7aa8b4d79ff6a984c9afdc88dc44f9973b99de7fd382d2f0f91f2688e24bb987c0185bf45d0b004f22afaaab0f990a830253bfb - languageName: node - linkType: hard - "react-hook-form@npm:7.49.1": version: 7.49.1 resolution: "react-hook-form@npm:7.49.1" @@ -36277,35 +27732,6 @@ __metadata: languageName: node linkType: hard -"react-inspector@npm:^5.1.0": - version: 5.1.1 - resolution: "react-inspector@npm:5.1.1" - dependencies: - "@babel/runtime": ^7.0.0 - is-dom: ^1.0.0 - prop-types: ^15.0.0 - peerDependencies: - react: ^16.8.4 || ^17.0.0 - checksum: 64282953f1e9318501ae9ff64dc955845fce0b543577fcc5b6a5cf786d9a1872edadc5df5821d830a8510ecf629e9a220b323e5cd45b091508939f71ea332239 - languageName: node - linkType: hard - -"react-inspector@npm:^6.0.0": - version: 6.0.2 - resolution: "react-inspector@npm:6.0.2" - peerDependencies: - react: ^16.8.4 || ^17.0.0 || ^18.0.0 - checksum: 8f9b23c21b4d95722e28c9455c2bf00fd9437347714382594461f98e5b9954d60864d0f4e74e881639b065e752a97ba52a65e39930c234072e5bff291bb02b5e - languageName: node - linkType: hard - -"react-is@npm:17.0.2, react-is@npm:^17.0.1, react-is@npm:^17.0.2": - version: 17.0.2 - resolution: "react-is@npm:17.0.2" - checksum: 2bdb6b93fbb1820b024b496042cce405c57e2f85e777c9aabd55f9b26d145408f9f74f5934676ffdc46f3dcff656d78413a6e43968e7b3f92eea35b3052e9053 - languageName: node - linkType: hard - "react-is@npm:18.1.0": version: 18.1.0 resolution: "react-is@npm:18.1.0" @@ -36320,31 +27746,23 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^18.0.0": - version: 18.2.0 - resolution: "react-is@npm:18.2.0" - checksum: 6eb5e4b28028c23e2bfcf73371e72cd4162e4ac7ab445ddae2afe24e347a37d6dc22fae6e1748632cd43c6d4f9b8f86dcf26bf9275e1874f436d129952528ae0 +"react-is@npm:^17.0.1": + version: 17.0.2 + resolution: "react-is@npm:17.0.2" + checksum: 2bdb6b93fbb1820b024b496042cce405c57e2f85e777c9aabd55f9b26d145408f9f74f5934676ffdc46f3dcff656d78413a6e43968e7b3f92eea35b3052e9053 languageName: node linkType: hard -"react-json-view@npm:^1.21.3": - version: 1.21.3 - resolution: "react-json-view@npm:1.21.3" - dependencies: - flux: ^4.0.1 - react-base16-styling: ^0.6.0 - react-lifecycles-compat: ^3.0.4 - react-textarea-autosize: ^8.3.2 - peerDependencies: - react: ^17.0.0 || ^16.3.0 || ^15.5.4 - react-dom: ^17.0.0 || ^16.3.0 || ^15.5.4 - checksum: f41b38e599f148cf922f60390e56bb821f17a091373b08310fd82ebc526428683011751aa023687041481a46b20aeb1c47f660979d43db77674486aec9dc1d3f +"react-is@npm:^18.0.0": + version: 18.3.1 + resolution: "react-is@npm:18.3.1" + checksum: f2f1e60010c683479e74c63f96b09fb41603527cd131a9959e2aee1e5a8b0caf270b365e5ca77d4a6b18aae659b60a86150bb3979073528877029b35aecd2072 languageName: node linkType: hard "react-jwt@npm:^1.2.0": - version: 1.2.0 - resolution: "react-jwt@npm:1.2.0" + version: 1.2.1 + resolution: "react-jwt@npm:1.2.1" dependencies: fsevents: ^2.3.2 peerDependencies: @@ -36352,34 +27770,20 @@ __metadata: dependenciesMeta: fsevents: optional: true - checksum: f674416ae044a5f911d81785d8d07c061406be671029f7995b4576c7446cd317b077c0a70fbaa59b416dcfd235c9c3b11f114c3c4a75e4d9a2b3cff63205fae8 - languageName: node - linkType: hard - -"react-lifecycles-compat@npm:^3.0.4": - version: 3.0.4 - resolution: "react-lifecycles-compat@npm:3.0.4" - checksum: 1d0df3c85af79df720524780f00c064d53a9dd1899d785eddb7264b378026979acbddb58a4b7e06e7d0d12aa1494fd5754562ee55d32907b15601068dae82c27 - languageName: node - linkType: hard - -"react-refresh@npm:^0.11.0": - version: 0.11.0 - resolution: "react-refresh@npm:0.11.0" - checksum: cbb5616c7ba670bbd2f37ddadcdfefa66e727ea188e89733ccb8184d3b874631104b0bc016d5676a7ade4d9c79100b99b46b6ed10cd117ab5d1ddcbf8653a9f2 + checksum: cbe27de003233f42126cb55ad6e8f368cc67d477f0b316afab2f9750f66b5f0b65703f682f6e2f85149427aa74c4674f548e64707fdfcbbf7146fec0659b8324 languageName: node linkType: hard "react-refresh@npm:^0.14.0": - version: 0.14.0 - resolution: "react-refresh@npm:0.14.0" - checksum: b8ae07ad153357d77830928a7f1fc2df837aabefee907fa273ba04c7643f3b860e986f1d4b7ada9b721c8d79b8c24b5b911a314a1a2398b105f1b13d19ea2b8d + version: 0.14.2 + resolution: "react-refresh@npm:0.14.2" + checksum: 875b72ef56b147a131e33f2abd6ec059d1989854b3ff438898e4f9310bfcc73acff709445b7ba843318a953cb9424bcc2c05af2b3d80011cee28f25aef3e2ebb languageName: node linkType: hard "react-remove-scroll-bar@npm:^2.3.3": - version: 2.3.4 - resolution: "react-remove-scroll-bar@npm:2.3.4" + version: 2.3.6 + resolution: "react-remove-scroll-bar@npm:2.3.6" dependencies: react-style-singleton: ^2.2.1 tslib: ^2.0.0 @@ -36389,7 +27793,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 2262750dc1022c56d2c79e8d865c00045881c57bcaca74810ae8adac35cfdf723ff7d6b3b0e95c85eb9a0cff90bb4b1e0af801bd703ce8c0a2e35ab14ff1babb + checksum: 4e32ee04bf655a8bd3b4aacf6ffc596ae9eb1b9ba27eef83f7002632ee75371f61516ae62250634a9eae4b2c8fc6f6982d9b182de260f6c11841841e6e2e7515 languageName: node linkType: hard @@ -36432,12 +27836,12 @@ __metadata: linkType: hard "react-resizable-panels@npm:^2.0.16": - version: 2.0.16 - resolution: "react-resizable-panels@npm:2.0.16" + version: 2.0.19 + resolution: "react-resizable-panels@npm:2.0.19" peerDependencies: react: ^16.14.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 - checksum: 91e125a10de5908cdca9c82247106927a98a2686097cca5aa31415d3ba7013425f3b3c10f1465eadcc6a4977a2d549cabadb71c58586cddfae4995c8bb575ace + checksum: eb9cb511aec917895dba842cb933c9885ea510f752b4f3b8c358bf33be8b7b6bf2fc4a81db7a16977e6b09f614a14c6652f15232ff03bce68a8845dcf179abf7 languageName: node linkType: hard @@ -36494,20 +27898,7 @@ __metadata: languageName: node linkType: hard -"react-textarea-autosize@npm:^8.3.2": - version: 8.5.1 - resolution: "react-textarea-autosize@npm:8.5.1" - dependencies: - "@babel/runtime": ^7.20.13 - use-composed-ref: ^1.3.0 - use-latest: ^1.2.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 991157ca70c04e6d412d71ffe9419f0fd12b568ec96985ec1da98b25391283062009206212e4c4978f3e777134e6330f2a7af3154548a1976ce7534aad169004 - languageName: node - linkType: hard - -"react@npm:^17.0.1, react@npm:^17.0.2": +"react@npm:^17.0.1": version: 17.0.2 resolution: "react@npm:17.0.2" dependencies: @@ -36518,11 +27909,11 @@ __metadata: linkType: hard "react@npm:^18.2.0": - version: 18.2.0 - resolution: "react@npm:18.2.0" + version: 18.3.1 + resolution: "react@npm:18.3.1" dependencies: loose-envify: ^1.1.0 - checksum: b562d9b569b0cb315e44b48099f7712283d93df36b19a39a67c254c6686479d3980b7f013dc931f4a5a3ae7645eae6386b4aa5eea933baa54ecd0f9acb0902b8 + checksum: 283e8c5efcf37802c9d1ce767f302dd569dd97a70d9bb8c7be79a789b9902451e0d16334b05d73299b20f048cbc3c7d288bbbde10b701fa194e2089c237dbea3 languageName: node linkType: hard @@ -36535,16 +27926,6 @@ __metadata: languageName: node linkType: hard -"read-pkg-up@npm:^1.0.1": - version: 1.0.1 - resolution: "read-pkg-up@npm:1.0.1" - dependencies: - find-up: ^1.0.0 - read-pkg: ^1.0.0 - checksum: 36c4fc8bd73edf77a4eeb497b6e43010819ea4aef64cbf8e393439fac303398751c5a299feab84e179a74507e3a1416e1ed033a888b1dac3463bf46d1765f7ac - languageName: node - linkType: hard - "read-pkg-up@npm:^7.0.1": version: 7.0.1 resolution: "read-pkg-up@npm:7.0.1" @@ -36556,17 +27937,6 @@ __metadata: languageName: node linkType: hard -"read-pkg@npm:^1.0.0": - version: 1.1.0 - resolution: "read-pkg@npm:1.1.0" - dependencies: - load-json-file: ^1.0.0 - normalize-package-data: ^2.3.2 - path-type: ^1.0.0 - checksum: 51fce9f7066787dc7688ea7014324cedeb9f38daa7dace4f1147d526f22354a07189ef728710bc97e27fcf5ed3a03b68ad8b60afb4251984640b6f09c180d572 - languageName: node - linkType: hard - "read-pkg@npm:^5.2.0": version: 5.2.0 resolution: "read-pkg@npm:5.2.0" @@ -36591,7 +27961,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:1 || 2, readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.1, readable-stream@npm:^2.0.2, readable-stream@npm:^2.1.5, readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.3, readable-stream@npm:^2.3.5, readable-stream@npm:^2.3.6, readable-stream@npm:~2.3.6": +"readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.2, readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.5, readable-stream@npm:~2.3.6": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -36651,28 +28021,16 @@ __metadata: languageName: node linkType: hard -"recast@npm:^0.21.0": - version: 0.21.5 - resolution: "recast@npm:0.21.5" +"recast@npm:^0.23.1, recast@npm:^0.23.3": + version: 0.23.6 + resolution: "recast@npm:0.23.6" dependencies: - ast-types: 0.15.2 - esprima: ~4.0.0 - source-map: ~0.6.1 - tslib: ^2.0.1 - checksum: a45168c82195f24fa2c70293a624fece0069a2e8e8adb637f9963777735f81cb3bb62e55172db677ec3573b08b2daaf1eddd85b74da6fe0bd37c9b15eeaf94b4 - languageName: node - linkType: hard - -"recast@npm:^0.23.1": - version: 0.23.4 - resolution: "recast@npm:0.23.4" - dependencies: - assert: ^2.0.0 ast-types: ^0.16.1 esprima: ~4.0.0 source-map: ~0.6.1 + tiny-invariant: ^1.3.3 tslib: ^2.0.1 - checksum: d719633be8029e28f23b8191d4a525c5dbdac721792ab3cb5e9dfcf1694fb93f3c147b186916195a9c7fa0711f1e4990ba457cdcee02faed3899d4a80da1bd1f + checksum: 589c1a96aea7656a844f56278ffe99e3360717991955e9409221f2c1582a922f8179c803c8d35ca61743facfa0ad895acfe73dcc76076e0717db04c508166d44 languageName: node linkType: hard @@ -36685,16 +28043,6 @@ __metadata: languageName: node linkType: hard -"redent@npm:^1.0.0": - version: 1.0.0 - resolution: "redent@npm:1.0.0" - dependencies: - indent-string: ^2.1.0 - strip-indent: ^1.0.1 - checksum: 9fa48d250d4e645acac9de57cb82dc29cd7f5f27257ec367461e3dd0c9f14c55f1c40fd3d9cf7f9a3ed337f209ad4e0370abfcf5cf75569ebd31c97a7949b8a2 - languageName: node - linkType: hard - "redent@npm:^3.0.0": version: 3.0.0 resolution: "redent@npm:3.0.0" @@ -36731,29 +28079,30 @@ __metadata: linkType: hard "redoc@npm:~2.1.3": - version: 2.1.3 - resolution: "redoc@npm:2.1.3" + version: 2.1.4 + resolution: "redoc@npm:2.1.4" dependencies: - "@redocly/openapi-core": ^1.0.0-rc.2 - classnames: ^2.3.1 + "@redocly/openapi-core": ^1.4.0 + classnames: ^2.3.2 decko: ^1.2.0 - dompurify: ^2.2.8 - eventemitter3: ^4.0.7 + dompurify: ^3.0.6 + eventemitter3: ^5.0.1 + jest-environment-jsdom: ^29.7.0 json-pointer: ^0.6.2 lunr: ^2.3.9 mark.js: ^8.11.1 - marked: ^4.0.15 + marked: ^4.3.0 mobx-react: ^7.2.0 - openapi-sampler: ^1.3.1 + openapi-sampler: ^1.5.0 path-browserify: ^1.0.1 perfect-scrollbar: ^1.5.5 - polished: ^4.1.3 - prismjs: ^1.27.0 - prop-types: ^15.7.2 + polished: ^4.2.2 + prismjs: ^1.29.0 + prop-types: ^15.8.1 react-tabs: ^4.3.0 slugify: ~1.4.7 stickyfill: ^1.1.1 - swagger2openapi: ^7.0.6 + swagger2openapi: ^7.0.8 url-template: ^2.0.8 peerDependencies: core-js: ^3.1.4 @@ -36761,17 +28110,46 @@ __metadata: react: ^16.8.4 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.4 || ^17.0.0 || ^18.0.0 styled-components: ^4.1.1 || ^5.1.1 || ^6.0.5 - checksum: 5a240b52635f6ce3bc3a631ca837ac69bea5cb537941182ce723cb2f109022ffd14b01ab8152757c77fdf2afdcd4612aee5594b9870446d4cffd5b0904e725d7 + checksum: f5510d88b8969d85ea9133a3c891db0c061b79328427203eb8f4f10a31f0f5ec818ae019d65d3b914f456feb8fc6ded6bf8ed1f0eccfa3dcf4651e7958474e4c languageName: node linkType: hard -"reflect-metadata@npm:0.1.13, reflect-metadata@npm:^0.1.13": +"reflect-metadata@npm:0.1.13": version: 0.1.13 resolution: "reflect-metadata@npm:0.1.13" checksum: 728bff0b376b05639fd11ed80c648b61f7fe653c5b506d7ca118e58b6752b9b00810fe0c86227ecf02bd88da6251ab3eb19fd403aaf2e9ff5ef36a2fda643026 languageName: node linkType: hard +"reflect-metadata@npm:^0.1.13": + version: 0.1.14 + resolution: "reflect-metadata@npm:0.1.14" + checksum: 3a6190c7f6cb224f26a012d11f9e329360c01c1945e2cbefea23976a8bacf9db6b794aeb5bf18adcb673c448a234fbc06fc41853c00a6c206b30f0777ecf019e + languageName: node + linkType: hard + +"reflect-metadata@npm:^0.2.1": + version: 0.2.2 + resolution: "reflect-metadata@npm:0.2.2" + checksum: 1cd93a15ea291e420204955544637c264c216e7aac527470e393d54b4bb075f10a17e60d8168ec96600c7e0b9fcc0cb0bb6e91c3fbf5b0d8c9056f04e6ac1ec2 + languageName: node + linkType: hard + +"reflect.getprototypeof@npm:^1.0.4": + version: 1.0.6 + resolution: "reflect.getprototypeof@npm:1.0.6" + dependencies: + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.1 + es-errors: ^1.3.0 + get-intrinsic: ^1.2.4 + globalthis: ^1.0.3 + which-builtin-type: ^1.1.3 + checksum: baf4ef8ee6ff341600f4720b251cf5a6cb552d6a6ab0fdc036988c451bf16f920e5feb0d46bd4f530a5cce568f1f7aca2d77447ca798920749cfc52783c39b55 + languageName: node + linkType: hard + "reftools@npm:^1.1.9": version: 1.1.9 resolution: "reftools@npm:1.1.9" @@ -36780,11 +28158,11 @@ __metadata: linkType: hard "regenerate-unicode-properties@npm:^10.1.0": - version: 10.1.0 - resolution: "regenerate-unicode-properties@npm:10.1.0" + version: 10.1.1 + resolution: "regenerate-unicode-properties@npm:10.1.1" dependencies: regenerate: ^1.4.2 - checksum: 17818ea6f67c5a4884b9e18842edc4b3838a12f62e24f843e80fbb6d8cb649274b5b86d98bb02075074e02021850e597a92ff6b58bbe5caba4bf5fd8e4e38b56 + checksum: 89adb5ee5ba081380c78f9057c02e156a8181969f6fcca72451efc45612e0c3df767b4333f8d8479c274d9c6fe52ec4854f0d8a22ef95dccbe87da8e5f2ac77d languageName: node linkType: hard @@ -36795,7 +28173,7 @@ __metadata: languageName: node linkType: hard -"regenerator-runtime@npm:^0.13.11, regenerator-runtime@npm:^0.13.7": +"regenerator-runtime@npm:^0.13.11": version: 0.13.11 resolution: "regenerator-runtime@npm:0.13.11" checksum: 12b069dc774001fbb0014f6a28f11c09ebfe3c0d984d88c9bced77fdb6fedbacbca434d24da9ae9371bfbf23f754869307fb51a4c98a8b8b18e5ef748677ca24 @@ -36803,18 +28181,9 @@ __metadata: linkType: hard "regenerator-runtime@npm:^0.14.0": - version: 0.14.0 - resolution: "regenerator-runtime@npm:0.14.0" - checksum: e25f062c1a183f81c99681691a342760e65c55e8d3a4d4fe347ebe72433b123754b942b70b622959894e11f8a9131dc549bd3c9a5234677db06a4af42add8d12 - languageName: node - linkType: hard - -"regenerator-transform@npm:^0.15.1": - version: 0.15.1 - resolution: "regenerator-transform@npm:0.15.1" - dependencies: - "@babel/runtime": ^7.8.4 - checksum: 6588e0c454e92ed6c2b3ed7ab24f61270aef47ae7052eceb5367cc15658948a2e84fdd6849f7c96e561d1f8a7474dc4c292166792e07498fdde226299b9ff374 + version: 0.14.1 + resolution: "regenerator-runtime@npm:0.14.1" + checksum: 1b16eb2c4bceb1665c89de70dcb64126a22bc8eb958feef3cd68fe11ac6d2a4899b5cd1b80b0774c7c03591dc57d16631a7f69d2daa2ec98100e2f29f7ec4cc4 languageName: node linkType: hard @@ -36838,20 +28207,21 @@ __metadata: linkType: hard "regex-parser@npm:^2.2.11": - version: 2.2.11 - resolution: "regex-parser@npm:2.2.11" - checksum: 6572acbd46b5444215a73cf164f3c6fdbd73b8a2cde6a31a97307e514d20f5cbb8609f9e4994a7744207f2d1bf9e6fca4bbc0c9854f2b3da77ae0063efdc3f98 + version: 2.3.0 + resolution: "regex-parser@npm:2.3.0" + checksum: de31c40e9d982735fdf5934c822cc5cafbe6a0f0909d9fef52e2bd4cc2198933c89fd5e7a17697f25591fdb5df386a088296612b45f0f8e194222070fc5b5cc7 languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.4.3, regexp.prototype.flags@npm:^1.5.0": - version: 1.5.0 - resolution: "regexp.prototype.flags@npm:1.5.0" +"regexp.prototype.flags@npm:^1.5.1, regexp.prototype.flags@npm:^1.5.2": + version: 1.5.2 + resolution: "regexp.prototype.flags@npm:1.5.2" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.2.0 - functions-have-names: ^1.2.3 - checksum: 312b7966c5cd2e6837da4073e0e6450191e3c6e8f07276cbed35e170ea5606f91487b435eb3290593f8aed39b1191c44f5340e6e5392650feaf2b34a98378464 + call-bind: ^1.0.6 + define-properties: ^1.2.1 + es-errors: ^1.3.0 + set-function-name: ^2.0.1 + checksum: 0f3fc4f580d9c349f8b560b012725eb9c002f36daa0041b3fbf6f4238cb05932191a4d7d5db3b5e2caa336d5150ad0402ed2be81f711f9308fe7e1a9bf9bd552 languageName: node linkType: hard @@ -36887,13 +28257,6 @@ __metadata: languageName: node linkType: hard -"relateurl@npm:^0.2.7": - version: 0.2.7 - resolution: "relateurl@npm:0.2.7" - checksum: c248b4e3b32474f116a804b537fa6343d731b80056fb506dffd91e737eef4cac6be47a65aae39b522b0db9d0b1011d1a12e288d82a109ecd94a5299d82f6573a - languageName: node - linkType: hard - "remark-external-links@npm:^8.0.0": version: 8.0.0 resolution: "remark-external-links@npm:8.0.0" @@ -36907,53 +28270,6 @@ __metadata: languageName: node linkType: hard -"remark-footnotes@npm:2.0.0": - version: 2.0.0 - resolution: "remark-footnotes@npm:2.0.0" - checksum: 45b55b3440b74bfeed11fba5ed6b31f2fd35ab4e9ba169061b76a19f5ff4d16d851c9f3c423c7fa54eb0fa5e6043b89098cb9478e9b5b417cf4bdef5571b0236 - languageName: node - linkType: hard - -"remark-mdx@npm:1.6.22": - version: 1.6.22 - resolution: "remark-mdx@npm:1.6.22" - dependencies: - "@babel/core": 7.12.9 - "@babel/helper-plugin-utils": 7.10.4 - "@babel/plugin-proposal-object-rest-spread": 7.12.1 - "@babel/plugin-syntax-jsx": 7.12.1 - "@mdx-js/util": 1.6.22 - is-alphabetical: 1.0.4 - remark-parse: 8.0.3 - unified: 9.2.0 - checksum: 3a964048e58cba7848d59fc920baa330a9b7f619fedb44d4d7985d84875eba8d92e0d0dd0617e28326c6086e21ef441664748526a2517a42555d44c648453b0a - languageName: node - linkType: hard - -"remark-parse@npm:8.0.3": - version: 8.0.3 - resolution: "remark-parse@npm:8.0.3" - dependencies: - ccount: ^1.0.0 - collapse-white-space: ^1.0.2 - is-alphabetical: ^1.0.0 - is-decimal: ^1.0.0 - is-whitespace-character: ^1.0.0 - is-word-character: ^1.0.0 - markdown-escapes: ^1.0.0 - parse-entities: ^2.0.0 - repeat-string: ^1.5.4 - state-toggle: ^1.0.0 - trim: 0.0.1 - trim-trailing-lines: ^1.0.0 - unherit: ^1.0.4 - unist-util-remove-position: ^2.0.0 - vfile-location: ^3.0.0 - xtend: ^4.0.1 - checksum: cbb859e2585864942823ce4d23a1b1514168a066ba91d47ca09ff45a5563b81bf17160c182ac7efed718712291c35a117db89b6ce603d04a845497ae7041c185 - languageName: node - linkType: hard - "remark-slug@npm:^6.0.0": version: 6.1.0 resolution: "remark-slug@npm:6.1.0" @@ -36965,15 +28281,6 @@ __metadata: languageName: node linkType: hard -"remark-squeeze-paragraphs@npm:4.0.0": - version: 4.0.0 - resolution: "remark-squeeze-paragraphs@npm:4.0.0" - dependencies: - mdast-squeeze-paragraphs: ^4.0.0 - checksum: 61b39acfde3bebb1e9364a6991957f83ab0d878c0fd1de0e86e9bf9e060574cefb7a76057d64e7422e2a2bcf6e3c54635a4ae43f00b3dda38812ae4b6f4342f4 - languageName: node - linkType: hard - "remove-accents@npm:0.5.0": version: 0.5.0 resolution: "remove-accents@npm:0.5.0" @@ -36995,19 +28302,6 @@ __metadata: languageName: node linkType: hard -"renderkid@npm:^2.0.4": - version: 2.0.7 - resolution: "renderkid@npm:2.0.7" - dependencies: - css-select: ^4.1.3 - dom-converter: ^0.2.0 - htmlparser2: ^6.1.0 - lodash: ^4.17.21 - strip-ansi: ^3.0.1 - checksum: 05e19c8861e0f9f3d379a175fbb52e3be3c957022acf52d19d36b23f99bb401b6bc3c493d43213f4d76efb08cb2f13e66df38c9a487249cb8dad1f6170da6a14 - languageName: node - linkType: hard - "repeat-element@npm:^1.1.2": version: 1.1.4 resolution: "repeat-element@npm:1.1.4" @@ -37015,22 +28309,13 @@ __metadata: languageName: node linkType: hard -"repeat-string@npm:^1.5.4, repeat-string@npm:^1.6.1": +"repeat-string@npm:^1.6.1": version: 1.6.1 resolution: "repeat-string@npm:1.6.1" checksum: 87fa21bfdb2fbdedc44b9a5b118b7c1239bdd2c2c1e42742ef9119b7d412a5137a1d23f1a83dc6bb686f4f27429ac6f542e3d923090b44181bafa41e8ac0174d languageName: node linkType: hard -"repeating@npm:^2.0.0": - version: 2.0.1 - resolution: "repeating@npm:2.0.1" - dependencies: - is-finite: ^1.0.0 - checksum: 7f5cd293ec47d9c074ef0852800d5ff5c49028ce65242a7528d84f32bd2fe200b142930562af58c96d869c5a3046e87253030058e45231acaa129c1a7087d2e7 - languageName: node - linkType: hard - "request-ip@npm:^3.3.0": version: 3.3.0 resolution: "request-ip@npm:3.3.0" @@ -37240,20 +28525,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.7, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.18.1, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.3.2": - version: 1.22.3 - resolution: "resolve@npm:1.22.3" - dependencies: - is-core-module: ^2.12.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: 5ebd90dc08467e7d9af8f89a67f127c90d77e58d3bfc65da5221699cc15679c5bae5e410e6795ee4b9f717cd711c495a52a3b650ce6720b0626de46e5074e796 - languageName: node - linkType: hard - -"resolve@npm:^1.22.2": +"resolve@npm:^1.1.7, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.18.1, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.2, resolve@npm:~1.22.1": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -37266,16 +28538,16 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^2.0.0-next.4": - version: 2.0.0-next.4 - resolution: "resolve@npm:2.0.0-next.4" +"resolve@npm:^2.0.0-next.5": + version: 2.0.0-next.5 + resolution: "resolve@npm:2.0.0-next.5" dependencies: - is-core-module: ^2.9.0 + is-core-module: ^2.13.0 path-parse: ^1.0.7 supports-preserve-symlinks-flag: ^1.0.0 bin: resolve: bin/resolve - checksum: 1de92669e7c46cfe125294c66d5405e13288bb87b97e9bdab71693ceebbcc0255c789bde30e2834265257d330d8ff57414d7d88e3097d8f69951f3ce978bf045 + checksum: a6c33555e3482ea2ec4c6e3d3bf0d78128abf69dca99ae468e64f1e30acaa318fd267fb66c8836b04d558d3e2d6ed875fe388067e7d8e0de647d3c21af21c43a languageName: node linkType: hard @@ -37295,20 +28567,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.18.1#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.3.2#~builtin": - version: 1.22.3 - resolution: "resolve@patch:resolve@npm%3A1.22.3#~builtin::version=1.22.3&hash=07638b" - dependencies: - is-core-module: ^2.12.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: 6267bdbbbb1da23975463e979dadf5135fcc40c4b9281c5af4581afa848ced98090ab4e2dbc9085e58f8ea48c0eb7c4fe94b1e8f55ebdd17a725d86982eb5288 - languageName: node - linkType: hard - -"resolve@patch:resolve@^1.22.2#~builtin": +"resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.18.1#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.2#~builtin, resolve@patch:resolve@~1.22.1#~builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=07638b" dependencies: @@ -37321,16 +28580,16 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^2.0.0-next.4#~builtin": - version: 2.0.0-next.4 - resolution: "resolve@patch:resolve@npm%3A2.0.0-next.4#~builtin::version=2.0.0-next.4&hash=07638b" +"resolve@patch:resolve@^2.0.0-next.5#~builtin": + version: 2.0.0-next.5 + resolution: "resolve@patch:resolve@npm%3A2.0.0-next.5#~builtin::version=2.0.0-next.5&hash=07638b" dependencies: - is-core-module: ^2.9.0 + is-core-module: ^2.13.0 path-parse: ^1.0.7 supports-preserve-symlinks-flag: ^1.0.0 bin: resolve: bin/resolve - checksum: ed2bb51d616b9cd30fe85cf49f7a2240094d9fa01a221d361918462be81f683d1855b7f192391d2ab5325245b42464ca59690db5bd5dad0a326fc0de5974dd10 + checksum: 78ad6edb8309a2bfb720c2c1898f7907a37f858866ce11a5974643af1203a6a6e05b2fa9c53d8064a673a447b83d42569260c306d43628bff5bb101969708355 languageName: node linkType: hard @@ -37394,13 +28653,13 @@ __metadata: linkType: hard "rfdc@npm:^1.3.0": - version: 1.3.0 - resolution: "rfdc@npm:1.3.0" - checksum: a17fd7b81f42c7ae4cb932abd7b2f677b04cc462a03619fb46945ae1ccae17c3bc87c020ffdde1751cbfa8549860a2883486fdcabc9b9de3f3108af32b69a667 + version: 1.3.1 + resolution: "rfdc@npm:1.3.1" + checksum: 69f65e3ed30970f8055fac9fbbef9ce578800ca19554eab1dcbffe73a4b8aef536bc4248313889cf25e3b4e38b212c721eabe30856575bf2b2bc3d90f8ba93ef languageName: node linkType: hard -"rimraf@npm:5.0.1, rimraf@npm:^5.0.1": +"rimraf@npm:5.0.1": version: 5.0.1 resolution: "rimraf@npm:5.0.1" dependencies: @@ -37411,7 +28670,7 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:^2.5.4, rimraf@npm:^2.6.1, rimraf@npm:^2.6.3": +"rimraf@npm:^2.6.1": version: 2.7.1 resolution: "rimraf@npm:2.7.1" dependencies: @@ -37433,6 +28692,17 @@ __metadata: languageName: node linkType: hard +"rimraf@npm:^5.0.1": + version: 5.0.5 + resolution: "rimraf@npm:5.0.5" + dependencies: + glob: ^10.3.7 + bin: + rimraf: dist/esm/bin.mjs + checksum: d50dbe724f33835decd88395b25ed35995077c60a50ae78ded06e0185418914e555817aad1b4243edbff2254548c2f6ad6f70cc850040bebb4da9e8cc016f586 + languageName: node + linkType: hard + "rimraf@npm:~2.4.0": version: 2.4.5 resolution: "rimraf@npm:2.4.5" @@ -37455,16 +28725,6 @@ __metadata: languageName: node linkType: hard -"ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1": - version: 2.0.2 - resolution: "ripemd160@npm:2.0.2" - dependencies: - hash-base: ^3.0.0 - inherits: ^2.0.1 - checksum: f6f0df78817e78287c766687aed4d5accbebc308a8e7e673fb085b9977473c1f139f0c5335d353f172a915bb288098430755d2ad3c4f30612f4dd0c901cd2c3a - languageName: node - linkType: hard - "rollup-plugin-bundle-size@npm:^1.0.3": version: 1.0.3 resolution: "rollup-plugin-bundle-size@npm:1.0.3" @@ -37492,21 +28752,21 @@ __metadata: linkType: hard "rollup-plugin-license@npm:^3.0.1": - version: 3.2.0 - resolution: "rollup-plugin-license@npm:3.2.0" + version: 3.3.1 + resolution: "rollup-plugin-license@npm:3.3.1" dependencies: commenting: ~1.1.0 glob: ~7.2.0 lodash: ~4.17.21 magic-string: ~0.30.0 mkdirp: ~3.0.0 - moment: ~2.29.3 + moment: ~2.30.1 package-name-regex: ~2.0.6 spdx-expression-validate: ~2.0.0 spdx-satisfies: ~5.0.1 peerDependencies: rollup: ^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 - checksum: fea97faadc037d3799f067356d97b22c235cd47943a1d6626a0639e810db42f52c325f9063e9eb64bc24b14bc29cc110c37e3aa2ddc2de61bb3b3b141df62e5d + checksum: affa9cb1284a2884b20e76e2d8e76585d6e4c72d2358517f4eee72b4905b7ef8dd7b0d34bacabfc72199cde072e54519895da098e7e1c9f8759b82c9f8571bd6 languageName: node linkType: hard @@ -37607,21 +28867,21 @@ __metadata: linkType: hard "rollup-plugin-visualizer@npm:^5.9.2": - version: 5.9.2 - resolution: "rollup-plugin-visualizer@npm:5.9.2" + version: 5.12.0 + resolution: "rollup-plugin-visualizer@npm:5.12.0" dependencies: open: ^8.4.0 picomatch: ^2.3.1 source-map: ^0.7.4 yargs: ^17.5.1 peerDependencies: - rollup: 2.x || 3.x + rollup: 2.x || 3.x || 4.x peerDependenciesMeta: rollup: optional: true bin: rollup-plugin-visualizer: dist/bin/cli.js - checksum: e6280bed797084e9f9ee06726e46706e32854fc7647c5c5bcec68a9be8ca8e6fbf7f8a0b2f76255e9df72e84135a7d57eb2662b6cfd68496a1ef60fa33597eaf + checksum: 0e44a641223377ebb472bb10f2b22efa773b5f6fbe8d54f197f07c68d7a432cbf00abad79a0aa1570f70c673c792f24700d926d663ed9a4d0ad8406ae5a0f4e4 languageName: node linkType: hard @@ -37648,7 +28908,7 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^2.25.0 || ^3.3.0, rollup@npm:^3.26.0, rollup@npm:^3.27.1": +"rollup@npm:^2.25.0 || ^3.3.0, rollup@npm:^3.2.5, rollup@npm:^3.26.0, rollup@npm:^3.27.1": version: 3.29.4 resolution: "rollup@npm:3.29.4" dependencies: @@ -37676,37 +28936,27 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^3.2.5": - version: 3.26.0 - resolution: "rollup@npm:3.26.0" - dependencies: - fsevents: ~2.3.2 - dependenciesMeta: - fsevents: - optional: true - bin: - rollup: dist/bin/rollup - checksum: 948b028978dc943c2dee30713c12e2cdc5f63c99871a86e8de1fa31038209dd14a1408146e6d112105d9f82231f2cdfca319cadd29459eec81cb37a152692311 - languageName: node - linkType: hard - "rollup@npm:^4.0.2, rollup@npm:^4.2.0": - version: 4.9.2 - resolution: "rollup@npm:4.9.2" + version: 4.17.2 + resolution: "rollup@npm:4.17.2" dependencies: - "@rollup/rollup-android-arm-eabi": 4.9.2 - "@rollup/rollup-android-arm64": 4.9.2 - "@rollup/rollup-darwin-arm64": 4.9.2 - "@rollup/rollup-darwin-x64": 4.9.2 - "@rollup/rollup-linux-arm-gnueabihf": 4.9.2 - "@rollup/rollup-linux-arm64-gnu": 4.9.2 - "@rollup/rollup-linux-arm64-musl": 4.9.2 - "@rollup/rollup-linux-riscv64-gnu": 4.9.2 - "@rollup/rollup-linux-x64-gnu": 4.9.2 - "@rollup/rollup-linux-x64-musl": 4.9.2 - "@rollup/rollup-win32-arm64-msvc": 4.9.2 - "@rollup/rollup-win32-ia32-msvc": 4.9.2 - "@rollup/rollup-win32-x64-msvc": 4.9.2 + "@rollup/rollup-android-arm-eabi": 4.17.2 + "@rollup/rollup-android-arm64": 4.17.2 + "@rollup/rollup-darwin-arm64": 4.17.2 + "@rollup/rollup-darwin-x64": 4.17.2 + "@rollup/rollup-linux-arm-gnueabihf": 4.17.2 + "@rollup/rollup-linux-arm-musleabihf": 4.17.2 + "@rollup/rollup-linux-arm64-gnu": 4.17.2 + "@rollup/rollup-linux-arm64-musl": 4.17.2 + "@rollup/rollup-linux-powerpc64le-gnu": 4.17.2 + "@rollup/rollup-linux-riscv64-gnu": 4.17.2 + "@rollup/rollup-linux-s390x-gnu": 4.17.2 + "@rollup/rollup-linux-x64-gnu": 4.17.2 + "@rollup/rollup-linux-x64-musl": 4.17.2 + "@rollup/rollup-win32-arm64-msvc": 4.17.2 + "@rollup/rollup-win32-ia32-msvc": 4.17.2 + "@rollup/rollup-win32-x64-msvc": 4.17.2 + "@types/estree": 1.0.5 fsevents: ~2.3.2 dependenciesMeta: "@rollup/rollup-android-arm-eabi": @@ -37719,12 +28969,18 @@ __metadata: optional: true "@rollup/rollup-linux-arm-gnueabihf": optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true "@rollup/rollup-linux-arm64-gnu": optional: true "@rollup/rollup-linux-arm64-musl": optional: true + "@rollup/rollup-linux-powerpc64le-gnu": + optional: true "@rollup/rollup-linux-riscv64-gnu": optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true "@rollup/rollup-linux-x64-gnu": optional: true "@rollup/rollup-linux-x64-musl": @@ -37739,7 +28995,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: c9cd2bd09c3074730c51f22088fdc27c6ff674c81724cc75dcc26d36039a61be8ef982923493b680d583002f20f0792bca7fbbb355e303deaefbd41906a8c638 + checksum: 4fa6644e5c7fc4a34f654ea7e209be6c2c5897ed9dd43e7135230137204df748a795c7553804130f6c41da0b71e83f8c35a4a7881d385a77996adee50b609a6e languageName: node linkType: hard @@ -37841,24 +29097,6 @@ __metadata: languageName: node linkType: hard -"run-queue@npm:^1.0.0, run-queue@npm:^1.0.3": - version: 1.0.3 - resolution: "run-queue@npm:1.0.3" - dependencies: - aproba: ^1.1.1 - checksum: 4e8964279d8f160f9ffaabe82eaad11a1d4c0db596a0f2b5257ae9d2b900c7e1ffcece3e5719199436f50718e1e7f45bb4bf7a82e331a4e734d67c2588a90cbb - languageName: node - linkType: hard - -"rxjs@npm:^6.4.0": - version: 6.6.7 - resolution: "rxjs@npm:6.6.7" - dependencies: - tslib: ^1.9.0 - checksum: e556a13a9aa89395e5c9d825eabcfa325568d9c9990af720f3f29f04a888a3b854f25845c2b55875d875381abcae2d8100af9cacdc57576e7ed6be030a01d2fe - languageName: node - linkType: hard - "rxjs@npm:^7.2.0, rxjs@npm:^7.5.1, rxjs@npm:^7.5.5, rxjs@npm:^7.8.1": version: 7.8.1 resolution: "rxjs@npm:7.8.1" @@ -37877,22 +29115,15 @@ __metadata: languageName: node linkType: hard -"safe-array-concat@npm:^1.0.0": - version: 1.0.0 - resolution: "safe-array-concat@npm:1.0.0" +"safe-array-concat@npm:^1.1.2": + version: 1.1.2 + resolution: "safe-array-concat@npm:1.1.2" dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.2.0 + call-bind: ^1.0.7 + get-intrinsic: ^1.2.4 has-symbols: ^1.0.3 isarray: ^2.0.5 - checksum: 792d41fde9834583980912cb16bee511ce25e1759d3c467fdbbb3fc3245346a2289a6476d821713aa1ae23cc1d613d17e79c80e55adb29577f6a29e6f45e7f46 - languageName: node - linkType: hard - -"safe-buffer@npm:5.1.1": - version: 5.1.1 - resolution: "safe-buffer@npm:5.1.1" - checksum: 1c233bd105deeba3c9a8911ed4ec24ba45adbb51fec02f7944a10a202c38e3df4ef2b524bdeb55f2e4f8c77c13b2959e2e2e6022e5d99acdd70633b5f7e138cf + checksum: 12f9fdb01c8585e199a347eacc3bae7b5164ae805cdc8c6707199dbad5b9e30001a50a43c4ee24dc9ea32dbb7279397850e9208a7e217f4d8b1cf5d90129dec9 languageName: node linkType: hard @@ -37903,7 +29134,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.2, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 @@ -37924,14 +29155,14 @@ __metadata: languageName: node linkType: hard -"safe-regex-test@npm:^1.0.0": - version: 1.0.0 - resolution: "safe-regex-test@npm:1.0.0" +"safe-regex-test@npm:^1.0.3": + version: 1.0.3 + resolution: "safe-regex-test@npm:1.0.3" dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.3 + call-bind: ^1.0.6 + es-errors: ^1.3.0 is-regex: ^1.1.4 - checksum: 14a81a7e683f97b2d6e9c8be61fddcf8ed7a02f4e64a825515f96bb1738eb007145359313741d2704d28b55b703a0f6300c749dde7c1dbc13952a2b85048ede2 + checksum: 900bf7c98dc58f08d8523b7012b468e4eb757afa624f198902c0643d7008ba777b0bdc35810ba0b758671ce887617295fb742b3f3968991b178ceca54cb07603 languageName: node linkType: hard @@ -37978,8 +29209,8 @@ __metadata: linkType: hard "sass-loader@npm:^13.2.2": - version: 13.3.2 - resolution: "sass-loader@npm:13.3.2" + version: 13.3.3 + resolution: "sass-loader@npm:13.3.3" dependencies: neo-async: ^2.6.2 peerDependencies: @@ -37997,7 +29228,7 @@ __metadata: optional: true sass-embedded: optional: true - checksum: 7db8132101ed663f3cf936ce765b9b960a48b14f13f17d367a4e0c2ae259e91b6c401e33ab0f27ee88c98c8b5893c778848fc8366f1f387ac788ebef244e000a + checksum: 5e955a4ffce35ee0a46fce677ce51eaa69587fb5371978588c83af00f49e7edc36dcf3bb559cbae27681c5e24a71284463ebe03a1fb65e6ecafa1db0620e3fc8 languageName: node linkType: hard @@ -38038,56 +29269,12 @@ __metadata: languageName: node linkType: hard -"scheduler@npm:^0.23.0": - version: 0.23.0 - resolution: "scheduler@npm:0.23.0" +"scheduler@npm:^0.23.2": + version: 0.23.2 + resolution: "scheduler@npm:0.23.2" dependencies: loose-envify: ^1.1.0 - checksum: b777f7ca0115e6d93e126ac490dbd82642d14983b3079f58f35519d992fa46260be7d6e6cede433a92db70306310c6f5f06e144f0e40c484199e09c1f7be53dd - languageName: node - linkType: hard - -"schema-utils@npm:2.7.0": - version: 2.7.0 - resolution: "schema-utils@npm:2.7.0" - dependencies: - "@types/json-schema": ^7.0.4 - ajv: ^6.12.2 - ajv-keywords: ^3.4.1 - checksum: 723c3c856a0313a89aa81c5fb2c93d4b11225f5cdd442665fddd55d3c285ae72e079f5286a3a9a1a973affe888f6c33554a2cf47b79b24cd8de2f1f756a6fb1b - languageName: node - linkType: hard - -"schema-utils@npm:^1.0.0": - version: 1.0.0 - resolution: "schema-utils@npm:1.0.0" - dependencies: - ajv: ^6.1.0 - ajv-errors: ^1.0.0 - ajv-keywords: ^3.1.0 - checksum: 670e22d7f0ff0b6f4514a4d6fb27c359101b44b7dbfd9563af201af72eb4a9ff06144020cab5f85b16e88821fd09b97cbdae6c893721c6528c8cb704124e6a2f - languageName: node - linkType: hard - -"schema-utils@npm:^2.6.5, schema-utils@npm:^2.7.0": - version: 2.7.1 - resolution: "schema-utils@npm:2.7.1" - dependencies: - "@types/json-schema": ^7.0.5 - ajv: ^6.12.4 - ajv-keywords: ^3.5.2 - checksum: f484f34464edd8758712d5d3ba25a306e367dac988aecaf4ce112e99baae73f33a807b5cf869240bb6648c80720b36af2d7d72be3a27faa49a2d4fc63fa3f85f - languageName: node - linkType: hard - -"schema-utils@npm:^3.0.0, schema-utils@npm:^3.1.1, schema-utils@npm:^3.2.0": - version: 3.3.0 - resolution: "schema-utils@npm:3.3.0" - dependencies: - "@types/json-schema": ^7.0.8 - ajv: ^6.12.5 - ajv-keywords: ^3.5.2 - checksum: fafdbde91ad8aa1316bc543d4b61e65ea86970aebbfb750bfb6d8a6c287a23e415e0e926c2498696b242f63af1aab8e585252637fabe811fd37b604351da6500 + checksum: 26383305e249651d4c58e6705d5f8425f153211aef95f15161c151f7b8de885f24751b377e4a0b3dd42cce09aad3f87a61dab7636859c0d89b7daf1a1e2a5c78 languageName: node linkType: hard @@ -38105,21 +29292,21 @@ __metadata: languageName: node linkType: hard -"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.4.1, semver@npm:^5.5.0, semver@npm:^5.6.0, semver@npm:^5.7.0, semver@npm:^5.7.1": - version: 5.7.1 - resolution: "semver@npm:5.7.1" +"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.5.0, semver@npm:^5.6.0, semver@npm:^5.7.0, semver@npm:^5.7.1": + version: 5.7.2 + resolution: "semver@npm:5.7.2" bin: - semver: ./bin/semver - checksum: d4884f2aeca28bff35d0bd40ff0a9b2dfc4b36a883bf0ea5dc15d10d9a01bdc9041035b05f825d4b5ac8a56e490703dbf0d986d054de82cc5e9bad3f02ca6e00 + semver: bin/semver + checksum: e4cf10f86f168db772ae95d86ba65b3fd6c5967c94d97c708ccb463b778c2ee53b914cd7167620950fc07faf5a564e6efe903836639e512a1aa15fbc9667fa25 languageName: node linkType: hard -"semver@npm:6.x, semver@npm:^6.0.0, semver@npm:^6.1.1, semver@npm:^6.1.2, semver@npm:^6.3.0": - version: 6.3.0 - resolution: "semver@npm:6.3.0" +"semver@npm:6.x, semver@npm:^6.0.0, semver@npm:^6.3.0, semver@npm:^6.3.1": + version: 6.3.1 + resolution: "semver@npm:6.3.1" bin: - semver: ./bin/semver.js - checksum: 1f4959e15bcfbaf727e964a4920f9260141bb8805b399793160da4e7de128e42a7d1f79c1b7d5cd21a6073fba0d55feb9966f5fef3e5ccb8e1d7ead3d7527458 + semver: bin/semver.js + checksum: e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d languageName: node linkType: hard @@ -38134,34 +29321,14 @@ __metadata: languageName: node linkType: hard -"semver@npm:7.x, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3": - version: 7.5.3 - resolution: "semver@npm:7.5.3" +"semver@npm:7.x, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4": + version: 7.6.0 + resolution: "semver@npm:7.6.0" dependencies: lru-cache: ^6.0.0 bin: semver: bin/semver.js - checksum: 4cf3bab7e8cf8c2ae521fc4bcc50a4d6912a836360796b23b9f1c26f45d27a73f870e47664df4770bde0dd60dc4d4781a05fd49fe91d72376ea5519b9e791459 - languageName: node - linkType: hard - -"semver@npm:^6.3.1": - version: 6.3.1 - resolution: "semver@npm:6.3.1" - bin: - semver: bin/semver.js - checksum: e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d - languageName: node - linkType: hard - -"semver@npm:^7.5.2, semver@npm:^7.5.4": - version: 7.5.4 - resolution: "semver@npm:7.5.4" - dependencies: - lru-cache: ^6.0.0 - bin: - semver: bin/semver.js - checksum: 5160b06975a38b11c1ab55950cb5b8a23db78df88275d3d8a42ccf1f29e55112ac995b3a26a522c36e3b5f76b0445f1eef70d696b8c7862a2b4303d7b0e7609e + checksum: fbfe717094ace0aa8d6332d7ef5ce727259815bd8d8815700853f4faf23aacbd7192522f0dc5af6df52ef4fa85a355ebd2f5d39f554bd028200d6cf481ab9b53 languageName: node linkType: hard @@ -38174,6 +29341,17 @@ __metadata: languageName: node linkType: hard +"semver@npm:~7.5.4": + version: 7.5.4 + resolution: "semver@npm:7.5.4" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: 5160b06975a38b11c1ab55950cb5b8a23db78df88275d3d8a42ccf1f29e55112ac995b3a26a522c36e3b5f76b0445f1eef70d696b8c7862a2b4303d7b0e7609e + languageName: node + linkType: hard + "send@npm:0.17.1": version: 0.17.1 resolution: "send@npm:0.17.1" @@ -38225,37 +29403,6 @@ __metadata: languageName: node linkType: hard -"serialize-javascript@npm:^5.0.1": - version: 5.0.1 - resolution: "serialize-javascript@npm:5.0.1" - dependencies: - randombytes: ^2.1.0 - checksum: 646bd92a8298d764d38316f3006bce0b0def6d0e254791396ac34403847654d9346b0b6ed7865efd799d93d4c47d900e08a8fa7a6f7f8d2dbaebab5444c3b431 - languageName: node - linkType: hard - -"serialize-javascript@npm:^6.0.1": - version: 6.0.1 - resolution: "serialize-javascript@npm:6.0.1" - dependencies: - randombytes: ^2.1.0 - checksum: 1af427f4fee3fee051f54ffe15f77068cff78a3c96d20f5c1178d20630d3ab122d8350e639d5e13cde8111ef9db9439b871305ffb185e24be0a2149cec230988 - languageName: node - linkType: hard - -"serve-favicon@npm:^2.5.0": - version: 2.5.0 - resolution: "serve-favicon@npm:2.5.0" - dependencies: - etag: ~1.8.1 - fresh: 0.5.2 - ms: 2.1.1 - parseurl: ~1.3.2 - safe-buffer: 5.1.1 - checksum: 7244ced3c46f8dfde591dc801f1e21ebc8fa07c4870cbbaee3ce37104b3aad32858e674e251a8ed4837867ea0dd67cb734b485ae5a7b0895cb6022f8b8c79303 - languageName: node - linkType: hard - "serve-static@npm:1.14.1": version: 1.14.1 resolution: "serve-static@npm:1.14.1" @@ -38287,13 +29434,6 @@ __metadata: languageName: node linkType: hard -"set-cookie-parser@npm:^2.4.6": - version: 2.6.0 - resolution: "set-cookie-parser@npm:2.6.0" - checksum: 739da029f0e56806a103fcd5501d9c475e19e77bd8274192d7ae5c374ae714a82bba9a7ac00b0330a18227c5644b08df9e442240527be578f5a6030f9bb2bb80 - languageName: node - linkType: hard - "set-function-length@npm:^1.2.1": version: 1.2.2 resolution: "set-function-length@npm:1.2.2" @@ -38308,6 +29448,18 @@ __metadata: languageName: node linkType: hard +"set-function-name@npm:^2.0.1, set-function-name@npm:^2.0.2": + version: 2.0.2 + resolution: "set-function-name@npm:2.0.2" + dependencies: + define-data-property: ^1.1.4 + es-errors: ^1.3.0 + functions-have-names: ^1.2.3 + has-property-descriptors: ^1.0.2 + checksum: fce59f90696c450a8523e754abb305e2b8c73586452619c2bad5f7bf38c7b6b4651895c9db895679c5bef9554339cf3ef1c329b66ece3eda7255785fbe299316 + languageName: node + linkType: hard + "set-value@npm:^2.0.0, set-value@npm:^2.0.1": version: 2.0.1 resolution: "set-value@npm:2.0.1" @@ -38320,13 +29472,6 @@ __metadata: languageName: node linkType: hard -"setimmediate@npm:^1.0.4, setimmediate@npm:^1.0.5": - version: 1.0.5 - resolution: "setimmediate@npm:1.0.5" - checksum: 5bae81bfdbfbd0ce992893286d49c9693c82b1bcc00dcaaf3a09c8f428fdeacf4190c013598b81875dfac2b08a572422db7df779a99332d0fce186d15a3e4d49 - languageName: node - linkType: hard - "setprototypeof@npm:1.1.1": version: 1.1.1 resolution: "setprototypeof@npm:1.1.1" @@ -38341,7 +29486,7 @@ __metadata: languageName: node linkType: hard -"sha.js@npm:^2.4.0, sha.js@npm:^2.4.11, sha.js@npm:^2.4.8": +"sha.js@npm:^2.4.11": version: 2.4.11 resolution: "sha.js@npm:2.4.11" dependencies: @@ -38464,18 +29609,7 @@ __metadata: languageName: node linkType: hard -"side-channel@npm:^1.0.4": - version: 1.0.4 - resolution: "side-channel@npm:1.0.4" - dependencies: - call-bind: ^1.0.0 - get-intrinsic: ^1.0.2 - object-inspect: ^1.9.0 - checksum: 054a5d23ee35054b2c4609b9fd2a0587760737782b5d765a9c7852264710cc39c6dcb56a9bbd6c12cd84071648aea3edb2359d2f6e560677eedadce511ac1da5 - languageName: node - linkType: hard - -"side-channel@npm:^1.0.6": +"side-channel@npm:^1.0.4, side-channel@npm:^1.0.6": version: 1.0.6 resolution: "side-channel@npm:1.0.6" dependencies: @@ -38501,10 +29635,10 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^4.0.1": - version: 4.0.2 - resolution: "signal-exit@npm:4.0.2" - checksum: 3c36ae214f4774b4a7cbbd2d090b2864f8da4dc3f9140ba5b76f38bea7605c7aa8042adf86e48ee8a0955108421873f9b0f20281c61b8a65da4d9c1c1de4929f +"signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 languageName: node linkType: hard @@ -38545,15 +29679,6 @@ __metadata: languageName: node linkType: hard -"simple-update-notifier@npm:^2.0.0": - version: 2.0.0 - resolution: "simple-update-notifier@npm:2.0.0" - dependencies: - semver: ^7.5.3 - checksum: 2a00bd03bfbcbf8a737c47ab230d7920f8bfb92d1159d421bdd194479f6d01ebc995d13fbe13d45dace23066a78a3dc6642999b4e3b38b847e6664191575b20c - languageName: node - linkType: hard - "simple-websocket@npm:^9.0.0": version: 9.1.0 resolution: "simple-websocket@npm:9.1.0" @@ -38702,24 +29827,24 @@ __metadata: languageName: node linkType: hard -"socks-proxy-agent@npm:^7.0.0": - version: 7.0.0 - resolution: "socks-proxy-agent@npm:7.0.0" +"socks-proxy-agent@npm:^8.0.3": + version: 8.0.3 + resolution: "socks-proxy-agent@npm:8.0.3" dependencies: - agent-base: ^6.0.2 - debug: ^4.3.3 - socks: ^2.6.2 - checksum: b859f7eb8e96ec2c4186beea233ae59c02404094f3eb009946836af27d6e5c1627d1975a69b4d2e20611729ed543b6db3ae8481eb38603433c50d0345c987600 + agent-base: ^7.1.1 + debug: ^4.3.4 + socks: ^2.7.1 + checksum: 4950529affd8ccd6951575e21c1b7be8531b24d924aa4df3ee32df506af34b618c4e50d261f4cc603f1bfd8d426915b7d629966c8ce45b05fb5ad8c8b9a6459d languageName: node linkType: hard -"socks@npm:^2.6.2": - version: 2.7.1 - resolution: "socks@npm:2.7.1" +"socks@npm:^2.7.1": + version: 2.8.3 + resolution: "socks@npm:2.8.3" dependencies: - ip: ^2.0.0 + ip-address: ^9.0.5 smart-buffer: ^4.2.0 - checksum: 43f69dbc9f34fc8220bc51c6eea1c39715ab3cfdb115d6e3285f6c7d1a603c5c75655668a5bbc11e3c7e2c99d60321fb8d7ab6f38cda6a215fadd0d6d0b52130 + checksum: d54a52bf9325165770b674a67241143a3d8b4e4c8884560c4e0e078aace2a728dffc7f70150660f51b85797c4e1a3b82f9b7aa25e0a0ceae1a243365da5c51a7 languageName: node linkType: hard @@ -38740,21 +29865,7 @@ __metadata: languageName: node linkType: hard -"source-list-map@npm:^2.0.0": - version: 2.0.1 - resolution: "source-list-map@npm:2.0.1" - checksum: 2e5e421b185dcd857f46c3c70e2e711a65d717b78c5f795e2e248c9d67757882ea989b80ebc08cf164eeeda5f4be8aa95d3b990225070b2daaaf3257c5958149 - languageName: node - linkType: hard - -"source-map-js@npm:^1.0.1, source-map-js@npm:^1.0.2": - version: 1.0.2 - resolution: "source-map-js@npm:1.0.2" - checksum: 32f2dfd1e9b7168f9a9715eb1b4e21905850f3b50cf02cf476e47e4eebe8e6b762b63a64357896aa29b37e24922b4282df0f492e0d2ace572b43d15525976ff8 - languageName: node - linkType: hard - -"source-map-js@npm:^1.2.0": +"source-map-js@npm:^1.0.1, source-map-js@npm:^1.0.2, source-map-js@npm:^1.2.0": version: 1.2.0 resolution: "source-map-js@npm:1.2.0" checksum: 7e5f896ac10a3a50fe2898e5009c58ff0dc102dcb056ed27a354623a0ece8954d4b2649e1a1b2b52ef2e161d26f8859c7710350930751640e71e374fe2d321a4 @@ -38784,7 +29895,7 @@ __metadata: languageName: node linkType: hard -"source-map-support@npm:^0.5.16, source-map-support@npm:^0.5.6, source-map-support@npm:~0.5.12, source-map-support@npm:~0.5.20": +"source-map-support@npm:^0.5.16, source-map-support@npm:^0.5.6, source-map-support@npm:~0.5.20": version: 0.5.21 resolution: "source-map-support@npm:0.5.21" dependencies: @@ -38801,7 +29912,7 @@ __metadata: languageName: node linkType: hard -"source-map@npm:0.6.1, source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.0, source-map@npm:~0.6.1": +"source-map@npm:0.6.1, source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.1": version: 0.6.1 resolution: "source-map@npm:0.6.1" checksum: ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011 @@ -38877,9 +29988,9 @@ __metadata: linkType: hard "spdx-exceptions@npm:^2.1.0": - version: 2.3.0 - resolution: "spdx-exceptions@npm:2.3.0" - checksum: 83089e77d2a91cb6805a5c910a2bedb9e50799da091f532c2ba4150efdef6e53f121523d3e2dc2573a340dc0189e648b03157097f65465b3a0c06da1f18d7e8a + version: 2.5.0 + resolution: "spdx-exceptions@npm:2.5.0" + checksum: 37217b7762ee0ea0d8b7d0c29fd48b7e4dfb94096b109d6255b589c561f57da93bf4e328c0290046115961b9209a8051ad9f525e48d433082fc79f496a4ea940 languageName: node linkType: hard @@ -38903,9 +30014,9 @@ __metadata: linkType: hard "spdx-license-ids@npm:^3.0.0": - version: 3.0.13 - resolution: "spdx-license-ids@npm:3.0.13" - checksum: a5cb77ea7be86d574c8876970920e34d9b37f2fb6e361e6b732b61267afbc63dd37831160b731f85c1478f5ba95ae00369742555920e3c694f047f7068d33318 + version: 3.0.17 + resolution: "spdx-license-ids@npm:3.0.17" + checksum: ddf9477b5afc70f1a7d3bf91f0b8e8a1c1b0fa65d2d9a8b5c991b1a2ba91b693d8b9749700119d5ce7f3fbf307ac421087ff43d321db472605e98a5804f80eac languageName: node linkType: hard @@ -38943,10 +30054,10 @@ __metadata: languageName: node linkType: hard -"sprintf-js@npm:^1.1.1": - version: 1.1.2 - resolution: "sprintf-js@npm:1.1.2" - checksum: 6cc8382f746348bd64b31bc5c99d8ebda7efff716025c41bf501e0e8be4f6744a9fa507e18513554753553d0bcb57fd5fc8dc8c42f94f8008127a52a2c544d21 +"sprintf-js@npm:^1.1.1, sprintf-js@npm:^1.1.3": + version: 1.1.3 + resolution: "sprintf-js@npm:1.1.3" + checksum: 09270dc4f30d479e666aee820eacd9e464215cdff53848b443964202bf4051490538e5dd1b42e1a65cf7296916ca17640aebf63dae9812749c7542ee5f288dec languageName: node linkType: hard @@ -38965,8 +30076,8 @@ __metadata: linkType: hard "sshpk@npm:^1.7.0": - version: 1.17.0 - resolution: "sshpk@npm:1.17.0" + version: 1.18.0 + resolution: "sshpk@npm:1.18.0" dependencies: asn1: ~0.2.3 assert-plus: ^1.0.0 @@ -38981,34 +30092,16 @@ __metadata: sshpk-conv: bin/sshpk-conv sshpk-sign: bin/sshpk-sign sshpk-verify: bin/sshpk-verify - checksum: cf5e7f4c72e8a505ef41daac9f9ca26da365cfe26ae265a01ce98a8868991943857a8526c1cf98a42ef0dc4edf1dbe4e77aeea378cfeb58054beb78505e85402 + checksum: e516e34fa981cfceef45fd2e947772cc70dbd57523e5c608e2cd73752ba7f8a99a04df7c3ed751588e8d91956b6f16531590b35d3489980d1c54c38bebcd41b1 languageName: node linkType: hard "ssri@npm:^10.0.0": - version: 10.0.4 - resolution: "ssri@npm:10.0.4" + version: 10.0.6 + resolution: "ssri@npm:10.0.6" dependencies: - minipass: ^5.0.0 - checksum: d085474ea6b439623a9a6a2c67570cb9e68e1bb6060e46e4d387f113304d75a51946d57c524be3a90ebfa3c73026edf76eb1a2d79a7f6cff0b04f21d99f127ab - languageName: node - linkType: hard - -"ssri@npm:^6.0.1": - version: 6.0.2 - resolution: "ssri@npm:6.0.2" - dependencies: - figgy-pudding: ^3.5.1 - checksum: e6f18c57dc9fed69343db5c59f95ef334e9664bfbdbad686c190ef2c6ad6b35e9b56cb203f3e4eb7eee6cb7bb602daa26dab6685e3847f0b5c464cdf7d9c2cee - languageName: node - linkType: hard - -"ssri@npm:^8.0.1": - version: 8.0.1 - resolution: "ssri@npm:8.0.1" - dependencies: - minipass: ^3.1.1 - checksum: 5cfae216ae02dcd154d1bbed2d0a60038a4b3a2fcaac3c7e47401ff4e058e551ee74cfdba618871bf168cd583db7b8324f94af6747d4303b73cd4c3f6dc5c9c2 + minipass: ^7.0.3 + checksum: e5a1e23a4057a86a97971465418f22ea89bd439ac36ade88812dd920e4e61873e8abd6a9b72a03a67ef50faa00a2daf1ab745c5a15b46d03e0544a0296354227 languageName: node linkType: hard @@ -39051,13 +30144,6 @@ __metadata: languageName: node linkType: hard -"stackframe@npm:^1.3.4": - version: 1.3.4 - resolution: "stackframe@npm:1.3.4" - checksum: 18410f7a1e0c5d211a4effa83bdbf24adbe8faa8c34db52e1cd3e89837518c592be60b60d8b7270ac53eeeb8b807cd11b399a41667f6c9abb41059c3ccc8a989 - languageName: node - linkType: hard - "standard-as-callback@npm:^2.1.0": version: 2.1.0 resolution: "standard-as-callback@npm:2.1.0" @@ -39065,13 +30151,6 @@ __metadata: languageName: node linkType: hard -"state-toggle@npm:^1.0.0": - version: 1.0.3 - resolution: "state-toggle@npm:1.0.3" - checksum: 6051ee5654b39b0006911ae3130fa7f47675e07db16a711d8cd23d43b63f383e98f3bd9fa80e118a3f5964a11284d8eee180baef27a556146e628f8da74aba12 - languageName: node - linkType: hard - "static-extend@npm:^0.1.1": version: 0.1.2 resolution: "static-extend@npm:0.1.2" @@ -39082,7 +30161,7 @@ __metadata: languageName: node linkType: hard -"statuses@npm:2.0.1, statuses@npm:^2.0.0": +"statuses@npm:2.0.1": version: 2.0.1 resolution: "statuses@npm:2.0.1" checksum: 34378b207a1620a24804ce8b5d230fea0c279f00b18a7209646d5d47e419d1cc23e7cbf33a25a1e51ac38973dc2ac2e1e9c647a8e481ef365f77668d72becfd0 @@ -39097,9 +30176,9 @@ __metadata: linkType: hard "std-env@npm:^3.3.3": - version: 3.4.3 - resolution: "std-env@npm:3.4.3" - checksum: 61c0d673eb157bbd9ff65da42ae768ff154b948737030fddfbd3f289ab4c0455285d365b1ed03319e05df58eed26622aaa009a03ee1f9159ec71087646834a9a + version: 3.7.0 + resolution: "std-env@npm:3.7.0" + checksum: 60edf2d130a4feb7002974af3d5a5f3343558d1ccf8d9b9934d225c638606884db4a20d2fe6440a09605bca282af6b042ae8070a10490c0800d69e82e478f41e languageName: node linkType: hard @@ -39135,62 +30214,29 @@ __metadata: languageName: node linkType: hard -"store2@npm:^2.12.0, store2@npm:^2.14.2": - version: 2.14.2 - resolution: "store2@npm:2.14.2" - checksum: 2f27c3eaa7207b81410e170e7c41379816d22c1566308a9d97fbf853c4facff531fcb2a85f085c7503c578736570972f747c26018ebeaba7d1341fb82a7b6d52 +"store2@npm:^2.14.2": + version: 2.14.3 + resolution: "store2@npm:2.14.3" + checksum: 22e1096e6d69590672ca0b7f891d82b060837ef4c3e5df0d4563e6cbed14c52ddf2589fa94b79f4311b6ec41d95d6142e5d01d194539e0175c3fb4090cca8244 languageName: node linkType: hard "storybook@npm:^7.0.23": - version: 7.5.1 - resolution: "storybook@npm:7.5.1" + version: 7.6.19 + resolution: "storybook@npm:7.6.19" dependencies: - "@storybook/cli": 7.5.1 + "@storybook/cli": 7.6.19 bin: sb: ./index.js storybook: ./index.js - checksum: 51337eb328ec727f13f1a547fab01133201685702e5fcab86bb34759afbb10a532fe5ce43a3a1ee4d66f1b508f695060ff69540533ee6dbe8df927755e70fb1e - languageName: node - linkType: hard - -"stream-browserify@npm:^2.0.1": - version: 2.0.2 - resolution: "stream-browserify@npm:2.0.2" - dependencies: - inherits: ~2.0.1 - readable-stream: ^2.0.2 - checksum: 485562bd5d962d633ae178449029c6fa2611052e356bdb5668f768544aa4daa94c4f9a97de718f3f30ad98f3cb98a5f396252bb3855aff153c138f79c0e8f6ac - languageName: node - linkType: hard - -"stream-each@npm:^1.1.0": - version: 1.2.3 - resolution: "stream-each@npm:1.2.3" - dependencies: - end-of-stream: ^1.1.0 - stream-shift: ^1.0.0 - checksum: 7ed229d3b7c24373058b5742b00066da8d3122d1487c8219a025ed53a8978545c77654a529a8e9c62ba83ae80c424cbb0204776b49abf72270d2e8154831dd5f - languageName: node - linkType: hard - -"stream-http@npm:^2.7.2": - version: 2.8.3 - resolution: "stream-http@npm:2.8.3" - dependencies: - builtin-status-codes: ^3.0.0 - inherits: ^2.0.1 - readable-stream: ^2.3.6 - to-arraybuffer: ^1.0.0 - xtend: ^4.0.0 - checksum: fbe7d327a29216bbabe88d3819bb8f7a502f11eeacf3212579e5af1f76fa7283f6ffa66134ab7d80928070051f571d1029e85f65ce3369fffd4c4df3669446c4 + checksum: dd026c19ceb1df74a94b45ee139d92f246d75b687913cc8a862a0a849d2d5327edc1fea096cb1ab37982bb569197a8bdf209edf34039e77d8b813510b1e1f75e languageName: node linkType: hard "stream-shift@npm:^1.0.0": - version: 1.0.1 - resolution: "stream-shift@npm:1.0.1" - checksum: b63a0d178cde34b920ad93e2c0c9395b840f408d36803b07c61416edac80ef9e480a51910e0ceea0d679cec90921bcd2cccab020d3a9fa6c73a98b0fbec132fd + version: 1.0.3 + resolution: "stream-shift@npm:1.0.3" + checksum: 939cd1051ca750d240a0625b106a2b988c45fb5a3be0cebe9a9858cb01bc1955e8c7b9fac17a9462976bea4a7b704e317c5c2200c70f0ca715a3363b9aa4fd3b languageName: node linkType: hard @@ -39210,15 +30256,6 @@ __metadata: languageName: node linkType: hard -"strict-event-emitter@npm:^0.2.0": - version: 0.2.8 - resolution: "strict-event-emitter@npm:0.2.8" - dependencies: - events: ^3.3.0 - checksum: 6891e19fea4f0289e4da2fe7050d85906eaca7f774aa38fe674f0e58fdece1b63b868614fa23974c4cb862aa99358caa987523b705fdfff4639231c62e384394 - languageName: node - linkType: hard - "string-argv@npm:0.3.1": version: 0.3.1 resolution: "string-argv@npm:0.3.1" @@ -39260,7 +30297,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.2, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.2, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -39282,78 +30319,61 @@ __metadata: languageName: node linkType: hard -"string.prototype.matchall@npm:^4.0.0 || ^3.0.1, string.prototype.matchall@npm:^4.0.8": - version: 4.0.8 - resolution: "string.prototype.matchall@npm:4.0.8" +"string.prototype.matchall@npm:^4.0.10": + version: 4.0.11 + resolution: "string.prototype.matchall@npm:4.0.11" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - get-intrinsic: ^1.1.3 + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.2 + es-errors: ^1.3.0 + es-object-atoms: ^1.0.0 + get-intrinsic: ^1.2.4 + gopd: ^1.0.1 has-symbols: ^1.0.3 - internal-slot: ^1.0.3 - regexp.prototype.flags: ^1.4.3 - side-channel: ^1.0.4 - checksum: 644523d05c1ee93bab7474e999a5734ee5f6ad2d7ad24ed6ea8706c270dc92b352bde0f2a5420bfbeed54e28cb6a770c3800e1988a5267a70fd5e677c7750abc + internal-slot: ^1.0.7 + regexp.prototype.flags: ^1.5.2 + set-function-name: ^2.0.2 + side-channel: ^1.0.6 + checksum: 915a2562ac9ab5e01b7be6fd8baa0b2b233a0a9aa975fcb2ec13cc26f08fb9a3e85d5abdaa533c99c6fc4c5b65b914eba3d80c4aff9792a4c9fed403f28f7d9d languageName: node linkType: hard -"string.prototype.padend@npm:^3.0.0": - version: 3.1.4 - resolution: "string.prototype.padend@npm:3.1.4" +"string.prototype.trim@npm:^1.2.9": + version: 1.2.9 + resolution: "string.prototype.trim@npm:1.2.9" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 11feb9ae51a32febc73bb3b38d29900405c736f47613badff773ab830f23faad796c43d51e18090cada975b82831f66bdcb6b5353739a019b7fcc321900205ad + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.0 + es-object-atoms: ^1.0.0 + checksum: dcef1a0fb61d255778155006b372dff8cc6c4394bc39869117e4241f41a2c52899c0d263ffc7738a1f9e61488c490b05c0427faa15151efad721e1a9fb2663c2 languageName: node linkType: hard -"string.prototype.padstart@npm:^3.0.0": - version: 3.1.4 - resolution: "string.prototype.padstart@npm:3.1.4" +"string.prototype.trimend@npm:^1.0.8": + version: 1.0.8 + resolution: "string.prototype.trimend@npm:1.0.8" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 4f395af27917b4cc52db2f77fe2221401cf396fcac1a96bed5e7dc53d08e453f6cdc4959e1f3ed45e8a29fd583f98af9ac67f6fd8b931d34618ddbecba8ea20b + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-object-atoms: ^1.0.0 + checksum: 0a0b54c17c070551b38e756ae271865ac6cc5f60dabf2e7e343cceae7d9b02e1a1120a824e090e79da1b041a74464e8477e2da43e2775c85392be30a6f60963c languageName: node linkType: hard -"string.prototype.trim@npm:^1.2.7": - version: 1.2.7 - resolution: "string.prototype.trim@npm:1.2.7" +"string.prototype.trimstart@npm:^1.0.8": + version: 1.0.8 + resolution: "string.prototype.trimstart@npm:1.0.8" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 31698f6d718794e422db6fcfa6685dcd9243097273b3b2a8b7948b5d45a183cd336378893ff0d4a7b2531b604c32bb5c45193dd6da3d2f5504df5cd222372c09 + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-object-atoms: ^1.0.0 + checksum: d53af1899959e53c83b64a5fd120be93e067da740e7e75acb433849aa640782fb6c7d4cd5b84c954c84413745a3764df135a8afeb22908b86a835290788d8366 languageName: node linkType: hard -"string.prototype.trimend@npm:^1.0.6": - version: 1.0.6 - resolution: "string.prototype.trimend@npm:1.0.6" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 51b663e3195a74b58620a250b3fc4efb58951000f6e7d572a9f671c038f2f37f24a2b8c6994500a882aeab2f1c383fac1e8c023c01eb0c8b4e52d2f13b6c4513 - languageName: node - linkType: hard - -"string.prototype.trimstart@npm:^1.0.6": - version: 1.0.6 - resolution: "string.prototype.trimstart@npm:1.0.6" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 13b9970d4e234002dfc8069c655c1fe19e83e10ced208b54858c41bb0f7544e581ac0ce746e92b279563664ad63910039f7253f36942113fec413b2b4e7c1fcd - languageName: node - linkType: hard - -"string_decoder@npm:^1.0.0, string_decoder@npm:^1.1.1": +"string_decoder@npm:^1.1.1": version: 1.3.0 resolution: "string_decoder@npm:1.3.0" dependencies: @@ -39391,7 +30411,7 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^3.0.0, strip-ansi@npm:^3.0.1": +"strip-ansi@npm:^3.0.0": version: 3.0.1 resolution: "strip-ansi@npm:3.0.1" dependencies: @@ -39418,15 +30438,6 @@ __metadata: languageName: node linkType: hard -"strip-bom@npm:^2.0.0": - version: 2.0.0 - resolution: "strip-bom@npm:2.0.0" - dependencies: - is-utf8: ^0.2.0 - checksum: 4fcbb248af1d5c1f2d710022b7d60245077e7942079bfb7ef3fc8c1ae78d61e96278525ba46719b15ab12fced5c7603777105bc898695339d7c97c64d300ed0b - languageName: node - linkType: hard - "strip-bom@npm:^3.0.0": version: 3.0.0 resolution: "strip-bom@npm:3.0.0" @@ -39462,17 +30473,6 @@ __metadata: languageName: node linkType: hard -"strip-indent@npm:^1.0.1": - version: 1.0.1 - resolution: "strip-indent@npm:1.0.1" - dependencies: - get-stdin: ^4.0.1 - bin: - strip-indent: cli.js - checksum: 671370d44105b63daf4582a42f0a0168d58a351f6558eb913d1ede05d0ad5f964548b99f15c63fa6c7415c3980aad72f28c62997fd98fbb6da2eee1051d3c21a - languageName: node - linkType: hard - "strip-indent@npm:^3.0.0": version: 3.0.0 resolution: "strip-indent@npm:3.0.0" @@ -39507,23 +30507,13 @@ __metadata: languageName: node linkType: hard -"stripe@npm:*": - version: 12.11.0 - resolution: "stripe@npm:12.11.0" +"stripe@npm:*, stripe@npm:latest": + version: 15.5.0 + resolution: "stripe@npm:15.5.0" dependencies: "@types/node": ">=8.1.0" qs: ^6.11.0 - checksum: 9859e455b6968a8a96bd14fd9d98da1fd2d50b4b6776acf080c4c94a9c2aad6724946626111330fa65f7bdc7c61ddc6b33ff32f12c1a639afe65c698fb54d069 - languageName: node - linkType: hard - -"stripe@npm:latest": - version: 14.16.0 - resolution: "stripe@npm:14.16.0" - dependencies: - "@types/node": ">=8.1.0" - qs: ^6.11.0 - checksum: bada06609592bae71094ba86fdf745d86945d6bb5b44482da0355235c01ca6f2c76f261fad31d9d367cee5cf6b8b5532fb66733d664d4bb497125809b61699bf + checksum: 69bf0fda79949a9e35a2b73a1353e162d669d853199b56645f479d040bc914e1dfd75e172825ce321191cafed98542ffd7befe4e5fb616ee52e6213138c74604 languageName: node linkType: hard @@ -39541,42 +30531,21 @@ __metadata: languageName: node linkType: hard -"style-loader@npm:^1.3.0": - version: 1.3.0 - resolution: "style-loader@npm:1.3.0" - dependencies: - loader-utils: ^2.0.0 - schema-utils: ^2.7.0 - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: 21137d63623690af0c8b135f94e01af724bc0dea560c65ff553aa06c560fac69c068ec19ae7893b3667e50e79a660e051783803c949bcd559a8fc2f839397056 - languageName: node - linkType: hard - "style-loader@npm:^3.3.2": - version: 3.3.3 - resolution: "style-loader@npm:3.3.3" + version: 3.3.4 + resolution: "style-loader@npm:3.3.4" peerDependencies: webpack: ^5.0.0 - checksum: 104bae8abd0627579dc14f3917cf65f1117e8098e3529872f09c26b5eee07933567b7be5c8ebf94d16e322b6e726dc569c5787111bf3786915850db4e351ef33 - languageName: node - linkType: hard - -"style-to-object@npm:0.3.0, style-to-object@npm:^0.3.0": - version: 0.3.0 - resolution: "style-to-object@npm:0.3.0" - dependencies: - inline-style-parser: 0.1.1 - checksum: afe9b96ba077a9068baf8887091870f50298157c0ebf5378151792cf2a2ce084fec9b34fc544da0d9f8e6c22ca0c9e23aa6f075bb8eb051aa1d64363e9987600 + checksum: 8f8027fc5c6e91400cbb60066e7db3315810f8eaa0d19b2a254936eb0bec399ba8a7043b1789da9d05ab7c3ba50faf9267765ae0bf3571e48aa34ecdc774be37 languageName: node linkType: hard "styled-components@npm:^6.0.7": - version: 6.1.8 - resolution: "styled-components@npm:6.1.8" + version: 6.1.9 + resolution: "styled-components@npm:6.1.9" dependencies: "@emotion/is-prop-valid": 1.2.1 - "@emotion/unitless": 0.8.0 + "@emotion/unitless": 0.8.1 "@types/stylis": 4.2.0 css-to-react-native: 3.2.0 csstype: 3.1.2 @@ -39587,7 +30556,7 @@ __metadata: peerDependencies: react: ">= 16.8.0" react-dom: ">= 16.8.0" - checksum: fafe4b9198d5d7980c2358821d1a89f86200d55c8eec03670cf12cf43b8a05a77eafaf0872cd85821f68238308e0f5c9d9aa43a62e6987c65b70baa2c3277ab8 + checksum: e5298859675f954424af45e7e1261980f86ca01188509e0af330cabe869533e6ce04aa63a4f94cbdc66ba1b834da247e54bb0ee05b5d2d57d906f0a45388763f languageName: node linkType: hard @@ -39610,13 +30579,13 @@ __metadata: languageName: node linkType: hard -"sucrase@npm:^3.20.3": - version: 3.32.0 - resolution: "sucrase@npm:3.32.0" +"sucrase@npm:^3.20.3, sucrase@npm:^3.32.0": + version: 3.35.0 + resolution: "sucrase@npm:3.35.0" dependencies: "@jridgewell/gen-mapping": ^0.3.2 commander: ^4.0.0 - glob: 7.1.6 + glob: ^10.3.10 lines-and-columns: ^1.1.6 mz: ^2.7.0 pirates: ^4.0.1 @@ -39624,25 +30593,7 @@ __metadata: bin: sucrase: bin/sucrase sucrase-node: bin/sucrase-node - checksum: c5f2d0c49a2462da3440a14ed62caad655c27919408471141b6866b18be9b29635e8b5e9246cc476a2c3df84e94a8d5498903f0f4e765c50d95d9ff360b95f79 - languageName: node - linkType: hard - -"sucrase@npm:^3.32.0": - version: 3.34.0 - resolution: "sucrase@npm:3.34.0" - dependencies: - "@jridgewell/gen-mapping": ^0.3.2 - commander: ^4.0.0 - glob: 7.1.6 - lines-and-columns: ^1.1.6 - mz: ^2.7.0 - pirates: ^4.0.1 - ts-interface-checker: ^0.1.9 - bin: - sucrase: bin/sucrase - sucrase-node: bin/sucrase-node - checksum: 83e524f2b9386c7029fc9e46b8d608485866d08bea5a0a71e9e3442dc12e1d05a5ab555808d1922f45dd012fc71043479d778aac07391d9740daabe45730a056 + checksum: ac85f3359d2c2ecbf5febca6a24ae9bf96c931f05fde533c22a94f59c6a74895e5d5f0e871878dfd59c2697a75ebb04e4b2224ef0bfc24ca1210735c2ec191ef languageName: node linkType: hard @@ -39674,7 +30625,7 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:8.1.1, supports-color@npm:^8.0.0, supports-color@npm:^8.1.0": +"supports-color@npm:8.1.1, supports-color@npm:^8.0.0, supports-color@npm:^8.1.0, supports-color@npm:~8.1.1": version: 8.1.1 resolution: "supports-color@npm:8.1.1" dependencies: @@ -39750,18 +30701,19 @@ __metadata: linkType: hard "svgo@npm:^3.0.2": - version: 3.0.2 - resolution: "svgo@npm:3.0.2" + version: 3.2.0 + resolution: "svgo@npm:3.2.0" dependencies: "@trysound/sax": 0.2.0 commander: ^7.2.0 css-select: ^5.1.0 - css-tree: ^2.2.1 + css-tree: ^2.3.1 + css-what: ^6.1.0 csso: ^5.0.5 picocolors: ^1.0.0 bin: - svgo: bin/svgo - checksum: d682d416dd68cdcbab5e1e77b93d621325480e97dfe87777e845ea9a0ce05d03fc837ce17080af67e787f6b24430b805ff79f4591dda30a0ab4060b6a3ac2adf + svgo: ./bin/svgo + checksum: 28fa9061ccbcf2e3616d48d1feb613aaa05f8f290a329beb0e585914f1864385152934a7d4d683a4609fafbae3d51666633437c359c5c5ef74fb58ad09092a7c languageName: node linkType: hard @@ -39780,7 +30732,7 @@ __metadata: languageName: node linkType: hard -"swagger2openapi@npm:^7.0.6": +"swagger2openapi@npm:^7.0.8": version: 7.0.8 resolution: "swagger2openapi@npm:7.0.8" dependencies: @@ -39810,18 +30762,6 @@ __metadata: languageName: node linkType: hard -"symbol.prototype.description@npm:^1.0.0": - version: 1.0.5 - resolution: "symbol.prototype.description@npm:1.0.5" - dependencies: - call-bind: ^1.0.2 - get-symbol-description: ^1.0.0 - has-symbols: ^1.0.2 - object.getownpropertydescriptors: ^2.1.2 - checksum: 6009bb54faa50fd899772baa0c047d4d4fc85cd03b7e2b5e5385f23f4688879518103ab4a95a03b0b25e4c89c10cf0bb16c159865df2c932682cc56502693650 - languageName: node - linkType: hard - "synchronous-promise@npm:^2.0.15": version: 2.0.17 resolution: "synchronous-promise@npm:2.0.17" @@ -39830,103 +30770,37 @@ __metadata: linkType: hard "table@npm:^6.0.9": - version: 6.8.1 - resolution: "table@npm:6.8.1" + version: 6.8.2 + resolution: "table@npm:6.8.2" dependencies: ajv: ^8.0.1 lodash.truncate: ^4.4.2 slice-ansi: ^4.0.0 string-width: ^4.2.3 strip-ansi: ^6.0.1 - checksum: 591ed84b2438b01c9bc02248e2238e21e8bfb73654bc5acca0d469053eb39be3db2f57d600dcf08ac983b6f50f80842c44612c03877567c2afee3aec4a033e5f + checksum: f8b348af38ee34e419d8ce7306ba00671ce6f20e861ccff22555f491ba264e8416086063ce278a8d81abfa8d23b736ec2cca7ac4029b5472f63daa4b4688b803 languageName: node linkType: hard "tailwind-merge@npm:^2.2.1": - version: 2.2.1 - resolution: "tailwind-merge@npm:2.2.1" + version: 2.3.0 + resolution: "tailwind-merge@npm:2.3.0" dependencies: - "@babel/runtime": ^7.23.7 - checksum: 14ab965ec897e9377484b7593f7a700dde09b8035b762ad42652622a3ed1f202b203f48c0f235c0b1b38e9390470d94458f6f9010d33a5a18d71b15f38b986a6 + "@babel/runtime": ^7.24.1 + checksum: 5ea308e23c3ab1cf4c3f35f0a471753f4d3ed232d63dd7c09151a74428737321902203d90e9f0cb76ea5c3978e71b0adbc503dc455e56cda967a7674ae4b94b5 languageName: node linkType: hard "tailwindcss-animate@npm:^1.0.6": - version: 1.0.6 - resolution: "tailwindcss-animate@npm:1.0.6" + version: 1.0.7 + resolution: "tailwindcss-animate@npm:1.0.7" peerDependencies: tailwindcss: "*" - checksum: 2d8589be6da9253c234b4e62273f95165235e560eaf5e995d865cd8d40bd2f79818a84f2e8fb56ccbe62c8ecbd5944a261fa297b3a9cf76b049582d4da0b988e + checksum: ec7dbd1631076b97d66a1fbaaa06e0725fccfa63119221e8d87a997b02dcede98ad88bb1ef6665b968f5d260fcefb10592e0299ca70208d365b37761edf5e19a languageName: node linkType: hard -"tailwindcss@npm:^3.3.6": - version: 3.4.0 - resolution: "tailwindcss@npm:3.4.0" - dependencies: - "@alloc/quick-lru": ^5.2.0 - arg: ^5.0.2 - chokidar: ^3.5.3 - didyoumean: ^1.2.2 - dlv: ^1.1.3 - fast-glob: ^3.3.0 - glob-parent: ^6.0.2 - is-glob: ^4.0.3 - jiti: ^1.19.1 - lilconfig: ^2.1.0 - micromatch: ^4.0.5 - normalize-path: ^3.0.0 - object-hash: ^3.0.0 - picocolors: ^1.0.0 - postcss: ^8.4.23 - postcss-import: ^15.1.0 - postcss-js: ^4.0.1 - postcss-load-config: ^4.0.1 - postcss-nested: ^6.0.1 - postcss-selector-parser: ^6.0.11 - resolve: ^1.22.2 - sucrase: ^3.32.0 - bin: - tailwind: lib/cli.js - tailwindcss: lib/cli.js - checksum: 0a1cef7468e6d17c2857d0b3c4017af2cb37ed8ba27dfb14780c517b8a74f6786970227c400ac1325fc8bcfc09099d8e990fa7c60924bf945f3d0a912d63f546 - languageName: node - linkType: hard - -"tailwindcss@npm:^3.4.1": - version: 3.4.1 - resolution: "tailwindcss@npm:3.4.1" - dependencies: - "@alloc/quick-lru": ^5.2.0 - arg: ^5.0.2 - chokidar: ^3.5.3 - didyoumean: ^1.2.2 - dlv: ^1.1.3 - fast-glob: ^3.3.0 - glob-parent: ^6.0.2 - is-glob: ^4.0.3 - jiti: ^1.19.1 - lilconfig: ^2.1.0 - micromatch: ^4.0.5 - normalize-path: ^3.0.0 - object-hash: ^3.0.0 - picocolors: ^1.0.0 - postcss: ^8.4.23 - postcss-import: ^15.1.0 - postcss-js: ^4.0.1 - postcss-load-config: ^4.0.1 - postcss-nested: ^6.0.1 - postcss-selector-parser: ^6.0.11 - resolve: ^1.22.2 - sucrase: ^3.32.0 - bin: - tailwind: lib/cli.js - tailwindcss: lib/cli.js - checksum: eec3d758f1cd4f51ab3b4c201927c3ecd18e55f8ac94256af60276aaf8d1df78f9dddb5e9fb1e057dfa7cea3c1356add4994cc3d42da9739df874e67047e656f - languageName: node - linkType: hard - -"tailwindcss@npm:^3.4.3": +"tailwindcss@npm:^3.3.6, tailwindcss@npm:^3.4.1, tailwindcss@npm:^3.4.3": version: 3.4.3 resolution: "tailwindcss@npm:3.4.3" dependencies: @@ -39959,20 +30833,6 @@ __metadata: languageName: node linkType: hard -"tapable@npm:^1.0.0, tapable@npm:^1.1.3": - version: 1.1.3 - resolution: "tapable@npm:1.1.3" - checksum: c9f0265e55e45821ec672b9b9ee8a35d95bf3ea6b352199f8606a2799018e89cfe4433c554d424b31fc67c4be26b05d4f36dc3c607def416fdb2514cd63dba50 - languageName: node - linkType: hard - -"tapable@npm:^2.1.1, tapable@npm:^2.2.0": - version: 2.2.1 - resolution: "tapable@npm:2.2.1" - checksum: bc40e6efe1e554d075469cedaba69a30eeb373552aaf41caeaaa45bf56ffacc2674261b106245bd566b35d8f3329b52d838e851ee0a852120acae26e622925c9 - languageName: node - linkType: hard - "tar-fs@npm:^2.1.1": version: 2.1.1 resolution: "tar-fs@npm:2.1.1" @@ -39998,9 +30858,9 @@ __metadata: languageName: node linkType: hard -"tar@npm:^6.0.2, tar@npm:^6.1.11, tar@npm:^6.1.2": - version: 6.1.15 - resolution: "tar@npm:6.1.15" +"tar@npm:^6.1.11, tar@npm:^6.1.2, tar@npm:^6.2.0": + version: 6.2.1 + resolution: "tar@npm:6.2.1" dependencies: chownr: ^2.0.0 fs-minipass: ^2.0.0 @@ -40008,21 +30868,7 @@ __metadata: minizlib: ^2.1.1 mkdirp: ^1.0.3 yallist: ^4.0.0 - checksum: bb2babe7b14442f690d83c2b2c571c9dd0bf802314773e05f4a3e4a241fdecd7fb560b8e4e7d6ea34533c8cd692e1b8418a3b8ba3b9687fe78a683dfbad7f82d - languageName: node - linkType: hard - -"tar@npm:^6.2.0": - version: 6.2.0 - resolution: "tar@npm:6.2.0" - dependencies: - chownr: ^2.0.0 - fs-minipass: ^2.0.0 - minipass: ^5.0.0 - minizlib: ^2.1.1 - mkdirp: ^1.0.3 - yallist: ^4.0.0 - checksum: 02ca064a1a6b4521fef88c07d389ac0936730091f8c02d30ea60d472e0378768e870769ab9e986d87807bfee5654359cf29ff4372746cc65e30cbddc352660d8 + checksum: a5eca3eb50bc11552d453488344e6507156b9193efd7635e98e867fab275d527af53d8866e2370cd09dfe74378a18111622ace35af6a608e5223a7d27fe99537 languageName: node linkType: hard @@ -40033,22 +30879,6 @@ __metadata: languageName: node linkType: hard -"telejson@npm:^6.0.8": - version: 6.0.8 - resolution: "telejson@npm:6.0.8" - dependencies: - "@types/is-function": ^1.0.0 - global: ^4.4.0 - is-function: ^1.0.2 - is-regex: ^1.1.2 - is-symbol: ^1.0.3 - isobject: ^4.0.0 - lodash: ^4.17.21 - memoizerific: ^1.11.3 - checksum: b9b723259504a24eae3343ca2c1020fd74e748dc7d6e532ca8171d8c3f678418f06708e2332c452480a9c8d56f8abe01e33b9e1ca3153a7bcd7640cdbfa3317b - languageName: node - linkType: hard - "telejson@npm:^7.2.0": version: 7.2.0 resolution: "telejson@npm:7.2.0" @@ -40104,82 +30934,9 @@ __metadata: languageName: node linkType: hard -"terser-webpack-plugin@npm:^1.4.3": - version: 1.4.5 - resolution: "terser-webpack-plugin@npm:1.4.5" - dependencies: - cacache: ^12.0.2 - find-cache-dir: ^2.1.0 - is-wsl: ^1.1.0 - schema-utils: ^1.0.0 - serialize-javascript: ^4.0.0 - source-map: ^0.6.1 - terser: ^4.1.2 - webpack-sources: ^1.4.0 - worker-farm: ^1.7.0 - peerDependencies: - webpack: ^4.0.0 - checksum: 97164cfa383cf988832427e912cd9606471452f15f8bfb905ae51f1a42561f90ea541141e1e530e59f8307639fed7dfdbd626aec8390acd6ad80e58ea3fcf6df - languageName: node - linkType: hard - -"terser-webpack-plugin@npm:^4.2.3": - version: 4.2.3 - resolution: "terser-webpack-plugin@npm:4.2.3" - dependencies: - cacache: ^15.0.5 - find-cache-dir: ^3.3.1 - jest-worker: ^26.5.0 - p-limit: ^3.0.2 - schema-utils: ^3.0.0 - serialize-javascript: ^5.0.1 - source-map: ^0.6.1 - terser: ^5.3.4 - webpack-sources: ^1.4.3 - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: 52bd036b72b596b162e65dce314f1ee7ba1e82b97200d919b61ad50592dc72608b5fe50d7e3f6c0934e42183dfc746b98b922c9e1d00d75253933f799687fa4b - languageName: node - linkType: hard - -"terser-webpack-plugin@npm:^5.3.7": - version: 5.3.9 - resolution: "terser-webpack-plugin@npm:5.3.9" - dependencies: - "@jridgewell/trace-mapping": ^0.3.17 - jest-worker: ^27.4.5 - schema-utils: ^3.1.1 - serialize-javascript: ^6.0.1 - terser: ^5.16.8 - peerDependencies: - webpack: ^5.1.0 - peerDependenciesMeta: - "@swc/core": - optional: true - esbuild: - optional: true - uglify-js: - optional: true - checksum: 8a757106101ea1504e5dc549c722506506e7d3f0d38e72d6c8108ad814c994ca0d67ac5d0825ba59704a4b2b04548201b2137f198bfce897b09fe9e36727a1e9 - languageName: node - linkType: hard - -"terser@npm:^4.1.2, terser@npm:^4.6.3": - version: 4.8.1 - resolution: "terser@npm:4.8.1" - dependencies: - commander: ^2.20.0 - source-map: ~0.6.1 - source-map-support: ~0.5.12 - bin: - terser: bin/terser - checksum: 1ec2620e58df0ea787ac579daf097df0fee2dd402f37acb4de0df1135f0598a29212e5f03042a9c2dc7e1bf1248b1dd9d9ea0724d34331a2017f32da8783b3d7 - languageName: node - linkType: hard - -"terser@npm:^5.0.0, terser@npm:^5.16.8, terser@npm:^5.3.4, terser@npm:^5.7.0": - version: 5.18.2 - resolution: "terser@npm:5.18.2" +"terser@npm:^5.0.0, terser@npm:^5.7.0": + version: 5.31.0 + resolution: "terser@npm:5.31.0" dependencies: "@jridgewell/source-map": ^0.3.3 acorn: ^8.8.2 @@ -40187,7 +30944,7 @@ __metadata: source-map-support: ~0.5.20 bin: terser: bin/terser - checksum: 7a7203eceef379c6381f5b43aaed509d12381c7453baee28b320fcd968523347f1bf4ba297cd3155ec860e9604279a1c9bc7060b35d9c34fae94c80cfa2738c2 + checksum: cb127a579b03fb9dcee0d293ff24814deedcd430f447933b618e8593b7454f615b5c8493c68e86a4b0188769d5ea2af5251b5d507edb208114f7e8aebdc7c850 languageName: node linkType: hard @@ -40248,7 +31005,7 @@ __metadata: languageName: node linkType: hard -"through2@npm:^2.0.0, through2@npm:^2.0.3": +"through2@npm:^2.0.3": version: 2.0.5 resolution: "through2@npm:2.0.5" dependencies: @@ -40272,15 +31029,6 @@ __metadata: languageName: node linkType: hard -"timers-browserify@npm:^2.0.4": - version: 2.0.12 - resolution: "timers-browserify@npm:2.0.12" - dependencies: - setimmediate: ^1.0.4 - checksum: 98e84db1a685bc8827c117a8bc62aac811ad56a995d07938fc7ed8cdc5bf3777bfe2d4e5da868847194e771aac3749a20f6cdd22091300fe889a76fe214a4641 - languageName: node - linkType: hard - "tiny-glob@npm:^0.2.8": version: 0.2.9 resolution: "tiny-glob@npm:0.2.9" @@ -40291,17 +31039,17 @@ __metadata: languageName: node linkType: hard -"tiny-invariant@npm:^1.3.1": - version: 1.3.1 - resolution: "tiny-invariant@npm:1.3.1" - checksum: 5b87c1d52847d9452b60d0dcb77011b459044e0361ca8253bfe7b43d6288106e12af926adb709a6fc28900e3864349b91dad9a4ac93c39aa15f360b26c2ff4db +"tiny-invariant@npm:^1.3.1, tiny-invariant@npm:^1.3.3": + version: 1.3.3 + resolution: "tiny-invariant@npm:1.3.3" + checksum: 65af4a07324b591a059b35269cd696aba21bef2107f29b9f5894d83cc143159a204b299553435b03874ebb5b94d019afa8b8eff241c8a4cfee95872c2e1c1c4a languageName: node linkType: hard "tinybench@npm:^2.5.0": - version: 2.5.1 - resolution: "tinybench@npm:2.5.1" - checksum: 9c55ef25ce1689c3e2fdb89cacbf27dada4d04f846cac70023fe97fc35d2122816d8bbc5b20253e071d13688cf006355d59f0096d22958b818e1e2fe60e5165b + version: 2.8.0 + resolution: "tinybench@npm:2.8.0" + checksum: 5a9a642351fa3e4955e0cbf38f5674be5f3ba6730fd872fd23a5c953ad6c914234d5aba6ea41ef88820180a81829ceece5bd8d3967c490c5171bca1141c2f24d languageName: node linkType: hard @@ -40313,9 +31061,9 @@ __metadata: linkType: hard "tinyspy@npm:^2.1.1": - version: 2.2.0 - resolution: "tinyspy@npm:2.2.0" - checksum: 8c7b70748dd8590e85d52741db79243746c15bc03c92d75c23160a762142db577e7f53e360ba7300e321b12bca5c42dd2522a8dbeec6ba3830302573dd8516bc + version: 2.2.1 + resolution: "tinyspy@npm:2.2.1" + checksum: 0b4cfd07c09871e12c592dfa7b91528124dc49a4766a0b23350638c62e6a483d5a2a667de7e6282246c0d4f09996482ddaacbd01f0c05b7ed7e0f79d32409bdc languageName: node linkType: hard @@ -40342,13 +31090,6 @@ __metadata: languageName: node linkType: hard -"to-arraybuffer@npm:^1.0.0": - version: 1.0.1 - resolution: "to-arraybuffer@npm:1.0.1" - checksum: 2460bd95524f4845a751e4f8bf9937f9f3dcd1651f104e1512868782f858f8302c1cf25bbc30794bc1b3ff65c4e135158377302f2abaff43a2d8e3c38dfe098c - languageName: node - linkType: hard - "to-fast-properties@npm:^2.0.0": version: 2.0.0 resolution: "to-fast-properties@npm:2.0.0" @@ -40397,9 +31138,9 @@ __metadata: linkType: hard "tocbot@npm:^4.20.1": - version: 4.21.2 - resolution: "tocbot@npm:4.21.2" - checksum: 3b3f138368aca22757e85c56230d7db7a0bbcf1d3642258f3c4a16ac910d1dc01f99d0e78b0d965727e1eb9c63ec672f93c55d09554a5807e43459185d5a227b + version: 4.27.19 + resolution: "tocbot@npm:4.27.19" + checksum: d1eaeac26065001ebd7d7abf09992cd632f0370a97b03e3e388bf31959e16972d4d0ddac398e8e00836e5cab0e8402a9ad7807a9d123eda17e0c483223297eef languageName: node linkType: hard @@ -40457,14 +31198,14 @@ __metadata: linkType: hard "tough-cookie@npm:^4.0.0, tough-cookie@npm:^4.1.2": - version: 4.1.3 - resolution: "tough-cookie@npm:4.1.3" + version: 4.1.4 + resolution: "tough-cookie@npm:4.1.4" dependencies: psl: ^1.1.33 punycode: ^2.1.1 universalify: ^0.2.0 url-parse: ^1.5.3 - checksum: 4fc0433a0cba370d57c4b240f30440c848906dee3180bb6e85033143c2726d322e7e4614abb51d42d111ebec119c4876ed8d7247d4113563033eebbc1739c831 + checksum: aca7ff96054f367d53d1e813e62ceb7dd2eda25d7752058a74d64b7266fd07be75908f3753a32ccf866a2f997604b414cfb1916d6e7f69bc64d9d9939b0d6c45 languageName: node linkType: hard @@ -40530,13 +31271,6 @@ __metadata: languageName: node linkType: hard -"trim-newlines@npm:^1.0.0": - version: 1.0.0 - resolution: "trim-newlines@npm:1.0.0" - checksum: ae859c83d0dbcbde32245509f7c51a4bc9696d56e080bc19acc95c4188381e34fba05a4b2fefb47b4ee4537150a11d57a0fd3cd1179837c06210795d7f62e795 - languageName: node - linkType: hard - "trim-newlines@npm:^3.0.0": version: 3.0.1 resolution: "trim-newlines@npm:3.0.1" @@ -40544,40 +31278,19 @@ __metadata: languageName: node linkType: hard -"trim-trailing-lines@npm:^1.0.0": - version: 1.1.4 - resolution: "trim-trailing-lines@npm:1.1.4" - checksum: 95c35ece5fc806e626e7a93a2135c52932d1dee584963138dbefb1df6cb7adcb7a7c68e2c63f05c536f0681c9260e1d5262cb2e234242d23b9a31617b2c1d53c - languageName: node - linkType: hard - -"trim@npm:0.0.1": - version: 0.0.1 - resolution: "trim@npm:0.0.1" - checksum: d974971fc8b8629d13286f20ec6ccc48f480494ca9df358d452beb1fd7eea1b802be41cc7ee157be4abbdf1b3ca79cc6d04c34b14a7026037d437e8de9dacecb - languageName: node - linkType: hard - "triple-beam@npm:^1.3.0": - version: 1.3.0 - resolution: "triple-beam@npm:1.3.0" - checksum: a6da96495f25b6c04b3629df5161c7eb84760927943f16665fd8dcd3a643daadf73d69eee78306b4b68d606937f22f8703afe763bc8d3723632ffb1f3a798493 - languageName: node - linkType: hard - -"trough@npm:^1.0.0": - version: 1.0.5 - resolution: "trough@npm:1.0.5" - checksum: f036d0d7f9bc7cfe5ee650d70b57bb1f048f3292adf6c81bb9b228e546b2b2e5b74ea04a060d21472108a8cda05ec4814bbe86f87ee35c182c50cb41b5c1810a + version: 1.4.1 + resolution: "triple-beam@npm:1.4.1" + checksum: 4bf1db71e14fe3ff1c3adbe3c302f1fdb553b74d7591a37323a7badb32dc8e9c290738996cbb64f8b10dc5a3833645b5d8c26221aaaaa12e50d1251c9aba2fea languageName: node linkType: hard "ts-api-utils@npm:^1.0.1": - version: 1.0.3 - resolution: "ts-api-utils@npm:1.0.3" + version: 1.3.0 + resolution: "ts-api-utils@npm:1.3.0" peerDependencies: typescript: ">=4.2.0" - checksum: 9408338819c3aca2a709f0bc54e3f874227901506cacb1163612a6c8a43df224174feb965a5eafdae16f66fc68fd7bfee8d3275d0fa73fbb8699e03ed26520c9 + checksum: f54a0ba9ed56ce66baea90a3fa087a484002e807f28a8ccb2d070c75e76bde64bd0f6dce98b3802834156306050871b67eec325cb4e918015a360a3f0868c77c languageName: node linkType: hard @@ -40652,73 +31365,7 @@ __metadata: languageName: node linkType: hard -"ts-jest@npm:^27.1.5": - version: 27.1.5 - resolution: "ts-jest@npm:27.1.5" - dependencies: - bs-logger: 0.x - fast-json-stable-stringify: 2.x - jest-util: ^27.0.0 - json5: 2.x - lodash.memoize: 4.x - make-error: 1.x - semver: 7.x - yargs-parser: 20.x - peerDependencies: - "@babel/core": ">=7.0.0-beta.0 <8" - "@types/jest": ^27.0.0 - babel-jest: ">=27.0.0 <28" - jest: ^27.0.0 - typescript: ">=3.8 <5.0" - peerDependenciesMeta: - "@babel/core": - optional: true - "@types/jest": - optional: true - babel-jest: - optional: true - esbuild: - optional: true - bin: - ts-jest: cli.js - checksum: af11586658a0766dcc82ba540448334f8370eb71b22f5d6749b1dc0a203b30e766ab3c02e4c7ed4b1f4c862613c2bb0cbc275d28922bed7d7a06e3b3af73fba1 - languageName: node - linkType: hard - -"ts-jest@npm:^29.0.5, ts-jest@npm:^29.1.1": - version: 29.1.1 - resolution: "ts-jest@npm:29.1.1" - dependencies: - bs-logger: 0.x - fast-json-stable-stringify: 2.x - jest-util: ^29.0.0 - json5: ^2.2.3 - lodash.memoize: 4.x - make-error: 1.x - semver: ^7.5.3 - yargs-parser: ^21.0.1 - peerDependencies: - "@babel/core": ">=7.0.0-beta.0 <8" - "@jest/types": ^29.0.0 - babel-jest: ^29.0.0 - jest: ^29.0.0 - typescript: ">=4.3 <6" - peerDependenciesMeta: - "@babel/core": - optional: true - "@jest/types": - optional: true - babel-jest: - optional: true - esbuild: - optional: true - bin: - ts-jest: cli.js - checksum: 6c45e0aeeff9cc54a64f931c43e1b99f4a1f0ddf44786cc128e7e55603ab7473c8c8f62fd83bd7e51bfe83e3c0c683132152efaeb844516bf7c923f4e92d157d - languageName: node - linkType: hard - -"ts-jest@npm:^29.1.0": +"ts-jest@npm:^29.1.0, ts-jest@npm:^29.1.1": version: 29.1.2 resolution: "ts-jest@npm:29.1.2" dependencies: @@ -40752,8 +31399,8 @@ __metadata: linkType: hard "ts-node@npm:^10.9.1": - version: 10.9.1 - resolution: "ts-node@npm:10.9.1" + version: 10.9.2 + resolution: "ts-node@npm:10.9.2" dependencies: "@cspotcode/source-map-support": ^0.8.0 "@tsconfig/node10": ^1.0.7 @@ -40785,37 +31432,11 @@ __metadata: ts-node-script: dist/bin-script.js ts-node-transpile-only: dist/bin-transpile.js ts-script: dist/bin-script-deprecated.js - checksum: 95187932fb83f3901e22546bd2feeac7d2feb4f412f42ac3a595f049a23e8dcf70516dffb51866391228ea2dbcfaea039e250fb2bb334d48a86ab2b6aea0ae2d + checksum: 5f29938489f96982a25ba650b64218e83a3357d76f7bede80195c65ab44ad279c8357264639b7abdd5d7e75fc269a83daa0e9c62fd8637a3def67254ecc9ddc2 languageName: node linkType: hard -"ts-pnp@npm:^1.1.6": - version: 1.2.0 - resolution: "ts-pnp@npm:1.2.0" - peerDependenciesMeta: - typescript: - optional: true - checksum: ff32b4f810f9d99f676d70fe2c0e327cb6c812214bd4fc7135870b039f9e85a85b2c20f8fe030d9bd36e9598a12faa391f10aecb95df624b92f1af6bd47dc397 - languageName: node - linkType: hard - -"tsc-alias@npm:^1.8.6": - version: 1.8.6 - resolution: "tsc-alias@npm:1.8.6" - dependencies: - chokidar: ^3.5.3 - commander: ^9.0.0 - globby: ^11.0.4 - mylas: ^2.1.9 - normalize-path: ^3.0.0 - plimit-lit: ^1.2.6 - bin: - tsc-alias: dist/bin/index.js - checksum: 0af7162780e7c5d017697b31f59c3f71f3be2b2e313048b0a9fc5fec96e7ba98286b33c9a8275aaf285631559ff18eeffd36422ef863802de784d25e09f1a989 - languageName: node - linkType: hard - -"tsc-alias@npm:^1.8.7": +"tsc-alias@npm:^1.8.6, tsc-alias@npm:^1.8.7": version: 1.8.8 resolution: "tsc-alias@npm:1.8.8" dependencies: @@ -40863,21 +31484,14 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^1, tslib@npm:^1.11.1, tslib@npm:^1.13.0, tslib@npm:^1.8.1, tslib@npm:^1.9.0": +"tslib@npm:^1, tslib@npm:^1.11.1, tslib@npm:^1.13.0, tslib@npm:^1.8.1": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: 69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2 languageName: node linkType: hard -"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.0": - version: 2.6.0 - resolution: "tslib@npm:2.6.0" - checksum: 8d18020a8b9e70ecc529a744c883c095f177805efdbc9786bd50bd82a46c17547923133c5444fbcaf1f7f1c44e0e29c89f73ecf6d8fd1039668024a073a81dc6 - languageName: node - linkType: hard - -"tslib@npm:^2.6.1, tslib@npm:^2.6.2": +"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.1, tslib@npm:^2.6.2": version: 2.6.2 resolution: "tslib@npm:2.6.2" checksum: e03a8a4271152c8b26604ed45535954c0a45296e32445b4b87f8a5abdb2421f40b59b4ca437c4346af0f28179780d604094eb64546bee2019d903d01c6c19bdb @@ -40891,42 +31505,6 @@ __metadata: languageName: node linkType: hard -"tsup@npm:6.7.0": - version: 6.7.0 - resolution: "tsup@npm:6.7.0" - dependencies: - bundle-require: ^4.0.0 - cac: ^6.7.12 - chokidar: ^3.5.1 - debug: ^4.3.1 - esbuild: ^0.17.6 - execa: ^5.0.0 - globby: ^11.0.3 - joycon: ^3.0.1 - postcss-load-config: ^3.0.1 - resolve-from: ^5.0.0 - rollup: ^3.2.5 - source-map: 0.8.0-beta.0 - sucrase: ^3.20.3 - tree-kill: ^1.2.2 - peerDependencies: - "@swc/core": ^1 - postcss: ^8.4.12 - typescript: ">=4.1.0" - peerDependenciesMeta: - "@swc/core": - optional: true - postcss: - optional: true - typescript: - optional: true - bin: - tsup: dist/cli-default.js - tsup-node: dist/cli-node.js - checksum: f6ab9a191b91c68d2bcac9a4df062d26343a9253d5577ee617fa3409e306cb6373ffa6cdb3f6a772e7222a5cf945e330bf6ad9455a7ae3c47aa9eb13f98ac812 - languageName: node - linkType: hard - "tsup@npm:7.1.0": version: 7.1.0 resolution: "tsup@npm:7.1.0" @@ -40963,7 +31541,7 @@ __metadata: languageName: node linkType: hard -"tsup@npm:8.0.1, tsup@npm:^8.0.1": +"tsup@npm:8.0.1": version: 8.0.1 resolution: "tsup@npm:8.0.1" dependencies: @@ -41038,6 +31616,45 @@ __metadata: languageName: node linkType: hard +"tsup@npm:^8.0.1": + version: 8.0.2 + resolution: "tsup@npm:8.0.2" + dependencies: + bundle-require: ^4.0.0 + cac: ^6.7.12 + chokidar: ^3.5.1 + debug: ^4.3.1 + esbuild: ^0.19.2 + execa: ^5.0.0 + globby: ^11.0.3 + joycon: ^3.0.1 + postcss-load-config: ^4.0.1 + resolve-from: ^5.0.0 + rollup: ^4.0.2 + source-map: 0.8.0-beta.0 + sucrase: ^3.20.3 + tree-kill: ^1.2.2 + peerDependencies: + "@microsoft/api-extractor": ^7.36.0 + "@swc/core": ^1 + postcss: ^8.4.12 + typescript: ">=4.5.0" + peerDependenciesMeta: + "@microsoft/api-extractor": + optional: true + "@swc/core": + optional: true + postcss: + optional: true + typescript: + optional: true + bin: + tsup: dist/cli-default.js + tsup-node: dist/cli-node.js + checksum: de3e8b2d9a7a504afb9394f2409ef88fd21dd338a78ebb572dd5c1719d73db816baa7ae4b7867016f08ba6a67560daec13a85768efff1d70e380972e39e27ce6 + languageName: node + linkType: hard + "tsutils@npm:^3.21.0": version: 3.21.0 resolution: "tsutils@npm:3.21.0" @@ -41049,16 +31666,9 @@ __metadata: languageName: node linkType: hard -"tty-browserify@npm:0.0.0": - version: 0.0.0 - resolution: "tty-browserify@npm:0.0.0" - checksum: c0c68206565f1372e924d5cdeeff1a0d9cc729833f1da98c03d78be8f939e5f61a107bd0ab77d1ef6a47d62bb0e48b1081fbea273acf404959e22fd3891439c5 - languageName: node - linkType: hard - "tty-table@npm:^4.1.5": - version: 4.2.1 - resolution: "tty-table@npm:4.2.1" + version: 4.2.3 + resolution: "tty-table@npm:4.2.3" dependencies: chalk: ^4.1.2 csv: ^5.5.3 @@ -41069,7 +31679,7 @@ __metadata: yargs: ^17.7.1 bin: tty-table: adapters/terminal-adapter.js - checksum: 64c302135021a69aba80a122e4d8a7d3172483d331a7ce23c397e8900ca469f2ca50f3be0b5cda318730c04c08b5cdd06d5fa51dcb188ac6fa8ced69b988edf7 + checksum: 408b75693a2b0bae8cd27940c42d9cd29539deb01d90314e708f34f49c80697a3bf55bf5573f02a8aa6dc3ddee78b9e1bcf9ae986d1ec77896ae1d0bd5efb071 languageName: node linkType: hard @@ -41082,58 +31692,58 @@ __metadata: languageName: node linkType: hard -"turbo-darwin-64@npm:1.10.7": - version: 1.10.7 - resolution: "turbo-darwin-64@npm:1.10.7" +"turbo-darwin-64@npm:1.13.3": + version: 1.13.3 + resolution: "turbo-darwin-64@npm:1.13.3" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"turbo-darwin-arm64@npm:1.10.7": - version: 1.10.7 - resolution: "turbo-darwin-arm64@npm:1.10.7" +"turbo-darwin-arm64@npm:1.13.3": + version: 1.13.3 + resolution: "turbo-darwin-arm64@npm:1.13.3" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"turbo-linux-64@npm:1.10.7": - version: 1.10.7 - resolution: "turbo-linux-64@npm:1.10.7" +"turbo-linux-64@npm:1.13.3": + version: 1.13.3 + resolution: "turbo-linux-64@npm:1.13.3" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"turbo-linux-arm64@npm:1.10.7": - version: 1.10.7 - resolution: "turbo-linux-arm64@npm:1.10.7" +"turbo-linux-arm64@npm:1.13.3": + version: 1.13.3 + resolution: "turbo-linux-arm64@npm:1.13.3" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"turbo-windows-64@npm:1.10.7": - version: 1.10.7 - resolution: "turbo-windows-64@npm:1.10.7" +"turbo-windows-64@npm:1.13.3": + version: 1.13.3 + resolution: "turbo-windows-64@npm:1.13.3" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"turbo-windows-arm64@npm:1.10.7": - version: 1.10.7 - resolution: "turbo-windows-arm64@npm:1.10.7" +"turbo-windows-arm64@npm:1.13.3": + version: 1.13.3 + resolution: "turbo-windows-arm64@npm:1.13.3" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard "turbo@npm:^1.6.3": - version: 1.10.7 - resolution: "turbo@npm:1.10.7" + version: 1.13.3 + resolution: "turbo@npm:1.13.3" dependencies: - turbo-darwin-64: 1.10.7 - turbo-darwin-arm64: 1.10.7 - turbo-linux-64: 1.10.7 - turbo-linux-arm64: 1.10.7 - turbo-windows-64: 1.10.7 - turbo-windows-arm64: 1.10.7 + turbo-darwin-64: 1.13.3 + turbo-darwin-arm64: 1.13.3 + turbo-linux-64: 1.13.3 + turbo-linux-arm64: 1.13.3 + turbo-windows-64: 1.13.3 + turbo-windows-arm64: 1.13.3 dependenciesMeta: turbo-darwin-64: optional: true @@ -41149,7 +31759,7 @@ __metadata: optional: true bin: turbo: bin/turbo - checksum: 310412bdd8dd3fd2e5bdd3992fbda31ed467e5f64831326b6aaae6e853c1654207674e43f8d28ba57f39441b33018677b61e38a955f13c1ec603676081df02f2 + checksum: 0382cc88f65a6690e97d30a6ad5d9b9ede7705f5f57edea27629408b166eff4a5938824746ce2cbcd50d2b64ebdbd359160e2cbe009f0bfd6f144997f9f6705b languageName: node linkType: hard @@ -41227,7 +31837,7 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^1.0.1, type-fest@npm:^1.2.2": +"type-fest@npm:^1.0.1": version: 1.4.0 resolution: "type-fest@npm:1.4.0" checksum: a3c0f4ee28ff6ddf800d769eafafcdeab32efa38763c1a1b8daeae681920f6e345d7920bf277245235561d8117dab765cb5f829c76b713b4c9de0998a5397141 @@ -41258,14 +31868,55 @@ __metadata: languageName: node linkType: hard -"typed-array-length@npm:^1.0.4": - version: 1.0.4 - resolution: "typed-array-length@npm:1.0.4" +"typed-array-buffer@npm:^1.0.2": + version: 1.0.2 + resolution: "typed-array-buffer@npm:1.0.2" dependencies: - call-bind: ^1.0.2 + call-bind: ^1.0.7 + es-errors: ^1.3.0 + is-typed-array: ^1.1.13 + checksum: 9e043eb38e1b4df4ddf9dde1aa64919ae8bb909571c1cc4490ba777d55d23a0c74c7d73afcdd29ec98616d91bb3ae0f705fad4421ea147e1daf9528200b562da + languageName: node + linkType: hard + +"typed-array-byte-length@npm:^1.0.1": + version: 1.0.1 + resolution: "typed-array-byte-length@npm:1.0.1" + dependencies: + call-bind: ^1.0.7 for-each: ^0.3.3 - is-typed-array: ^1.1.9 - checksum: c5163c0103d07fefc8a2ad0fc151f9ca9a1f6422098c00f695d55f9896e4d63614cd62cf8d8a031c6cee5f418e8980a533796597174da4edff075b3d275a7e23 + gopd: ^1.0.1 + has-proto: ^1.0.3 + is-typed-array: ^1.1.13 + checksum: fcebeffb2436c9f355e91bd19e2368273b88c11d1acc0948a2a306792f1ab672bce4cfe524ab9f51a0505c9d7cd1c98eff4235c4f6bfef6a198f6cfc4ff3d4f3 + languageName: node + linkType: hard + +"typed-array-byte-offset@npm:^1.0.2": + version: 1.0.2 + resolution: "typed-array-byte-offset@npm:1.0.2" + dependencies: + available-typed-arrays: ^1.0.7 + call-bind: ^1.0.7 + for-each: ^0.3.3 + gopd: ^1.0.1 + has-proto: ^1.0.3 + is-typed-array: ^1.1.13 + checksum: d2628bc739732072e39269389a758025f75339de2ed40c4f91357023c5512d237f255b633e3106c461ced41907c1bf9a533c7e8578066b0163690ca8bc61b22f + languageName: node + linkType: hard + +"typed-array-length@npm:^1.0.6": + version: 1.0.6 + resolution: "typed-array-length@npm:1.0.6" + dependencies: + call-bind: ^1.0.7 + for-each: ^0.3.3 + gopd: ^1.0.1 + has-proto: ^1.0.3 + is-typed-array: ^1.1.13 + possible-typed-array-names: ^1.0.0 + checksum: 74253d7dc488eb28b6b2711cf31f5a9dcefc9c41b0681fd1c178ed0a1681b4468581a3626d39cd4df7aee3d3927ab62be06aa9ca74e5baf81827f61641445b77 languageName: node linkType: hard @@ -41286,20 +31937,20 @@ __metadata: linkType: hard "typeorm@npm:^0.3.16": - version: 0.3.17 - resolution: "typeorm@npm:0.3.17" + version: 0.3.20 + resolution: "typeorm@npm:0.3.20" dependencies: "@sqltools/formatter": ^1.2.5 app-root-path: ^3.1.0 buffer: ^6.0.3 chalk: ^4.1.2 cli-highlight: ^2.1.11 - date-fns: ^2.29.3 + dayjs: ^1.11.9 debug: ^4.3.4 dotenv: ^16.0.3 - glob: ^8.1.0 + glob: ^10.3.10 mkdirp: ^2.1.3 - reflect-metadata: ^0.1.13 + reflect-metadata: ^0.2.1 sha.js: ^2.4.11 tslib: ^2.5.0 uuid: ^9.0.0 @@ -41307,13 +31958,13 @@ __metadata: peerDependencies: "@google-cloud/spanner": ^5.18.0 "@sap/hana-client": ^2.12.25 - better-sqlite3: ^7.1.2 || ^8.0.0 + better-sqlite3: ^7.1.2 || ^8.0.0 || ^9.0.0 hdb-pool: ^0.1.6 ioredis: ^5.0.4 - mongodb: ^5.2.0 - mssql: ^9.1.1 + mongodb: ^5.8.0 + mssql: ^9.1.1 || ^10.0.1 mysql2: ^2.2.5 || ^3.0.1 - oracledb: ^5.1.0 + oracledb: ^6.3.0 pg: ^8.5.1 pg-native: ^3.0.0 pg-query-stream: ^4.0.0 @@ -41361,7 +32012,7 @@ __metadata: typeorm: cli.js typeorm-ts-node-commonjs: cli-ts-node-commonjs.js typeorm-ts-node-esm: cli-ts-node-esm.js - checksum: 589b8e384310cf25061fe1bd8f396eb08340da90fa4d03aa5db6f6be4709ac667ff81e8a4b00e0896c85a79ed05a125b5a2e57c84ab0c22192be55556a46372a + checksum: 7e4be724641beef86ae36289c87b6e66bfaf19a4313f089926d36d2d6f0d67f9314d942711c9d83ab8a174b8622148c2f7e83e6c1448d638ee3ab24469257814 languageName: node linkType: hard @@ -41385,7 +32036,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:5.2.2, typescript@npm:^5.1.6": +"typescript@npm:5.2.2": version: 5.2.2 resolution: "typescript@npm:5.2.2" bin: @@ -41395,7 +32046,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:5.3.3, typescript@npm:^5.3.3": +"typescript@npm:5.3.3": version: 5.3.3 resolution: "typescript@npm:5.3.3" bin: @@ -41405,7 +32056,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.0.4": +"typescript@npm:^5.0.4, typescript@npm:^5.1.6, typescript@npm:^5.3.3": version: 5.4.5 resolution: "typescript@npm:5.4.5" bin: @@ -41435,7 +32086,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@5.2.2#~builtin, typescript@patch:typescript@^5.1.6#~builtin": +"typescript@patch:typescript@5.2.2#~builtin": version: 5.2.2 resolution: "typescript@patch:typescript@npm%3A5.2.2#~builtin::version=5.2.2&hash=7ad353" bin: @@ -41445,7 +32096,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@5.3.3#~builtin, typescript@patch:typescript@^5.3.3#~builtin": +"typescript@patch:typescript@5.3.3#~builtin": version: 5.3.3 resolution: "typescript@patch:typescript@npm%3A5.3.3#~builtin::version=5.3.3&hash=7ad353" bin: @@ -41455,7 +32106,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@^5.0.4#~builtin": +"typescript@patch:typescript@^5.0.4#~builtin, typescript@patch:typescript@^5.1.6#~builtin, typescript@patch:typescript@^5.3.3#~builtin": version: 5.4.5 resolution: "typescript@patch:typescript@npm%3A5.4.5#~builtin::version=5.4.5&hash=7ad353" bin: @@ -41466,16 +32117,16 @@ __metadata: linkType: hard "ua-parser-js@npm:^1.0.35": - version: 1.0.35 - resolution: "ua-parser-js@npm:1.0.35" - checksum: 4641332fdf163ecdec4810cc2335932754f1b71527097f06005a658de256e22f5836a4a7860619c9e611d578e0451ff39dbff1a9b83c6615e3b0b3dd29588c30 + version: 1.0.37 + resolution: "ua-parser-js@npm:1.0.37" + checksum: dac8cf82a55b2e097bd2286954e01454c4cfcf23c9d9b56961ce94bda3cec5a38ca536e6e84c20a4000a9d4b4a4abcbd98ec634ccebe21be36595ea3069126e4 languageName: node linkType: hard -"ufo@npm:^1.3.0": - version: 1.3.1 - resolution: "ufo@npm:1.3.1" - checksum: 9348ff03f76820116c4735625ee894912bc92b6d49dc63474a89a35d2752265421a405f0033b961bb0b885d460c915e7860adb6dc854422faf3483882f14ba86 +"ufo@npm:^1.4.0, ufo@npm:^1.5.3": + version: 1.5.3 + resolution: "ufo@npm:1.5.3" + checksum: 1df10702582aa74f4deac4486ecdfd660e74be057355f1afb6adfa14243476cf3d3acff734ccc3d0b74e9bfdefe91d578f3edbbb0a5b2430fe93cd672370e024 languageName: node linkType: hard @@ -41552,23 +32203,6 @@ __metadata: languageName: node linkType: hard -"unfetch@npm:^4.2.0": - version: 4.2.0 - resolution: "unfetch@npm:4.2.0" - checksum: a5c0a896a6f09f278b868075aea65652ad185db30e827cb7df45826fe5ab850124bf9c44c4dafca4bf0c55a0844b17031e8243467fcc38dd7a7d435007151f1b - languageName: node - linkType: hard - -"unherit@npm:^1.0.4": - version: 1.1.3 - resolution: "unherit@npm:1.1.3" - dependencies: - inherits: ^2.0.0 - xtend: ^4.0.0 - checksum: f953b548e56ef347b14c0897484ff22187acfeeb599afe2994cfdbfaddffe8731b999029e243fd40966b597bdffd541f3b5a54254797b98aebb760bb39dd8456 - languageName: node - linkType: hard - "unicode-canonical-property-names-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" @@ -41607,20 +32241,6 @@ __metadata: languageName: node linkType: hard -"unified@npm:9.2.0": - version: 9.2.0 - resolution: "unified@npm:9.2.0" - dependencies: - bail: ^1.0.0 - extend: ^3.0.0 - is-buffer: ^2.0.0 - is-plain-obj: ^2.0.0 - trough: ^1.0.0 - vfile: ^4.0.0 - checksum: 53aedb794b0ada002b72593d74633f45742e3dfe771a8091c0f51b59119f74f3f1bba0a24c5d72a35629793f992cf9e1debf21aa4689dc718482ffec3a633623 - languageName: node - linkType: hard - "union-value@npm:^1.0.0": version: 1.0.1 resolution: "union-value@npm:1.0.1" @@ -41633,15 +32253,6 @@ __metadata: languageName: node linkType: hard -"unique-filename@npm:^1.1.1": - version: 1.1.1 - resolution: "unique-filename@npm:1.1.1" - dependencies: - unique-slug: ^2.0.0 - checksum: d005bdfaae6894da8407c4de2b52f38b3c58ec86e79fc2ee19939da3085374413b073478ec54e721dc8e32b102cf9e50d0481b8331abdc62202e774b789ea874 - languageName: node - linkType: hard - "unique-filename@npm:^3.0.0": version: 3.0.0 resolution: "unique-filename@npm:3.0.0" @@ -41651,15 +32262,6 @@ __metadata: languageName: node linkType: hard -"unique-slug@npm:^2.0.0": - version: 2.0.2 - resolution: "unique-slug@npm:2.0.2" - dependencies: - imurmurhash: ^0.1.4 - checksum: 9eabc51680cf0b8b197811a48857e41f1364b25362300c1ff636c0eca5ec543a92a38786f59cf0697e62c6f814b11ecbe64e8093db71246468a1f03b80c83970 - languageName: node - linkType: hard - "unique-slug@npm:^4.0.0": version: 4.0.0 resolution: "unique-slug@npm:4.0.0" @@ -41687,20 +32289,6 @@ __metadata: languageName: node linkType: hard -"unist-builder@npm:2.0.3, unist-builder@npm:^2.0.0": - version: 2.0.3 - resolution: "unist-builder@npm:2.0.3" - checksum: d8b13ffd774bfe6175ca988d63cbaf6d85882a0701d6158597134ce1c3acf665a09421461a4036704f77edb8a6a2792d09eb55382428c2a9a60488b44909eeae - languageName: node - linkType: hard - -"unist-util-generated@npm:^1.0.0": - version: 1.1.6 - resolution: "unist-util-generated@npm:1.1.6" - checksum: ee04a58a6711145ec5c8c6f10dfd3335ac93d9039dc35e7410ffc1299d6f3671b27d9b7aa486f826bd66ec15807ad6d0bf9348b34a1046440e1617abcf42903f - languageName: node - linkType: hard - "unist-util-is@npm:^4.0.0": version: 4.1.0 resolution: "unist-util-is@npm:4.1.0" @@ -41708,40 +32296,6 @@ __metadata: languageName: node linkType: hard -"unist-util-position@npm:^3.0.0": - version: 3.1.0 - resolution: "unist-util-position@npm:3.1.0" - checksum: a89d4095560f01e0ddfdab3deae6abd250ee6b91c3b23922de05297227a4aede076d96cb0e22e9962d0e85f54d11f719d1e11388233d0936631b8527485a02a8 - languageName: node - linkType: hard - -"unist-util-remove-position@npm:^2.0.0": - version: 2.0.1 - resolution: "unist-util-remove-position@npm:2.0.1" - dependencies: - unist-util-visit: ^2.0.0 - checksum: 9aadc8e9fafc4eeb04462454ab084184b84b397a367cab3787c59411b16c8f03d13e80e9ffd6bdae68bf8e5175f42008f410288a041a6ee53bcac8ced45a12ed - languageName: node - linkType: hard - -"unist-util-remove@npm:^2.0.0": - version: 2.1.0 - resolution: "unist-util-remove@npm:2.1.0" - dependencies: - unist-util-is: ^4.0.0 - checksum: f7dea56fb720ddab5e406af12ce37453b028273e23a7cc3e4c9f3f1ec85e1f72c6943a1ebb907120c9be0b1d08b209d7b8c7d2191a5012e16081056edf638df9 - languageName: node - linkType: hard - -"unist-util-stringify-position@npm:^2.0.0": - version: 2.0.3 - resolution: "unist-util-stringify-position@npm:2.0.3" - dependencies: - "@types/unist": ^2.0.2 - checksum: 46fa03f840df173b7f032cbfffdb502fb05b79b3fb5451681c796cf4985d9087a537833f5afb75d55e79b46bbbe4b3d81dd75a1062f9289091c526aebe201d5d - languageName: node - linkType: hard - "unist-util-visit-parents@npm:^3.0.0": version: 3.1.1 resolution: "unist-util-visit-parents@npm:3.1.1" @@ -41752,7 +32306,7 @@ __metadata: languageName: node linkType: hard -"unist-util-visit@npm:2.0.3, unist-util-visit@npm:^2.0.0": +"unist-util-visit@npm:^2.0.0": version: 2.0.3 resolution: "unist-util-visit@npm:2.0.3" dependencies: @@ -41778,9 +32332,9 @@ __metadata: linkType: hard "universalify@npm:^2.0.0": - version: 2.0.0 - resolution: "universalify@npm:2.0.0" - checksum: 07092b9f46df61b823d8ab5e57f0ee5120c178b39609a95e4a15a98c42f6b0b8e834e66fbb47ff92831786193be42f1fd36347169b88ce8639d0f9670af24a71 + version: 2.0.1 + resolution: "universalify@npm:2.0.1" + checksum: 73e8ee3809041ca8b818efb141801a1004e3fc0002727f1531f4de613ea281b494a40909596dae4a042a4fb6cd385af5d4db2e137b1362e0e91384b828effd3a languageName: node linkType: hard @@ -41799,14 +32353,14 @@ __metadata: linkType: hard "unplugin@npm:^1.3.1": - version: 1.5.0 - resolution: "unplugin@npm:1.5.0" + version: 1.10.1 + resolution: "unplugin@npm:1.10.1" dependencies: - acorn: ^8.10.0 - chokidar: ^3.5.3 + acorn: ^8.11.3 + chokidar: ^3.6.0 webpack-sources: ^3.2.3 - webpack-virtual-modules: ^0.5.0 - checksum: 2f79a7bf6b428a6aac80bf21852ed83cafead0ae3ed8866db1dca1cd4489f3b50c95874275e9a9b0f10c2e3c4892bfe0431c70d13635775c4c620a6a3f9eae37 + webpack-virtual-modules: ^0.6.1 + checksum: 6fe469785a46ff2a2d5c077db8b8b8d2c5429016f2561cffed4eb0068ea085c50b8c503891a4ea028f8226da0b9a8b878118a0b9eeded511b53adec4edbb38d3 languageName: node linkType: hard @@ -41820,15 +32374,6 @@ __metadata: languageName: node linkType: hard -"untildify@npm:^2.0.0": - version: 2.1.0 - resolution: "untildify@npm:2.1.0" - dependencies: - os-homedir: ^1.0.0 - checksum: 8a8a8766fcac7a796104d2124d1951af87889e95fd73d5704c78000fb0612fe21041eb33eadb7b4dedc44dd99db3c4adba04775454990baf7c4b728076ab2bc2 - languageName: node - linkType: hard - "untildify@npm:^4.0.0": version: 4.0.0 resolution: "untildify@npm:4.0.0" @@ -41843,35 +32388,21 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.0.11": - version: 1.0.11 - resolution: "update-browserslist-db@npm:1.0.11" - dependencies: - escalade: ^3.1.1 - picocolors: ^1.0.0 - peerDependencies: - browserslist: ">= 4.21.0" - bin: - update-browserslist-db: cli.js - checksum: 280d5cf92e302d8de0c12ef840a6af26ec024a5158aa2020975cd01bf0ded09c709793a6f421e6d0f1a47557d6a1a10dc43af80f9c30b8fd0df9691eb98c1c69 - languageName: node - linkType: hard - "update-browserslist-db@npm:^1.0.13": - version: 1.0.13 - resolution: "update-browserslist-db@npm:1.0.13" + version: 1.0.15 + resolution: "update-browserslist-db@npm:1.0.15" dependencies: - escalade: ^3.1.1 + escalade: ^3.1.2 picocolors: ^1.0.0 peerDependencies: browserslist: ">= 4.21.0" bin: update-browserslist-db: cli.js - checksum: e52b8b521c78ce1e0c775f356cd16a9c22c70d25f3e01180839c407a5dc787fb05a13f67560cbaf316770d26fa99f78f1acd711b1b54a4f35d4820d4ea7136e6 + checksum: c5f67dc68aba9a37701a14199e57e22f20c579411d386f47b4d81f6e3f06fd3ec256310594f4f9d6b01bc1cfb93cb1ebb1a1da70c4fa28720bc1d030f55bb8a1 languageName: node linkType: hard -"uri-js@npm:^4.2.2": +"uri-js@npm:^4.2.2, uri-js@npm:^4.4.1": version: 4.4.1 resolution: "uri-js@npm:4.4.1" dependencies: @@ -41887,23 +32418,6 @@ __metadata: languageName: node linkType: hard -"url-loader@npm:^4.1.1": - version: 4.1.1 - resolution: "url-loader@npm:4.1.1" - dependencies: - loader-utils: ^2.0.0 - mime-types: ^2.1.27 - schema-utils: ^3.0.0 - peerDependencies: - file-loader: "*" - webpack: ^4.0.0 || ^5.0.0 - peerDependenciesMeta: - file-loader: - optional: true - checksum: 71b6300e02ce26c70625eae1a2297c0737635038c62691bb3007ac33e85c0130efc74bfb444baf5c6b3bad5953491159d31d66498967d1417865d0c7e7cd1a64 - languageName: node - linkType: hard - "url-parse@npm:^1.5.3": version: 1.5.10 resolution: "url-parse@npm:1.5.10" @@ -41921,19 +32435,9 @@ __metadata: languageName: node linkType: hard -"url@npm:^0.11.0": - version: 0.11.1 - resolution: "url@npm:0.11.1" - dependencies: - punycode: ^1.4.1 - qs: ^6.11.0 - checksum: 9e18c57b854d6a8e0288c4ddf21f9e30273a0ef2efb28a7e3e3d6eac392637dbdecce0d8f616586d58ff43154997150ecc2c9873e6c845d1e742e24c940b6e12 - languageName: node - linkType: hard - "use-callback-ref@npm:^1.3.0": - version: 1.3.0 - resolution: "use-callback-ref@npm:1.3.0" + version: 1.3.2 + resolution: "use-callback-ref@npm:1.3.2" dependencies: tslib: ^2.0.0 peerDependencies: @@ -41942,42 +32446,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 8a0867ffd441f358c66d79567970a745cc78ac2f98840a81c1fa749a525e8716116c645497d886a815e1dcf40ad81a107ebd6a7d15fd9ab5925c44a994a1d89a - languageName: node - linkType: hard - -"use-composed-ref@npm:^1.3.0": - version: 1.3.0 - resolution: "use-composed-ref@npm:1.3.0" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: e64ce52f4b18c020407636784192726807404a2552609acf7497b66a2b7070674fb5d2b950d426c4aa85f353e2bbecb02ebf9c5b865cd06797938c70bcbf5d26 - languageName: node - linkType: hard - -"use-isomorphic-layout-effect@npm:^1.1.1": - version: 1.1.2 - resolution: "use-isomorphic-layout-effect@npm:1.1.2" - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: d8deea8b85e55ac6daba237a889630bfdbf0ebf60e9e22b6a78a78c26fabe6025e04ada7abef1e444e6786227d921e648b2707db8b3564daf757264a148a6e23 - languageName: node - linkType: hard - -"use-latest@npm:^1.2.1": - version: 1.2.1 - resolution: "use-latest@npm:1.2.1" - dependencies: - use-isomorphic-layout-effect: ^1.1.1 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 1958886fc35262d973f5cd4ce16acd6ce3a66707a72761c93abd1b5ae64e1a11efa83f68e6c8c9bf1647628037980ce59df64cba50adb36bd4071851e70527d2 + checksum: d232c37160fe3970c99255da19b5fb5299fb5926a5d6141d928a87feb47732c323d29be2f8137d3b1e5499c70d284cd1d9cfad703cc58179db8be24d7dd8f1f2 languageName: node linkType: hard @@ -42010,11 +32479,11 @@ __metadata: linkType: hard "use-sync-external-store@npm:^1.2.0": - version: 1.2.0 - resolution: "use-sync-external-store@npm:1.2.0" + version: 1.2.2 + resolution: "use-sync-external-store@npm:1.2.2" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: ac4814e5592524f242921157e791b022efe36e451fe0d4fd4d204322d5433a4fc300d63b0ade5185f8e0735ded044c70bcf6d2352db0f74d097a238cebd2da02 + checksum: 23b1597c10adf15b26ade9e8c318d8cc0abc9ec0ab5fc7ca7338da92e89c2536abd150a5891bf076836c352fdfa104fc7231fb48f806fd9960e0cbe03601abaf languageName: node linkType: hard @@ -42032,34 +32501,6 @@ __metadata: languageName: node linkType: hard -"util.promisify@npm:1.0.0": - version: 1.0.0 - resolution: "util.promisify@npm:1.0.0" - dependencies: - define-properties: ^1.1.2 - object.getownpropertydescriptors: ^2.0.3 - checksum: af9df9d111b1464586e4fa414ccf6de61c3a14c0664a66a497438a0507d47f65389f5e025c048ef7e2bf6dba73e95adc3d0c56111a0952ae0282817fc4dd83b2 - languageName: node - linkType: hard - -"util@npm:0.10.3": - version: 0.10.3 - resolution: "util@npm:0.10.3" - dependencies: - inherits: 2.0.1 - checksum: 88bb58fec3b1f5f43dea27795f61f24b3b505bbba6f3ad6e91b32db0cd0928b2acb54ebe21603a75743c6e21a52f954cd2ffb6cddafed5a01169dd1287db3ff3 - languageName: node - linkType: hard - -"util@npm:^0.11.0": - version: 0.11.1 - resolution: "util@npm:0.11.1" - dependencies: - inherits: 2.0.3 - checksum: 8e9d1a85e661c8a8d9883d821aedbff3f8d9c3accd85357020905386ada5653b20389fc3591901e2a0bde64f8dc86b28c3f990114aa5a38eaaf30b455fa3cdf6 - languageName: node - linkType: hard - "util@npm:^0.12.4, util@npm:^0.12.5": version: 0.12.5 resolution: "util@npm:0.12.5" @@ -42073,13 +32514,6 @@ __metadata: languageName: node linkType: hard -"utila@npm:~0.4": - version: 0.4.0 - resolution: "utila@npm:0.4.0" - checksum: 2791604e09ca4f77ae314df83e80d1805f867eb5c7e13e7413caee01273c278cf2c9a3670d8d25c889a877f7b149d892fe61b0181a81654b425e9622ab23d42e - languageName: node - linkType: hard - "utils-merge@npm:1.0.1, utils-merge@npm:^1.0.1": version: 1.0.1 resolution: "utils-merge@npm:1.0.1" @@ -42087,13 +32521,6 @@ __metadata: languageName: node linkType: hard -"uuid-browser@npm:^3.1.0": - version: 3.1.0 - resolution: "uuid-browser@npm:3.1.0" - checksum: bfb6bcc8cc75c1adf776370c4f86d00ee5682f7315c8bccb99938e53dafae189ef6a4dc125e67abd2a2cdfaad6020690fe4cb67dbd5b39f32d3ba75fb713d807 - languageName: node - linkType: hard - "uuid@npm:^3.3.2": version: 3.4.0 resolution: "uuid@npm:3.4.0" @@ -42112,16 +32539,7 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^9.0.0": - version: 9.0.0 - resolution: "uuid@npm:9.0.0" - bin: - uuid: dist/bin/uuid - checksum: 8867e438990d1d33ac61093e2e4e3477a2148b844e4fa9e3c2360fa4399292429c4b6ec64537eb1659c97b2d10db349c673ad58b50e2824a11e0d3630de3c056 - languageName: node - linkType: hard - -"uuid@npm:^9.0.1": +"uuid@npm:^9.0.0, uuid@npm:^9.0.1": version: 9.0.1 resolution: "uuid@npm:9.0.1" bin: @@ -42138,9 +32556,9 @@ __metadata: linkType: hard "v8-compile-cache@npm:^2.0.3": - version: 2.3.0 - resolution: "v8-compile-cache@npm:2.3.0" - checksum: b2d866febf943fbbf0b5e8d43ae9a9b0dacd11dd76e6a9c8e8032268f0136f081e894a2723774ae2d86befa994be4d4046b0717d82df4f3a10e067994ad5c688 + version: 2.4.0 + resolution: "v8-compile-cache@npm:2.4.0" + checksum: 387851192545e7f4d691ba674de90890bba76c0f08ee4909ab862377f556221e75b3a361466490e201203401d64d7795f889882bdabc98b6f3c0bf1038a535be languageName: node linkType: hard @@ -42177,25 +32595,14 @@ __metadata: languageName: node linkType: hard -"v8-to-istanbul@npm:^9.0.0, v8-to-istanbul@npm:^9.0.1": - version: 9.1.0 - resolution: "v8-to-istanbul@npm:9.1.0" - dependencies: - "@jridgewell/trace-mapping": ^0.3.12 - "@types/istanbul-lib-coverage": ^2.0.1 - convert-source-map: ^1.6.0 - checksum: 657ef7c52a514c1a0769663f96dd6f2cd11d2d3f6c8272d1035f4a543dca0b52c84b005beb7f0ca215eb98425c8bc4aa92a62826b1fc76abc1f7228d33ccbc60 - languageName: node - linkType: hard - -"v8-to-istanbul@npm:^9.1.0": - version: 9.1.3 - resolution: "v8-to-istanbul@npm:9.1.3" +"v8-to-istanbul@npm:^9.0.1, v8-to-istanbul@npm:^9.1.0": + version: 9.2.0 + resolution: "v8-to-istanbul@npm:9.2.0" dependencies: "@jridgewell/trace-mapping": ^0.3.12 "@types/istanbul-lib-coverage": ^2.0.1 convert-source-map: ^2.0.0 - checksum: 7acfc460731b629a0d547b231e9d510aaa826df67f4deeaeeb991b492f78faf3bb1aa4b54fa0f9b06d815bc69eb0a04a6c2180c16ba43a83cc5e5490fa160a96 + checksum: e691ba4dd0dea4a884e52c37dbda30cce6f9eeafe9b26721e449429c6bb0f4b6d1e33fabe7711d0f67f7a34c3bfd56c873f7375bba0b1534e6a2843ce99550e5 languageName: node linkType: hard @@ -42218,14 +32625,7 @@ __metadata: languageName: node linkType: hard -"validator@npm:^13.7.0": - version: 13.9.0 - resolution: "validator@npm:13.9.0" - checksum: 0a0af4b37779671b53ef790aa9d36f71a605c9d41c6daf198d2a1051ce549bcdca3313fa3b52c8fa24577e1a4968ec9404ad8a928d3607d51bccef6d6e33bee7 - languageName: node - linkType: hard - -"validator@npm:^13.9.0": +"validator@npm:^13.7.0, validator@npm:^13.9.0": version: 13.11.0 resolution: "validator@npm:13.11.0" checksum: 0107da3add5a4ebc6391dac103c55f6d8ed055bbcc29a4c9cbf89eacfc39ba102a5618c470bdc33c6487d30847771a892134a8c791f06ef0962dd4b7a60ae0f5 @@ -42323,35 +32723,6 @@ __metadata: languageName: node linkType: hard -"vfile-location@npm:^3.0.0, vfile-location@npm:^3.2.0": - version: 3.2.0 - resolution: "vfile-location@npm:3.2.0" - checksum: d9513c738fcac26388f4ee04337663514434df718201309088377b53be3fdcfdb01a4a8f02f5a21ebf33690a670f31229e4c7c3991fb7af63f549fda3ec36836 - languageName: node - linkType: hard - -"vfile-message@npm:^2.0.0": - version: 2.0.4 - resolution: "vfile-message@npm:2.0.4" - dependencies: - "@types/unist": ^2.0.0 - unist-util-stringify-position: ^2.0.0 - checksum: ce50d90e0e5dc8f995f39602dd2404f1756388a54209c983d259b17c15e6f262a53546977a638065bc487d0657799fa96f4c1ba6b2915d9724a4968e9c7ff1c8 - languageName: node - linkType: hard - -"vfile@npm:^4.0.0": - version: 4.2.1 - resolution: "vfile@npm:4.2.1" - dependencies: - "@types/unist": ^2.0.0 - is-buffer: ^2.0.0 - unist-util-stringify-position: ^2.0.0 - vfile-message: ^2.0.0 - checksum: 4816aecfedc794ba4d3131abff2032ef0e825632cfa8cd20dd9d83819ef260589924f4f3e8fa30e06da2d8e60d7ec8ef7d0af93e0483df62890738258daf098a - languageName: node - linkType: hard - "vite-node@npm:0.32.4": version: 0.32.4 resolution: "vite-node@npm:0.32.4" @@ -42416,8 +32787,8 @@ __metadata: linkType: hard "vite@npm:^3.0.0 || ^4.0.0, vite@npm:^4.3.9": - version: 4.5.0 - resolution: "vite@npm:4.5.0" + version: 4.5.3 + resolution: "vite@npm:4.5.3" dependencies: esbuild: ^0.18.10 fsevents: ~2.3.2 @@ -42451,7 +32822,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 7e21e9e4b80656ae5ee61e8c5edb5e8f589139c2b22c43e89d054c65a0194f1c1ef066fbc770204173c7eb244c798265042f988adda5880ad74337a053b28b7f + checksum: caeb1eecc0a8e0865782899e2f83d2993a9816562badc1c8291316d80d49b82f12038abd8cb8b8c627b6f369f58dfb25972ef4517d5e6e1b6e1bf7ee5b63a8a6 languageName: node linkType: hard @@ -42515,13 +32886,6 @@ __metadata: languageName: node linkType: hard -"vm-browserify@npm:^1.0.1": - version: 1.1.2 - resolution: "vm-browserify@npm:1.1.2" - checksum: 0cc1af6e0d880deb58bc974921320c187f9e0a94f25570fca6b1bd64e798ce454ab87dfd797551b1b0cc1849307421aae0193cedf5f06bdb5680476780ee344b - languageName: node - linkType: hard - "void-elements@npm:3.1.0": version: 3.1.0 resolution: "void-elements@npm:3.1.0" @@ -42591,39 +32955,13 @@ __metadata: languageName: node linkType: hard -"watchpack-chokidar2@npm:^2.0.1": - version: 2.0.1 - resolution: "watchpack-chokidar2@npm:2.0.1" - dependencies: - chokidar: ^2.1.8 - checksum: 9b8d880ae2543dd4f26a69f6b7f881119494f6b772b7431027a06a5cf963e0ebc1cac91a3ef479365c358b693c65fa80a1f8297427fa11fd4c080c3d6408c372 - languageName: node - linkType: hard - -"watchpack@npm:^1.7.4": - version: 1.7.5 - resolution: "watchpack@npm:1.7.5" - dependencies: - chokidar: ^3.4.1 - graceful-fs: ^4.1.2 - neo-async: ^2.5.0 - watchpack-chokidar2: ^2.0.1 - dependenciesMeta: - chokidar: - optional: true - watchpack-chokidar2: - optional: true - checksum: 53e3b112064f5de9edbb2a14973fb3901d9697b24cc70f8531a143eaace2353a273ca25c0ba21def8d3803cfedb8f6861ca1e49e9782257e40d5b5f8f5365c86 - languageName: node - linkType: hard - -"watchpack@npm:^2.2.0, watchpack@npm:^2.4.0": - version: 2.4.0 - resolution: "watchpack@npm:2.4.0" +"watchpack@npm:^2.2.0": + version: 2.4.1 + resolution: "watchpack@npm:2.4.1" dependencies: glob-to-regexp: ^0.4.1 graceful-fs: ^4.1.2 - checksum: c5e35f9fb9338d31d2141d9835643c0f49b5f9c521440bb648181059e5940d93dd8ed856aa8a33fbcdd4e121dad63c7e8c15c063cf485429cd9d427be197fe62 + checksum: c694de0a61004e587a8a0fdc9cfec20ee692c52032d9ab2c2e99969a37fdab9e6e1bd3164ed506f9a13f7c83e65563d563e0d6b87358470cdb7309b83db78683 languageName: node linkType: hard @@ -42636,13 +32974,6 @@ __metadata: languageName: node linkType: hard -"web-namespaces@npm:^1.0.0": - version: 1.1.4 - resolution: "web-namespaces@npm:1.1.4" - checksum: 05b5782c32a33ef94fa7a412afdebc9d0d3cc7b59db31d2cc7bd80de3e237d4b6309cb5f156d06e3a837b9826c9414448c25111ec1d4407d2025ffeb7bea4f62 - languageName: node - linkType: hard - "web-streams-polyfill@npm:^3.0.3": version: 3.3.3 resolution: "web-streams-polyfill@npm:3.3.3" @@ -42685,61 +33016,6 @@ __metadata: languageName: node linkType: hard -"webpack-dev-middleware@npm:^3.7.3": - version: 3.7.3 - resolution: "webpack-dev-middleware@npm:3.7.3" - dependencies: - memory-fs: ^0.4.1 - mime: ^2.4.4 - mkdirp: ^0.5.1 - range-parser: ^1.2.1 - webpack-log: ^2.0.0 - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: f9bd8318c6f356d006dc99e3e46ef8870d67640e43f26cfcd2bb36c9e7eaf64015513f43498e92b532896f7fbd8f32c0710d4489fc81d7a45ea328d7e4cf3085 - languageName: node - linkType: hard - -"webpack-filter-warnings-plugin@npm:^1.2.1": - version: 1.2.1 - resolution: "webpack-filter-warnings-plugin@npm:1.2.1" - peerDependencies: - webpack: ^2.0.0 || ^3.0.0 || ^4.0.0 - checksum: 0a30b2b7725e4d4de96701d3a76b10d1e6a6e502a26e64177d8bcb1ba16a34dc87ab82f588b5b46620f105ac471c3b76e5f2810244b373efbdf6d3dc193553da - languageName: node - linkType: hard - -"webpack-hot-middleware@npm:^2.25.1": - version: 2.25.4 - resolution: "webpack-hot-middleware@npm:2.25.4" - dependencies: - ansi-html-community: 0.0.8 - html-entities: ^2.1.0 - strip-ansi: ^6.0.0 - checksum: c0702d308a39bdbc9277d66df50272e8c358c2238cecb0881df57136f54cb7a3d8291320b13075325b58f7a3cbf7a1ef10829554a5bc2ddfa3effbf416dc8e8c - languageName: node - linkType: hard - -"webpack-log@npm:^2.0.0": - version: 2.0.0 - resolution: "webpack-log@npm:2.0.0" - dependencies: - ansi-colors: ^3.0.0 - uuid: ^3.3.2 - checksum: 515b800433da1c0b5722317baaeb05fc185da5a1fde5e39d25bed0b05c13ee3a544aa13844db8590696274a3c5dc04fd5abdd39f38f8c46a4084b74ff0dc9c60 - languageName: node - linkType: hard - -"webpack-sources@npm:^1.4.0, webpack-sources@npm:^1.4.1, webpack-sources@npm:^1.4.3": - version: 1.4.3 - resolution: "webpack-sources@npm:1.4.3" - dependencies: - source-list-map: ^2.0.0 - source-map: ~0.6.1 - checksum: 78dafb3e1e297d3f4eb6204311e8c64d28cd028f82887ba33aaf03fffc82482d8e1fdf6de25a60f4dde621d3565f4c3b1bfb350f09add8f4e54e00279ff3db5e - languageName: node - linkType: hard - "webpack-sources@npm:^3.2.3": version: 3.2.3 resolution: "webpack-sources@npm:3.2.3" @@ -42747,94 +33023,10 @@ __metadata: languageName: node linkType: hard -"webpack-virtual-modules@npm:^0.2.2": - version: 0.2.2 - resolution: "webpack-virtual-modules@npm:0.2.2" - dependencies: - debug: ^3.0.0 - checksum: 1e4156cbc7d64fde1a4531c3a2f92ccbe5702f16c34e3379ea302f7917b8c6c52f91328b893b615a34531a69c1e5079ec3b2edb7479f9908bd8243006437daa3 - languageName: node - linkType: hard - -"webpack-virtual-modules@npm:^0.5.0": - version: 0.5.0 - resolution: "webpack-virtual-modules@npm:0.5.0" - checksum: 0742e069cd49d91ccd0b59431b3666903d321582c1b1062fa6bdae005c3538af55ff8787ea5eafbf72662f3496d3a879e2c705d55ca0af8283548a925be18484 - languageName: node - linkType: hard - -"webpack@npm:4": - version: 4.46.0 - resolution: "webpack@npm:4.46.0" - dependencies: - "@webassemblyjs/ast": 1.9.0 - "@webassemblyjs/helper-module-context": 1.9.0 - "@webassemblyjs/wasm-edit": 1.9.0 - "@webassemblyjs/wasm-parser": 1.9.0 - acorn: ^6.4.1 - ajv: ^6.10.2 - ajv-keywords: ^3.4.1 - chrome-trace-event: ^1.0.2 - enhanced-resolve: ^4.5.0 - eslint-scope: ^4.0.3 - json-parse-better-errors: ^1.0.2 - loader-runner: ^2.4.0 - loader-utils: ^1.2.3 - memory-fs: ^0.4.1 - micromatch: ^3.1.10 - mkdirp: ^0.5.3 - neo-async: ^2.6.1 - node-libs-browser: ^2.2.1 - schema-utils: ^1.0.0 - tapable: ^1.1.3 - terser-webpack-plugin: ^1.4.3 - watchpack: ^1.7.4 - webpack-sources: ^1.4.1 - peerDependenciesMeta: - webpack-cli: - optional: true - webpack-command: - optional: true - bin: - webpack: bin/webpack.js - checksum: 3451b48b926d7c295a4eba65bb7ff9a7d2d49a848014ea0945f446ebf4c1ca5bdd15681b444f5dfd8bbc4856afda55211d30a173ae721b8108f229792e6fb509 - languageName: node - linkType: hard - -"webpack@npm:>=4.43.0 <6.0.0": - version: 5.88.1 - resolution: "webpack@npm:5.88.1" - dependencies: - "@types/eslint-scope": ^3.7.3 - "@types/estree": ^1.0.0 - "@webassemblyjs/ast": ^1.11.5 - "@webassemblyjs/wasm-edit": ^1.11.5 - "@webassemblyjs/wasm-parser": ^1.11.5 - acorn: ^8.7.1 - acorn-import-assertions: ^1.9.0 - browserslist: ^4.14.5 - chrome-trace-event: ^1.0.2 - enhanced-resolve: ^5.15.0 - es-module-lexer: ^1.2.1 - eslint-scope: 5.1.1 - events: ^3.2.0 - glob-to-regexp: ^0.4.1 - graceful-fs: ^4.2.9 - json-parse-even-better-errors: ^2.3.1 - loader-runner: ^4.2.0 - mime-types: ^2.1.27 - neo-async: ^2.6.2 - schema-utils: ^3.2.0 - tapable: ^2.1.1 - terser-webpack-plugin: ^5.3.7 - watchpack: ^2.4.0 - webpack-sources: ^3.2.3 - peerDependenciesMeta: - webpack-cli: - optional: true - bin: - webpack: bin/webpack.js - checksum: 03389ad02342becf527c2f603b46bedb27f5352703e6a625daa9a1f80ed84417e135fbcd8a2a79d6aaf37aafb8b8b571cd920bad4b068ca76c629252b3bfc9d7 +"webpack-virtual-modules@npm:^0.6.1": + version: 0.6.1 + resolution: "webpack-virtual-modules@npm:0.6.1" + checksum: 696bdc1acf3806374bdeb4b9b9856b79ee70b31e92f325dfab9b8c8c7e14bb6ddffa9f895a214770c4fb8fea45a21f34ca64310f74e877292a90f4a9966c9c2f languageName: node linkType: hard @@ -42935,15 +33127,35 @@ __metadata: languageName: node linkType: hard -"which-collection@npm:^1.0.1": - version: 1.0.1 - resolution: "which-collection@npm:1.0.1" +"which-builtin-type@npm:^1.1.3": + version: 1.1.3 + resolution: "which-builtin-type@npm:1.1.3" dependencies: - is-map: ^2.0.1 - is-set: ^2.0.1 - is-weakmap: ^2.0.1 - is-weakset: ^2.0.1 - checksum: 249f913e1758ed2f06f00706007d87dc22090a80591a56917376e70ecf8fc9ab6c41d98e1c87208bb9648676f65d4b09c0e4d23c56c7afb0f0a73a27d701df5d + function.prototype.name: ^1.1.5 + has-tostringtag: ^1.0.0 + is-async-function: ^2.0.0 + is-date-object: ^1.0.5 + is-finalizationregistry: ^1.0.2 + is-generator-function: ^1.0.10 + is-regex: ^1.1.4 + is-weakref: ^1.0.2 + isarray: ^2.0.5 + which-boxed-primitive: ^1.0.2 + which-collection: ^1.0.1 + which-typed-array: ^1.1.9 + checksum: 2b7b234df3443b52f4fbd2b65b731804de8d30bcc4210ec84107ef377a81923cea7f2763b7fb78b394175cea59118bf3c41b9ffd2d643cb1d748ef93b33b6bd4 + languageName: node + linkType: hard + +"which-collection@npm:^1.0.1": + version: 1.0.2 + resolution: "which-collection@npm:1.0.2" + dependencies: + is-map: ^2.0.3 + is-set: ^2.0.3 + is-weakmap: ^2.0.2 + is-weakset: ^2.0.3 + checksum: 3345fde20964525a04cdf7c4a96821f85f0cc198f1b2ecb4576e08096746d129eb133571998fe121c77782ac8f21cbd67745a3d35ce100d26d4e684c142ea1f2 languageName: node linkType: hard @@ -42964,17 +33176,16 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.2, which-typed-array@npm:^1.1.9": - version: 1.1.9 - resolution: "which-typed-array@npm:1.1.9" +"which-typed-array@npm:^1.1.13, which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15, which-typed-array@npm:^1.1.2, which-typed-array@npm:^1.1.9": + version: 1.1.15 + resolution: "which-typed-array@npm:1.1.15" dependencies: - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 + available-typed-arrays: ^1.0.7 + call-bind: ^1.0.7 for-each: ^0.3.3 gopd: ^1.0.1 - has-tostringtag: ^1.0.0 - is-typed-array: ^1.1.10 - checksum: 7edb12cfd04bfe2e2d3ec3e6046417c59e6a8c72209e4fe41fe1a1a40a3b196626c2ca63dac2a0fa2491d5c37c065dfabd2fcf7c0c15f1d19f5640fef88f6368 + has-tostringtag: ^1.0.2 + checksum: 4465d5348c044032032251be54d8988270e69c6b7154f8fcb2a47ff706fe36f7624b3a24246b8d9089435a8f4ec48c1c1025c5d6b499456b9e5eff4f48212983 languageName: node linkType: hard @@ -43000,6 +33211,17 @@ __metadata: languageName: node linkType: hard +"which@npm:^4.0.0": + version: 4.0.0 + resolution: "which@npm:4.0.0" + dependencies: + isexe: ^3.1.1 + bin: + node-which: bin/which.js + checksum: 449fa5c44ed120ccecfe18c433296a4978a7583bf2391c50abce13f76878d2476defde04d0f79db8165bdf432853c1f8389d0485ca6e8ebce3bbcded513d5e6a + languageName: node + linkType: hard + "why-is-node-running@npm:^2.2.2": version: 2.2.2 resolution: "why-is-node-running@npm:2.2.2" @@ -43012,15 +33234,6 @@ __metadata: languageName: node linkType: hard -"wide-align@npm:^1.1.2, wide-align@npm:^1.1.5": - version: 1.1.5 - resolution: "wide-align@npm:1.1.5" - dependencies: - string-width: ^1.0.2 || 2 || 3 || 4 - checksum: 1d9c2a3e36dfb09832f38e2e699c367ef190f96b82c71f809bc0822c306f5379df87bab47bed27ea99106d86447e50eb972d3c516c2f95782807a9d082fbea95 - languageName: node - linkType: hard - "widest-line@npm:^3.1.0": version: 3.1.0 resolution: "widest-line@npm:3.1.0" @@ -43030,17 +33243,6 @@ __metadata: languageName: node linkType: hard -"winston-transport@npm:^4.5.0": - version: 4.5.0 - resolution: "winston-transport@npm:4.5.0" - dependencies: - logform: ^2.3.2 - readable-stream: ^3.6.0 - triple-beam: ^1.3.0 - checksum: 110a47c5acc87c3aa0f101741c0a992e52a86802272838c18aede8178d2b5e80254d2433dcac3439cefbc2777d9e22e65f84e9cee3130681c58e4ae5d58f50c3 - languageName: node - linkType: hard - "winston-transport@npm:^4.7.0": version: 4.7.0 resolution: "winston-transport@npm:4.7.0" @@ -43052,26 +33254,7 @@ __metadata: languageName: node linkType: hard -"winston@npm:^3.8.2": - version: 3.9.0 - resolution: "winston@npm:3.9.0" - dependencies: - "@colors/colors": 1.5.0 - "@dabh/diagnostics": ^2.0.2 - async: ^3.2.3 - is-stream: ^2.0.0 - logform: ^2.4.0 - one-time: ^1.0.0 - readable-stream: ^3.4.0 - safe-stable-stringify: ^2.3.1 - stack-trace: 0.0.x - triple-beam: ^1.3.0 - winston-transport: ^4.5.0 - checksum: e789b0c57bc3b0173c6fbd7caa4d60816a1a45cd796e5643e1bea65161d44c82a139b69f6ffc738a2919d80b5afc6df46c01947972173fc847ebcc668285fab3 - languageName: node - linkType: hard - -"winston@npm:^3.9.0": +"winston@npm:^3.8.2, winston@npm:^3.9.0": version: 3.13.0 resolution: "winston@npm:3.13.0" dependencies: @@ -43090,10 +33273,10 @@ __metadata: languageName: node linkType: hard -"word-wrap@npm:~1.2.3": - version: 1.2.3 - resolution: "word-wrap@npm:1.2.3" - checksum: 1cb6558996deb22c909330db1f01d672feee41d7f0664492912de3de282da3f28ba2d49e87b723024e99d56ba2dac2f3ab28f8db07ac199f5e5d5e2e437833de +"word-wrap@npm:^1.2.5, word-wrap@npm:~1.2.3": + version: 1.2.5 + resolution: "word-wrap@npm:1.2.5" + checksum: e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20 languageName: node linkType: hard @@ -43104,24 +33287,6 @@ __metadata: languageName: node linkType: hard -"worker-farm@npm:^1.7.0": - version: 1.7.0 - resolution: "worker-farm@npm:1.7.0" - dependencies: - errno: ~0.1.7 - checksum: 069a032f9198a07273a7608dc0c23d7288c1c25256b66008e1ae95838cda6fa2c7aefb3b7ba760f975c8d18120ca54eb193afb66d7237b2a05e5da12c1c961f7 - languageName: node - linkType: hard - -"worker-rpc@npm:^0.1.0": - version: 0.1.1 - resolution: "worker-rpc@npm:0.1.1" - dependencies: - microevent.ts: ~0.1.1 - checksum: 986406dbed4a2fd25d21e05e5a16a2db5051735df4011848366bb9488ecf19f44b43a90072171e509580fafd0565a7759543966496b8c18322efa5440dea1e6c - languageName: node - linkType: hard - "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" @@ -43133,7 +33298,7 @@ __metadata: languageName: node linkType: hard -"wrap-ansi@npm:^6.2.0": +"wrap-ansi@npm:^6.0.1, wrap-ansi@npm:^6.2.0": version: 6.2.0 resolution: "wrap-ansi@npm:6.2.0" dependencies: @@ -43220,8 +33385,8 @@ __metadata: linkType: hard "ws@npm:^8.11.0, ws@npm:^8.13.0, ws@npm:^8.2.3": - version: 8.13.0 - resolution: "ws@npm:8.13.0" + version: 8.17.0 + resolution: "ws@npm:8.17.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -43230,21 +33395,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 579817dbbab3ee46669129c220cfd81ba6cdb9ab5c3e9a105702dd045743c4ab72e33bb384573827c0c481213417cc880e41bc097e0fc541a0b79fa3eb38207d - languageName: node - linkType: hard - -"x-default-browser@npm:^0.4.0": - version: 0.4.0 - resolution: "x-default-browser@npm:0.4.0" - dependencies: - default-browser-id: ^1.0.4 - dependenciesMeta: - default-browser-id: - optional: true - bin: - x-default-browser: bin/x-default-browser.js - checksum: a19e42ffeab19560ea05a423561f5b3b82bb3a5878dc932cfd0847fadc5890b8b685d6b39e2356c8304b3943f5a7120ba4b233365d686ff8f9bf2499ce11f052 + checksum: 55241ec93a66fdfc4bf4f8bc66c8eb038fda2c7a4ee8f6f157f2ca7dc7aa76aea0c0da0bf3adb2af390074a70a0e45456a2eaf80e581e630b75df10a64b0a990 languageName: node linkType: hard @@ -43283,7 +33434,7 @@ __metadata: languageName: node linkType: hard -"xtend@npm:^4.0.0, xtend@npm:^4.0.1, xtend@npm:^4.0.2, xtend@npm:~4.0.0, xtend@npm:~4.0.1": +"xtend@npm:^4.0.0, xtend@npm:^4.0.2, xtend@npm:~4.0.0, xtend@npm:~4.0.1": version: 4.0.2 resolution: "xtend@npm:4.0.2" checksum: 366ae4783eec6100f8a02dff02ac907bf29f9a00b82ac0264b4d8b832ead18306797e283cf19de776538babfdcb2101375ec5646b59f08c52128ac4ab812ed0e @@ -43332,24 +33483,19 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^1.10.0, yaml@npm:^1.10.2, yaml@npm:^1.7.2": +"yaml@npm:^1.10.0, yaml@npm:^1.10.2": version: 1.10.2 resolution: "yaml@npm:1.10.2" checksum: 5c28b9eb7adc46544f28d9a8d20c5b3cb1215a886609a2fd41f51628d8aaa5878ccd628b755dbcd29f6bb4921bd04ffbc6dcc370689bb96e594e2f9813d2605f languageName: node linkType: hard -"yaml@npm:^2.1.1": - version: 2.3.3 - resolution: "yaml@npm:2.3.3" - checksum: a0c56bf682159b0567e9cbbddf23efc2f6806f6450716d9be6ec5eb1af1b941e95c8d3dc9c47da20d1b6883a9d6c61e31cf98bb4b77ebca4396bf772657f2f00 - languageName: node - linkType: hard - -"yaml@npm:^2.2.1": - version: 2.3.1 - resolution: "yaml@npm:2.3.1" - checksum: ed4c21a907fb1cd60a25177612fa46d95064a144623d269199817908475fe85bef20fb17406e3bdc175351b6488056a6f84beb7836e8c262646546a0220188e3 +"yaml@npm:^2.2.1, yaml@npm:^2.3.4": + version: 2.4.2 + resolution: "yaml@npm:2.4.2" + bin: + yaml: bin.mjs + checksum: 280ddb2e43ffa7d91a95738e80c8f33e860749cdc25aa6d9e4d350a28e174fd7e494e4aa023108aaee41388e451e3dc1292261d8f022aabcf90df9c63d647549 languageName: node linkType: hard @@ -43363,7 +33509,7 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:20.x, yargs-parser@npm:^20.2.2, yargs-parser@npm:^20.2.9": +"yargs-parser@npm:20.x, yargs-parser@npm:^20.2.2": version: 20.2.9 resolution: "yargs-parser@npm:20.2.9" checksum: 0685a8e58bbfb57fab6aefe03c6da904a59769bd803a722bb098bd5b0f29d274a1357762c7258fb487512811b8063fb5d2824a3415a0a4540598335b3b086c72 @@ -43472,16 +33618,33 @@ __metadata: languageName: node linkType: hard -"zod@npm:3.22.4, zod@npm:^3.22.4": +"z-schema@npm:~5.0.2": + version: 5.0.5 + resolution: "z-schema@npm:5.0.5" + dependencies: + commander: ^9.4.1 + lodash.get: ^4.4.2 + lodash.isequal: ^4.5.0 + validator: ^13.7.0 + dependenciesMeta: + commander: + optional: true + bin: + z-schema: bin/z-schema + checksum: e4c812cfe6468c19b2a21d07d4ff8fb70359062d33400b45f89017eaa3efe9d51e85963f2b115eaaa99a16b451782249bf9b1fa8b31d35cc473e7becb3e44264 + languageName: node + linkType: hard + +"zod@npm:3.22.4": version: 3.22.4 resolution: "zod@npm:3.22.4" checksum: 7578ab283dac0eee66a0ad0fc4a7f28c43e6745aadb3a529f59a4b851aa10872b3890398b3160f257f4b6817b4ce643debdda4fb21a2c040adda7862cab0a587 languageName: node linkType: hard -"zwitch@npm:^1.0.0": - version: 1.0.5 - resolution: "zwitch@npm:1.0.5" - checksum: 26dc7d32e5596824b565db1da9650d00d32659c1211195bef50c25c60820f9c942aa7abefe678fc1ed0b97c1755036ac1bde5f97881d7d0e73e04e02aca56957 +"zod@npm:^3.22.4": + version: 3.23.6 + resolution: "zod@npm:3.23.6" + checksum: 9181606c656235cf6454c60ded6ec783226acafc0206844e9729b4d3c1c6ade411b195fa2590e882d3368c82580a44869567f7aebab005bf8d8476db6186d43f languageName: node linkType: hard